Иногда длительные команды ssh прекращают печать на стандартный вывод - PullRequest
3 голосов
/ 22 августа 2011

Я использую Perl :: Net :: SSH для автоматизации запуска некоторых скриптов на своих удаленных компьютерах.Однако выполнение некоторых из этих сценариев занимает очень много времени (час или два), а иногда я прекращаю получать от них данные, фактически не теряя соединение.

Вот код, который я использую:

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"
    ]
);

Иногда одна из случайных команд случайным образом просто останавливает печать / запуск событий stdout или stderr и никогда не завершается.Соединение ssh не прерывается (насколько я знаю), потому что $ssh->cmd все еще блокирует.

Есть идеи, как исправить это поведение?

Ответы [ 2 ]

0 голосов
/ 23 августа 2011

Сбой, вероятно, из-за того, как вы смотрите на вывод для отметки REGRESSION TEST IS COMPLETE. Он может быть разделен на два разных пакета SSH, поэтому ваш обратный вызов никогда его не найдет.

Лучше, используйте удаленную команду, которая заканчивается, когда это сделано как эта однострочная строка:

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

В противном случае вы закрываете удаленное соединение, но не останавливаете удаленный процесс, который останется в живых.

Кроме того, вы должны попробовать использовать Net :: OpenSSH или Net :: OpenSSH :: Parallel вместо Net :: SSH :: Perl:

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;
0 голосов
/ 23 августа 2011

В вашем хеше% sshParams может потребоваться добавить «TCPKeepAlive yes» к вашим опциям:

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

Эти параметры могут быть или не быть подходящими для вас, но я рекомендую установить TCPKeepAlive для любого долго работающего SSH-соединения. Если на вашем пути есть какой-либо брандмауэр с отслеживанием состояния, он может сбросить состояние, если не передавал трафик через соединение в течение длительного периода времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...