【问题标题】:OpenSSH POE session stuckOpenSSH POE 会话卡住
【发布时间】:2017-12-15 17:58:42
【问题描述】:

我正在使用 POE::Component::OpenSSH 和一个单独的 POE::Session 对我们网络上的 300 多个无线电设备进行非阻塞 ssh。我拥有的脚本处于工作状态,但某些设备尚未配置正确的密码(为简单起见,我们为所有设备保留相同的密码,因此使用相同的密码 ssh 进入每个设备)。有时工程师会犯错误并使用非标准 ssh 密码安装设备。在这种情况下,如果 OpenSSH 无法通过身份验证,那么 POE::Session 就会卡住(_stop 永远不会被调用并且脚本永远不会退出)。我知道这不是一个纯粹的程序问题。我们每天在网络上安装的设备很少,我不能指望我们的工程师每次都输入正确的密码。因此,即使我更正了现有设备上的密码,将来也不可避免地会出现密码错误的设备,这将导致我的进程挂起。

我可以做 $kernel->stop 但我不喜欢那样。我希望会话自行清除。有没有办法使用观察者会话清除会话内 POE::Component::OpenSSH 使用的资源/服务?任何帮助表示赞赏。请在下面查看我的代码。

use strict;
use warnings;
use POE;
use POE::Component::OpenSSH;
use POE::Component::Client::Ping;
use Data::Dumper;

my $domain = shift;
my @args = ($domain);
my $session = POE::Session->create(
        args => \@args,
        inline_states => {
                _start => \&start,
                configcapture => \&configcapture,
                activecapture => \&activecapture,
                detectdfs => \&dfs,
                pong => \&pingresult,
                handlerror => \&handlerror,
                _stop   => \&stop,
        },
);

POE::Kernel->run();
exit;

sub start {
        $_[KERNEL]->sig( DIE => 'sig_DIE' );
        print "STARTING ... for $_[ARG0] \n";
        $_[HEAP]{'domain'} = $domain;

        my $ssh = POE::Component::OpenSSH->new(
                args => ['user@'.$domain.':6022', passwd => '123' ],
        );

        $ssh->capture({event => 'configcapture', timeout => 2},
                      'cat /tmp/system.cfg | grep radio.1.freq');
        $ssh->capture({event => 'activecapture', timeout => 2},
                      '/usr/www/status.cgi');
        $_[KERNEL]->delay(detectdfs => 5);
}

sub configcapture {
        $_[HEAP]{'configfreq'} = $_[ARG0]{'result'}[0];
}

sub activecapture {
        $_[HEAP]{'activefreq'} = $_[ARG0]{'result'}[0];
}

sub dfs {
        if(defined($_[HEAP]{'configfreq'}) &&
           defined($_[HEAP]{'activefreq'})) {
                print "CONFIG: $_[HEAP]{'configfreq'}\n";
                print "ACTIVE: $_[HEAP]{'activefreq'}\n";
        }
}

sub stop {
        my ($self, $output) = @_;
        print "Ending Session Here \n";
}

【问题讨论】:

  • 在脚本的开头设置$Net::OpenSSH::debug = -1,在其中一台使用错误密码的机器上运行它,然后将输出附加到您的问题中。此外,您可以按照Net::OpenSSH 文档中关于how to use it from an event oriented framework 的说明进行操作,而不是使用POE::Component::OpenSSH
  • 也许您可以在 Net::OpenSSH args 中传递 timeoutkill_ssh_on_timeout 参数?

标签: perl session ssh nonblocking poe


【解决方案1】:

感谢您的留言。虽然自己找到了解决方案。在构建 POE::Component::OpenSSH 时,我必须添加 timeout,以便它为每个会话调用 _stop 事件。但是脚本仍然没有退出。

由于 POE::Component::OpenSSH 使用 POE::Component::Generic 来生成阻塞 Net::OpenSSH 进程作为 POE 会话,我只需要调用 POE::Component::Generic 的 shutdown 方法对于被卡住的openssh组件对象(bcoz密码错误或其他)并且所有会话都干净地结束并且脚本退出了。

请看下面的解决方案:

$_[HEAP]{'ssh'} = POE::Component::OpenSSH->new(
                args => [user@domain, passwd => '123', timeout => 180, async => 1, master_opts => [-o => "StrictHostKeyChecking=no"]],
        );

然后在_stop时

my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
delete $heap->{wheel};
$kernel->alias_remove($heap->{alias});
$kernel->alarm_remove_all();
$_[HEAP]{'ssh'}->object->shutdown;
delete($_[HEAP]{'ssh'});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    • 2015-06-20
    • 1970-01-01
    相关资源
    最近更新 更多