【问题标题】:gracefully close ssh and exit net::ssh::perl when SIGINTSIGINT 时优雅地关闭 ssh 并退出 net::ssh::perl
【发布时间】:2014-10-01 15:51:07
【问题描述】:

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

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

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

需要我需要放入子程序的代码

下面的代码在一个从 forked child 调用的函数中

#!/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 block\n";
#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_dir\n";
        }
# 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 it\n";
        mkpath($log_dir, 0777) or die "Can't make directory: $!";
        }



foreach $logHash (@{$logHashArray}){
        #print "LogHash Index $logHash\n";
        $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 block\n"; ### 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 In\n";

#-- 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,username,password,command (tail -F /full/path/to/logfile),要保存的文件名

【问题讨论】:

  • 执行一个不退出的命令(tail -f logfile),你的意思是tail没有安装或者logfile不存在?
  • 两者都存在,我的意思是它不会退出或终止,因为它是tail -f文件名
  • @tuxuday:他的意思是他对tail 的调用永远不会停止,因为它是用-f 调用的,需要CTRL + C 或INT 信号才能停止。
  • 如何添加更多代码以便我们自己尝试。请edit这个问题,以便其中有一个小的工作示例。您可以使用虚拟连接数据。我们都应该拥有某种可以通过 SSH 访问的机器。
  • @simbabque 添加了完整代码。

标签: perl ssh event-handling signals


【解决方案1】:

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

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

$ ssh starquake tty
not a tty

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

ssh apparently will pass on signals to the remote process 连接到终端时,但不是。

【讨论】:

  • 当您使用ssh 连接到远程主机(或包装它的某些模块)时,它可以工作。使用 Net::SSH::Perl 分配 tty 可以通过设置 use_pty =&gt; 1 来完成。
【解决方案2】:

如果您知道调用tail -f 的进程ID,您可以从命令行向它发送INT 信号:

kill -s INT <pid>

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

【讨论】:

  • 我无法获取 tail -f 的 pid,因为它在远程机器上运行。当我输入close $ssh-&gt;sock; inside the SIG{INT} 子程序时,它会显示Can't call method "sock" on an undefined value
  • 您的$ssh 是词法,SIG{INT} 看不到它。要么将$ssh 设为全局(不是很推荐),要么尝试将SIG{INT} 子的分配与my $ssh 放在同一块中。
  • 确实和$ssh在同一个区块
  • 请有人回答这个问题
【解决方案3】:

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

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

享受吧。

【讨论】:

    【解决方案4】:

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

    远程sftp-server 进程将在连接关闭时退出(例如,因为您按 Ctrl-C),而无需您采取任何进一步的操作。

    【讨论】:

      【解决方案5】:

      在 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_ssh\r\n");
                  $ssh ->close;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-07
        • 2012-07-03
        • 2012-04-09
        • 2011-10-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多