OpenSSH POE session 卡住了
OpenSSH POE session stuck
我正在 non-blocking 使用 POE::Component::OpenSSH 和每个设备单独的 POE::Session 连接到我们网络上的 300 多台无线电设备。我拥有的脚本处于工作状态,但某些设备尚未配置正确的密码(为简单起见,我们为所有设备保留相同的密码,因此使用相同的密码通过 ssh 连接到每个设备)。有时工程师会犯错误并使用 NON-STANDARD ssh 密码安装设备。在这种情况下,如果 OpenSSH 无法通过身份验证,那么 POE::Session 会卡住(_stop 永远不会被调用,脚本也永远不会退出)。我知道这不是一个纯粹的程序问题。我们每天在网络上安装的设备很少,我不能指望我们的工程师每次都输入正确的密码。因此,即使我在现有设备上更正了密码,将来也不可避免地会出现密码错误的设备,这将导致我的进程挂起。
我可以做 $kernel->stop 但我不喜欢那样。我希望 session 自行清除。有没有办法使用观察者 session 清除 session 中 POE::Component::OpenSSH 使用的 resources/services?任何帮助表示赞赏。请在下面查看我的代码。
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";
}
感谢您的留言。虽然自己找到了解决方案。我必须在构造 POE::Component::OpenSSH 时添加 timeout
以便它为每个会话调用 _stop 事件。但是脚本仍然没有退出。
由于 POE::Component::OpenSSH 使用 POE::Component::Generic 生成阻塞 Net::OpenSSH 进程作为 POE 会话,我只需要调用 POE::Component::Generic 的 shutdown
方法被卡住的 openssh 组件对象(密码错误或其他原因)并且所有会话都干净地结束并且脚本退出。
请看下面的解决方法:
$_[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'});
我正在 non-blocking 使用 POE::Component::OpenSSH 和每个设备单独的 POE::Session 连接到我们网络上的 300 多台无线电设备。我拥有的脚本处于工作状态,但某些设备尚未配置正确的密码(为简单起见,我们为所有设备保留相同的密码,因此使用相同的密码通过 ssh 连接到每个设备)。有时工程师会犯错误并使用 NON-STANDARD ssh 密码安装设备。在这种情况下,如果 OpenSSH 无法通过身份验证,那么 POE::Session 会卡住(_stop 永远不会被调用,脚本也永远不会退出)。我知道这不是一个纯粹的程序问题。我们每天在网络上安装的设备很少,我不能指望我们的工程师每次都输入正确的密码。因此,即使我在现有设备上更正了密码,将来也不可避免地会出现密码错误的设备,这将导致我的进程挂起。
我可以做 $kernel->stop 但我不喜欢那样。我希望 session 自行清除。有没有办法使用观察者 session 清除 session 中 POE::Component::OpenSSH 使用的 resources/services?任何帮助表示赞赏。请在下面查看我的代码。
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";
}
感谢您的留言。虽然自己找到了解决方案。我必须在构造 POE::Component::OpenSSH 时添加 timeout
以便它为每个会话调用 _stop 事件。但是脚本仍然没有退出。
由于 POE::Component::OpenSSH 使用 POE::Component::Generic 生成阻塞 Net::OpenSSH 进程作为 POE 会话,我只需要调用 POE::Component::Generic 的 shutdown
方法被卡住的 openssh 组件对象(密码错误或其他原因)并且所有会话都干净地结束并且脚本退出。
请看下面的解决方法:
$_[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'});