Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re^5: SSH2 - Asynchronous Opens & Synchronous Commands

by salva (Abbot)
on Apr 05, 2014 at 14:14 UTC ( #1081244=note: print w/ replies, xml ) Need Help??


in reply to Re^4: SSH2 - Asynchronous Opens & Synchronous Commands
in thread SSH2 - Asynchronous Opens & Synchronous Commands

You have to call $ssh->wait_for_master(1) repeatedly until it succeeds:

my %connecting = map { $_ => 1 } @hosts; while (1) { for my $host (keys %connecting) { my $ssh = $ssh{$host}; if ($ssh->wait_for_master(1)) { delete $connecting{$host}; } elsif ($ssh->error) { # handle connection error delete $connecting{$host}; } } last unless %connecting; select (undef, undef, undef, 0.05); }


Comment on Re^5: SSH2 - Asynchronous Opens & Synchronous Commands
Select or Download Code
Re^6: SSH2 - Asynchronous Opens & Synchronous Commands
by 5haun (Sexton) on Apr 05, 2014 at 22:44 UTC

    @Salva

    Thank you. So far, it looks like OpenSSH+Telnet will do what we need it to, although I am having to make some adjustments for the use of Telnet.

    BTW, it would be nice (i.e. enhancement request) if $ssh->error provided a message that could differentiate between password, connect, and timeout failures: I get "unable to establish master SSH connection: bad password or master process exited unexpectedly" for authentication, for connect (socket not open), and for timeout errors. I need to be able to differentiate (that was pretty easy to do with Net::SSH2). Unless you have a better test, it looks like I'll need to try a socket connect before the opens to differentiate.

      The connection and authentication phases are carried out by the OpenSSH client and it doesn't pass the cause of the failure back to the module.

      An easy to implement workaround is to redirect the output of the master ssh process to a file and then, to retrieve it when something goes wrong.

      my $ssh = Net::OpenSSH->new($host, master_stderr_file => "/tmp/ssh-std +err-$host", master_opts => ['-v'], ...);

        Of course! (head slap) :)

        I was already gathering the info, but didn't think of using it to automatically pull the error:

        my $ssh_debug = 0; # verbose logging: 0-3 ... my $session_log_name = "ssh_$host.log"; open( my $session_log_fh, ">", $session_log_name ) or die "Failed to create logfile $session_log_name: $!"; binmode( $session_log_fh, ":unix" ); # unbuffer log file ... $ssh_session{$host} = Net::OpenSSH->new( # host $host, # automatically add new host keys to the user known hosts file +s # enable verbosity, if enabled master_opts => ($ssh_debug) ? [ -o => "StrictHostKeyChecking=no", "-" . "v" x $ssh_debug ] : [ -o => "StrictHostKeyChecking=no" ], # authentication user => $username, password => $password, # logging master_stderr_fh => $session_log_fh, # connection parameters timeout => $loginTO, port => $ssh_port, async => 1 ); }

        The '-v' to enable debugging is not required in this case, as the error message (or nothing) will be written to the file with $ssh_debug = 0. I believe the important concept here is the cause of error message always appears to be the last line output to the master_stderr_fh file. Something like the following (combined with the above) appears to provide a more accurate error message:

        elsif ( $ssh->error ) { # handle connection error my $lasterr = File::ReadBackwards->new("ssh_$host.log")->r +eadline; # ... something that outputs or logs the error message }

        It should be noted there will be a linefeed on the end of $lasterr (it's left up to the user to chomp it off if they don't want it).

        It should also be noted that master_stderr_fh cannot be assigned to an in-memory file, or the following error will be received:

        Not a GLOB reference at /usr/local/share/perl/5.14.2/Net/OpenSSH.pm li +ne 614. 612 sub _check_is_system_fh { 613 my ($name, $fh) = @_; 614 my $fn = fileno(defined $fh ? $fh : $name); 615 defined $fn and $fn >= 0 and return; 616 croak "child process $name is not a real system file handle"; 617 }

        Thanks again. The full solution will be posted when it is done (I'm juggling a couple of other things while doing this, so sorry it's taking a while).

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1081244]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (10)
As of 2014-12-28 05:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (178 votes), past polls