3

Perl::Net::SSH を使用して、リモート ボックスでのスクリプトの実行を自動化しています。ただし、これらのスクリプトの中には完了するまでに非常に長い時間がかかるもの (1 時間または 2 時間) があり、実際には接続を失うことなく、スクリプトからのデータの取得を停止することがあります。

私が使用しているコードは次のとおりです。

sub run_regression_tests {
    for(my $i = 0; $i < @servers; $i++){
        my $inner = $users[$i];
        foreach(@$inner){
            my $user = $_;
            my $server = $servers[$i];

            my $outFile;
            open($outFile, ">" . $outputDir . $user . "@" . $server . ".log.txt");
            print $outFile "Opening connection to $user at $server on " . localtime() . "\n\n";
            close($outFile);

            my $pid = $pm->start and next;

                print "Connecting to $user@" . "$server...\n";

                my $hasWentToDownloadYet = 0;
                my $ssh = Net::SSH::Perl->new($server, %sshParams);
                $ssh->login($user, $password);              

                $ssh->register_handler("stdout", sub {
                    my($channel, $buffer) = @_;             
                    my $outFile;
                    open($outFile, ">>", $outputDir . $user . "@" . $server . ".log.txt");                  
                    print $outFile $buffer->bytes;              
                    close($outFile);                

                    my @lines = split("\n", $buffer->bytes);
                    foreach(@lines){
                        if($_ =~ m/REGRESSION TEST IS COMPLETE/){
                            $ssh->_disconnect();

                            if(!$hasWentToDownloadYet){
                                $hasWentToDownloadYet = 1;
                                print "Caught exit signal.\n";
                                print("Regression tests for ${user}\@${server} finised.\n");
                                download_regression_results($user, $server);
                                $pm->finish;
                            }
                        }
                    }

                });
                $ssh->register_handler("stderr", sub {
                    my($channel, $buffer) = @_;             
                    my $outFile;
                    open($outFile, ">>", $outputDir . $user . "@" . $server . ".log.txt");

                    print $outFile $buffer->bytes;              

                    close($outFile);                
                });
                if($debug){
                    $ssh->cmd('tail -fn 40 /GDS/gds/gdstest/t-gds-master/bin/comp.reg');
                }else{
                    my ($stdout, $stderr, $exit) = $ssh->cmd('. ./.profile && cleanall && my.comp.reg');
                    if(!$exit){
                        print "SSH connection failed for ${user}\@${server} finised.\n";
                    }
                }
                #$ssh->cmd('. ./.profile');

                if(!$hasWentToDownloadYet){
                    $hasWentToDownloadYet = 1;
                    print("Regression tests for ${user}\@${server} finised.\n");
                    download_regression_results($user, $server);
                }

            $pm->finish;        
        }
    }
    sleep(1);
    print "\n\n\nAll tests started. Tests typically take 1 hour to complete.\n";
    print "If they take significantly less time, there could be an error.\n";
    print "\n\nNo output will be printed until all commands have executed and finished.\n";
    print "If you wish to watch the progress tail -f one of the logs this script produces.\n Example:\n\t" . 'tail -f ./gds1@tdgds10.log.txt' . "\n";
    $pm->wait_all_children;
    print "\n\nAll Tests are Finished. \n";
}

そして、ここに私の%sshParamsがあります:

my %sshParams = (
    protocol => '2',
    port => '22',
    options => [
        "TCPKeepAlive yes",
        "ConenctTimeout 10",
        "BatchMode yes"
    ]
);

長時間実行されているコマンドの 1 つがランダムに、stdout または stderr イベントの印刷/起動を停止し、終了しないことがあります。$ssh->cmdまだブロックしているため、ssh接続は(私が知る限り)切断されません。

この動作を修正する方法はありますか?

4

2 に答える 2

0

REGRESSION TEST IS COMPLETEおそらく、マークの出力を調べる方法が原因で失敗します。2つの異なるSSHパケットに分割される可能性があるため、コールバックはそれを検出しません。

より良いのは、このワンライナーとして実行されたときに終了するリモートコマンドを使用することです。

perl -pe 'BEGIN {$p = open STDIN, "my.comp.reg |" or die $!}; kill TERM => -$p if /REGRESSION TEST IS COMPLETE/}'

それ以外の場合は、リモート接続を閉じていますが、存続するリモートプロセスを停止していません。

それ以外に、Net :: SSH::Perlの代わりにNet ::OpenSSHまたはNet::OpenSSH::Parallelを使用してみてください。

use Net::OpenSSH::Parallel;

my $pssh = Net::OpenSSH::Parallel->new;

for my $i (0..$#server) {
    my $server = $server[$i];
    for my $user (@{$users[$ix]}) {
        $pssh->add_host("$user\@$server", password => $password);
    }
}

if ($debug) {
    $pssh->all(cmd => { stdout_file => "$outputDir%USER%\@%HOST%.log.txt",
                        stderr_to_stdout => 1 },
               'fail -fn 40 /GDS/gds/gdstest/t-gds-master/bin/comp.reg');
}
else {
    $pssh->all(cmd => { stdout_file => "$outputDir%USER%\@%HOST%.log.txt",
                        stderr_to_stdout => 1 },
               '. ./.profile && cleanall && my.comp.reg');
}

$pssh->all(scp_get => $remote_regression_results_path, "regression_results/%USER%\@%HOST%/");

$pssh->run;
于 2011-08-23T09:09:33.143 に答える
0

%sshParams ハッシュで、オプションに「TCPKeepAlive yes」を追加する必要がある場合があります。

$sshParams{'options'} = ["BatchMode yes", "TCPKeepAlive yes"];

これらのオプションは適切である場合とそうでない場合がありますが、TCPKeepAlive は、長時間実行される SSH 接続に設定することをお勧めします。パスになんらかのステートフル ファイアウォールがある場合、長期間接続を介してトラフィックを通過させないと、状態がドロップする可能性があります。

于 2011-08-22T20:13:03.113 に答える