优雅地关闭ssh,并在SIGINT时退出net::ssh::perl



我正在连接到远程主机并执行一个不退出的命令(tail-f日志文件)

我正在注册一个处理程序,并将输出写入日志文件。这很好用但我想在主程序上按Control+C,它应该停止远程机器上的命令,并优雅地关闭ssh连接

所以我正在为SIGINT 注册一个信号处理程序

需要我需要放在子程序中的代码

下面的代码位于从分叉子调用的函数内部

#!/ats/bin/perl
use Net::SSH::Perl;
use File::Path;
use Text::CSV_XS;
chomp ($progName = `basename $0`);
if (@ARGV != 1 ) {
        print "usage: perl $progName <tc_id>n";
        exit;
}
$tc_id = shift;
$file = "config.prop";
$log_dir = "logs/";

#$SIG{INT}=&close_write;
sub close_write
{
#-- write it to file
print "nInside END blockn";
#open FH, ">$log_file";
#print $log_file;
#print FH @out;
#$thr->kill('INT');
#close $ssh->sock;
#undef $ssh;
exit 1;
}
# Read the configuration file and populate the Hash
$index = 0;
my $csv = Text::CSV_XS->new ({ binary => 1, eol => $/ });
 open my $io, "<", $file or die "$file: $!";
 while (my $row = $csv->getline ($io)) {
    next if (${$row}[0] =~ m/^#/);  #Ignore comments
    next if (${$row}[0] =~ m/^s*$/);   #Ignore blank lines
    ($logHashArray->[$index]->{host}, $logHashArray->[$index]->{user}, $logHashArray->[$index]->{pass}, $logHashArray->[$index]->{cmd}, $logHashArray->[$index]->{log_file}) = @$row;
    $index++;
 }

# Append "/" at the end of the directory if it does not exist
unless ($log_dir =~ m//$/) {
        $log_dir = $log_dir . "/";
        print "LogDir: $log_dirn";
        }
# Check if the log directory exists, if not, create it
if (-e $log_dir) {
        unless (-d $log_dir) {
                die "File exists but is not directory";
                }
        }
else {
        # don't forget to check mkdir's failure
        print "Directory $log_dir does not exist... Creating itn";
        mkpath($log_dir, 0777) or die "Can't make directory: $!";
        }

foreach $logHash (@{$logHashArray}){
        #print "LogHash Index $logHashn";
        $logHash->{log_file} = $tc_id . "_" . $logHash->{host} . "_" .$logHash->{log_file};
        $logHash->{cmd} = $logHash->{cmd} . " | tee /tmp/" . $logHash->{log_file};
        $logHash->{log_dir} = $log_dir;
        #$logHash->{thr}=threads->new(&connect_get_logs, $logHash);
        $logHash->{pid} = fork();
        if ($logHash->{pid}){
            # Parent
            push(@childs, $logHash->{pid});
        }
        elsif ($pid == 0){
            # Child
            connect_get_logs($logHash);
        }
        else {
            die "couldn’t fork: $!n";
            }
while (($key, $value) = each(%{$logHash})){
     print $key."=>".$value."n";
}
}
#$SIG{INT}=&close_write;
#$thr=threads->new(&connect_get_logs, $logHash);
foreach (@childs) {
    waitpid($_, 0);
    }

#print "Waiting...";
#while(1) {sleep 1;}
#$thr->join;

sub connect_get_logs{
$SIG{INT}= sub {
        print "Inside INT blockn"; ### Need proper code here
        close $ssh->sock;
        undef $ssh;
        };
my $logHash = shift;
while (($key, $value) = each(%{$logHash})){
     print $key."=>".$value."n";
}
my $stdout;
my $stderr;
my $exit;
#-- setup a new connection
print "Logging in to $logHash->{host}...";
my $ssh = Net::SSH::Perl->new($logHash->{host}, debug => 0, protocol => '2', options => ["PasswordAuthentication yes", "BatchMode yes",
                    "PubkeyAuthenticaion no", "RhostsAuthentication no", "RhostsRSAAuthentication no", "RSAAuthentication no", "DSAAuthentication no"]);
#-- authenticate
$ssh->login($logHash->{user}, $logHash->{pass});
print "Logged Inn";
#-- Create or Overwrite the log files
open LOG_FILE, ">", "$logHash->{log_dir}$logHash->{log_file}" or die $!;
#-- register a handler
$ssh->register_handler("stdout", sub {
        my($channel, $buffer) = @_;
        $str = $buffer->bytes;
        #push @out, $str;
        print LOG_FILE $str;
        #print $str;
});
#$SIG{INT}=&close_write;
#-- execute the command
($stdout, $stderr, $exit) = $ssh->cmd($logHash->{cmd});
print "Error: $stderr";
}

以csv格式创建config.prop文件

host/ip,用户名,密码,命令(tail-F/full/path/to/logfile),保存为的文件名

诀窍是用-t(或者可能是-tt)调用ssh。

默认情况下,ssh在远程机器上只为交互式登录shell分配一个pty(即,在远程调用命令时不分配)。-t强制ssh分配pty,即使在执行远程命令时也是如此。你可以看到效果:

$ ssh starquake tty
not a tty

$ ssh -t starquake tty
/dev/pts/1
Connection to starquake closed.

ssh显然会在连接到终端时将信号传递给远程进程,但在其他情况下不会。

如果您知道调用tail -f的进程id,您可以从命令行向它发送一个INT信号,其中包含:

kill -s INT <pid>

在主程序的$SIG{'INT'}中,您需要做的是让它也通过Net::SSH连接发送INT。不幸的是,我不知道该怎么做。

$sh->login()#登录ssh会话

$sh->关闭#从ssh会话注销

享受。

在这里,您可以看到一种使用SFTP而不是SSH来连续读取远程文件的替代解决方案:SFTP_tail.pl。

当连接关闭时(例如,因为您按下Ctrl-C),远程sftp-server进程将退出,而不需要您执行任何进一步操作。

在perl中登录、访问和关闭ssh会话的完整过程。

            my $host = 192.168.0.1;
            my $username = "example";
            my $passwd  = "example";
            my $ssh = Net::SSH::Expect->new(
            host => $host,
            user => $username,
            password => $passwd,
            timeout => 20,
            );
            $ssh->login();
            $ssh->exec("command_to_be_executed_in_sshrn");
            $ssh ->close;

相关内容

  • 没有找到相关文章

最新更新