Jigar
Jigar

Reputation: 93

how to disable Net::SSH::Expect timeout time

My master scripts executes on gateway server. It invokes another script and executes it on a remote server, however there is no definite run time for the remote script. So i would like to disable the timeout..

Ok let me explain.

sub rollout
{
(my $path, my $address)=@_;
my $errorStatus = 0;
print "Rollout process being initiated on netsim\n";
#Creating SSH object
my $ssh = Net::SSH::Expect-> new (
host => "netsim",
user => 'root',
raw_pty => 1
);
#Starting SSH process
$ssh->run_ssh() or die "SSH process couldn't start: $!";
#Start the interactive session
$ssh->exec("/tmp/rollout.pl $path $address", 30);


return $errorStatus;
}

When this part of the code gets executed, the rollout.pl script is invoked, however after a second the process gets killed on the remote server

Upvotes: 1

Views: 2240

Answers (1)

DeVadder
DeVadder

Reputation: 1404

Without knowing exactly what is going wrong let me do a wild guess at an answer. Should i missinterpret your question, i will edit this later:

The default and enforced timeout of Net::SSH::Expect is only a timeout for read operations. It does not mean, that a started script will be killed when its time has run out, it just means that the last reading operation no longer waits for it saying stuff.

You can start your remote script, for example with a timeout of 1 second and the exec call may return after one second. The string returned by exec will then only contain the first second of output by the remote script. But the remote script may continue to run, you just need to start a new reading operation (there are several to your choice) to capture future output. The remote script, if everything works as expected, should continue to run until it is finished or you close your ssh connection.

That means, it will be killed if you just exec, wait for that to return and then close your connection. One way to go would be to have the remote script print something when it is finished ("done" comes to mind) and wait for that string with a waitfor with very high timeout and only close the connection when waitfor has returned TRUE. Or, well, if the timeout was reasonably long, also when it returns FALSE. If you want to monitor for your script crashing, i would suggest using pgrep or ps on the remote machine. Or make sure your remote script says something when dieing, for example using eval{} or die "done".

edit:

One thing to remember is, that this exec is in fact not something like system. It basically sends the command to the remote shell and hits enter. At least that is how you might visualize what is happening. But then, to appear more like system it waits for the default timeout of 1 second for any output and stores that in its own return value. Sadly it is a rather dumb reading operation as it just sits there and listens, so it is not a good idea to give it a high timeout or actually use it to interact with the script.

I would suggest to uses exec with a timeout of 0 and then use waitfor with a very high timeout to wait for whatever pattern your remote script puts as output once finished. And only then close your connection.

edit 2:

Just replace your exec with something like:

$ssh->exec("/tmp/rollout.pl $path $address", 0);
my $didItReturn = $ssh->waitfor("done", 300);

And make sure rollout.pl prints "done" when it is finished. And not before. Now this will start the script and then wait for up to 5 minutes for the "done". If a "done" showed up, $didItReturn will be true, if it timed out, it will be false. It will not wait for 5 minutes if it sees a "done" (as opposed to giving a timeout to exec).

edit 3:

If you want no timeout at all:

$ssh->exec("/tmp/rollout.pl $path $address", 0);
my $didItReturn = 0;
while ($didItReturn = 0)
{
    $didItReturn = $ssh->waitfor("done", 300);
}

Upvotes: 2

Related Questions