#
# (c) Jan Gehring <jan.gehring@gmail.com>
#
# vim: set ts=2 sw=2 tw=0:
# vim: set expandtab:
package Rex::Interface::Connection::SSH;
use strict;
use warnings;
use Rex::Interface::Connection::Base;
use base qw(Rex::Interface::Connection::Base);
sub new {
my $that = shift;
my $proto = ref($that) || $that;
my $self = $that->SUPER::new(@_);
bless( $self, $proto );
return $self;
}
sub connect {
my ( $self, %option ) = @_;
my (
$user, $pass, $private_key, $public_key, $server,
$port, $timeout, $auth_type, $is_sudo
);
Rex::Logger::debug("Using Net::SSH2 for connection");
$user = $option{user};
$pass = $option{password};
$server = $option{server};
$port = $option{port};
$timeout = $option{timeout};
$public_key = $option{public_key};
$private_key = $option{private_key};
$auth_type = $option{auth_type};
$is_sudo = $option{sudo};
$self->{is_sudo} = $is_sudo;
$self->{__auth_info__} = \%option;
Rex::Logger::debug( "Using user: " . $user );
Rex::Logger::debug(
"Using password: " . ( $pass ? "***********" : "<no password>" ) );
$self->{server} = $server;
$self->{ssh} = Net::SSH2->new;
my $fail_connect = 0;
CON_SSH:
$port ||= Rex::Config->get_port( server => $server ) || 22;
$timeout ||= Rex::Config->get_timeout( server => $server ) || 3;
$server =
Rex::Config->get_ssh_config_hostname( server => $server ) || $server;
if ( $server =~ m/^(.*?):(\d+)$/ ) {
$server = $1;
$port = $2;
}
Rex::Logger::info( "Connecting to $server:$port (" . $user . ")" );
unless ( $self->{ssh}->connect( $server, $port, Timeout => $timeout ) ) {
++$fail_connect;
sleep 1;
goto CON_SSH
if (
$fail_connect < Rex::Config->get_max_connect_fails( server => $server ) )
; # try connecting 3 times
Rex::Logger::info( "Can't connect to $server", "warn" );
$self->{connected} = 0;
return;
}
Rex::Logger::debug( "Current Error-Code: " . $self->{ssh}->error() );
Rex::Logger::info("Connected to $server, trying to authenticate.");
$self->{connected} = 1;
if ( $auth_type && $auth_type eq "pass" ) {
Rex::Logger::debug("Using password authentication.");
$self->{auth_ret} = $self->{ssh}->auth_password( $user, $pass );
if ( !$self->{auth_ret} ) {
# try guessing
$self->{auth_ret} = $self->{ssh}->auth(
'username' => $user,
'password' => $pass
);
}
}
elsif ( $auth_type && $auth_type eq "key" ) {
Rex::Logger::debug("Using key authentication.");
$self->{auth_ret} =
$self->{ssh}->auth_publickey( $user, $public_key, $private_key, $pass );
}
else {
Rex::Logger::debug("Trying to guess the authentication method.");
$self->{auth_ret} = $self->{ssh}->auth(
'username' => $user,
'password' => $pass,
'publickey' => $public_key || "",
'privatekey' => $private_key || ""
);
}
$self->{sftp} = $self->{ssh}->sftp;
}
sub reconnect {
my ($self) = @_;
Rex::Logger::debug("Reconnecting SSH");
$self->connect( %{ $self->{__auth_info__} } );
}
sub disconnect {
my ($self) = @_;
$self->get_connection_object->disconnect;
}
sub error {
my ($self) = @_;
return $self->get_connection_object->error;
}
sub get_connection_object {
my ($self) = @_;
return $self->{ssh};
}
sub get_fs_connection_object {
my ($self) = @_;
if ( !defined $self->{sftp} ) {
Rex::Logger::info(
"It seems that you haven't installed or configured sftp on your server.",
"warn"
);
Rex::Logger::info(
"Rex needs sftp for file operations, so please install one.", "warn" );
die("No SFTP server found on remote host.");
}
return $self->{sftp};
}
sub is_connected {
my ($self) = @_;
return $self->{connected};
}
sub is_authenticated {
my ($self) = @_;
return $self->{auth_ret};
}
sub get_connection_type {
my ($self) = @_;
my $type = "SSH";
if ( $self->{is_sudo} && $self->{is_sudo} == 1 ) {
return "Sudo";
}
if ( Rex::is_ssh() && !Rex::is_sudo() ) {
$type = "SSH";
}
elsif ( Rex::is_sudo() ) {
$type = "Sudo";
}
return $type;
}
1;