in reply to Re^2: Problem with Net::SSH::Expect on unavailable hosts
in thread Problem with Net::SSH::Expect on unavailable hosts

Without a timeout value, you can attempt to use the ssh connection before run_ssh() has finished what it's doing. This causes crazy stuff, like the script abending. In the op's example, testing the value of $login_output would not have necessarily solved anything. In the test script I wrote, it had no effect whatsoever (was always empty, whether the connection was successful or not). Additionally, adding the debug and log to stdout parms will help to track down what exactly is happening behind the run_ssh() call. If he waits until run_ssh() has finished, the regex check he included from the documentation will correctly determine whether he has a valid connection or not.

The doc for Net::SSH::Expect does imply $! as the location meaningful error information from run_ssh() with the statement:
$ssh->run_ssh() or die "SSH process couldn't start: $!";
The fact that he "received nothing useful" from it leads me to believe he was checking trying to use the connection before run_ssh() had finished trying to connect.

Replies are listed 'Best First'.
Re^4: Problem with Net::SSH::Expect on unavailable hosts
by mr_mischief (Monsignor) on Jul 01, 2009 at 21:30 UTC
    It leads me to believe that, if by returning a failure state run_ssh() allows you to assume that the subprocess could not start, that it blocks its return until it has started otherwise.

    The docs for run_ssh() further state " boolean: 1 if the ssh ran OK or 0 otherwise. In case of failures, use $! to do get info." Note the tense and order. $! is meaningless unless run_ssh() returned a failure code. It wouldn't return a failure code if the SSH session was started successfully, and doesn't return success until and unless it was started successfully.

    $! is absolutely meaningless regarding the success of run_ssh(), as it will not get populated by run_ssh() except on failure.

    Why do you seem to think that run_ssh() is run asynchonously and does not block? It's the SSH connection that's supposed to be in a separate process per the docs, not run_ssh() itself.

      From Expect.pm in the Net::SSH package:
      sub run_ssh { my Net::SSH::Expect $self = shift; #(clipped setting up of user options and flags) my $exp = new Expect(); #(clipped setting of Expect options based on user opts/flags) my $success = $exp->spawn($ssh_string); return (defined $success); }
      $success contains the return value of the spawn method in the Expect object. The spawn method in Expect forks the ssh process. As soon as this method is called, ssh is off and running (and we'd better be thinking in async mode). From what I can tell, the spawn method in Expect only returns undef if fork fails or if it's unable to sync with the child process immediately after the fork (I assume to confirm that the process started). Except for those two instances, the eventual return value of run_ssh is going to be positive.

      I'll admit, I have some trouble reading the Expect module. So perhaps I'm missing something...but my experience with this module and the quick test script I wrote earlier both support my conclusion.
Re^4: Problem with Net::SSH::Expect on unavailable hosts
by sierpinski (Chaplain) on Jul 02, 2009 at 13:18 UTC
    First I'd like to thank all of you who are commenting...

    Second, I wanted to reiterate that the return value from the run_ssh ($login_output) always returns the value 1, no matter of it was successful or not. From what I read in the docs, this is because the return value of the spawn is returned, meaning that the ssh process was spawned successfully. The issue lies in the fact that the ssh connection dies immediately afterward (connection refused)... so the question becomes, how can I detect that an ssh connection has been terminated?

    It appears that is the reason for this line:
    ($ssh->read_all(2) =~ />\s*\z/) or die "where's the remote prompt?"
    But the script dies before it even finishes processing that line. The attempt to call a method on the $ssh object is what aborts the script. After the $ssh->run_ssh();, *anything* that is called from $ssh will do the same thing.

    I've tried using login() with a password instead, but according to the docs, login() actually calls run_ssh() anyway, so the result is the same.

    Would a 'waitfor' looking for connection refused help here perhaps?
      Did you try the timeout setting that I suggested above? What was the result? To really be thorough, capture the debug output from one of your sessions and post it. That will tell you (and us) exactly what Expect is doing underneath the covers. I don't expect I'd be able to decipher it, but others here could.
        I tried the timeout, but the result was the same. The debugging output that I get basically shows nothing from $!, and the return value of $ssh->run_ssh() is always 1, regardless if it's a success or failure.

        Here is the result of enabling debugging (for the offending server -- hugger):

        Spawned 'ssh -e none sebrint@hugger' spawn id(4) Pid: 22388 Tty: /dev/pts/7 Expect::spawn('Expect=GLOB(0x8074f40)','ssh -e none sebrint@h +ugger') called at /vol/perl/5.8/lib/site_perl/5.8.1/Net/SSH/Expect.pm + line 132 Net::SSH::Expect::run_ssh('Net::SSH::Expect=ARRAY(0x8074f58)') + called at ./dumpadm_oz.pl line 33 eval {...} called at ./dumpadm_oz.pl line 32 Starting EXPECT pattern matching... Expect::expect('Expect=GLOB(0x8074f40)',2,'-re','(?-xism:[\s\S +]+)') called at /vol/perl/5.8/lib/site_perl/5.8.1/Net/SSH/Expect.pm l +ine 580 Net::SSH::Expect::_sec_expect('Net::SSH::Expect=ARRAY(0x8074f5 +8)',2,'-re','(?-xism:[\s\S]+)') called at /vol/perl/5.8/lib/site_perl +/5.8.1/Net/SSH/Expect.pm line 419 Net::SSH::Expect::read_all('Net::SSH::Expect=ARRAY(0x8074f58)' +,2) called at ./dumpadm_oz.pl line 47 ssh: connect to host hugger port 22: Connection refused Starting EXPECT pattern matching... Expect::expect('Expect=GLOB(0x8074f40)',2,'-re','(?-xism:[\s\S +]+)') called at /vol/perl/5.8/lib/site_perl/5.8.1/Net/SSH/Expect.pm l +ine 580 Net::SSH::Expect::_sec_expect('Net::SSH::Expect=ARRAY(0x8074f5 +8)',2,'-re','(?-xism:[\s\S]+)') called at /vol/perl/5.8/lib/site_perl +/5.8.1/Net/SSH/Expect.pm line 420 Net::SSH::Expect::read_all('Net::SSH::Expect=ARRAY(0x8074f58)' +,2) called at ./dumpadm_oz.pl line 47 Closing spawn id(4). Expect::hard_close('Expect=GLOB(0x8074f40)') called at /vol/pe +rl/5.8/lib/site_perl/5.8.1/Expect.pm line 894 Expect::_multi_expect(2,'undef','ARRAY(0x81a82b8)') called at +/vol/perl/5.8/lib/site_perl/5.8.1/Expect.pm line 565 Expect::expect('Expect=GLOB(0x8074f40)',2,'-re','(?-xism:[\s\S +]+)') called at /vol/perl/5.8/lib/site_perl/5.8.1/Net/SSH/Expect.pm l +ine 580 Net::SSH::Expect::_sec_expect('Net::SSH::Expect=ARRAY(0x8074f5 +8)',2,'-re','(?-xism:[\s\S]+)') called at /vol/perl/5.8/lib/site_perl +/5.8.1/Net/SSH/Expect.pm line 420 Net::SSH::Expect::read_all('Net::SSH::Expect=ARRAY(0x8074f58)' +,2) called at ./dumpadm_oz.pl line 47 spawn id(4) closed. SSHProcessError The ssh process was terminated. at ./dumpadm_oz.pl lin +e 47 Closing spawn id(4). Expect::hard_close('Expect=GLOB(0x8074f40)') called at /vol/pe +rl/5.8/lib/site_perl/5.8.1/Expect.pm line 1621 Expect::DESTROY('Expect=GLOB(0x8074f40)') called at ./dumpadm_ +oz.pl line 0 eval {...} called at ./dumpadm_oz.pl line 0

        Thanks!