Seq has asked for the wisdom of the Perl Monks concerning the following question:

I have few servers which needs updating and other kind of maintenance.

xargs -a ~/servers -l1 -I'{}' ssh -t '{}' 'sudo aptitude full-upgrade'

Works, but it'll start to loose pty after one adds grep db ~servers|cut -d';' -f1 etc.
Anyway I wanted to use database, so I can make my life more difficult.
Everything else works, but that ssh is bit off. Script below works ok, no worries, but I need more.

I can execute commands OR run shell, but I need both in a same time.

I want to get interactive with commands. ;) Like sudo aptitude full-upgrade, which asks Yes or No.
Ofc I can add -y to that aptitude but there are more questions. Like, do you want to save your configurations or something.

And expect is not an answer.

Basically I want inject my commands to that shell and want it to stop after it's done, cause there will be more servers...

#!/usr/bin/perl use strict; use Net::SSH::Perl; my $host = '172.16.9.40'; my $username = 'power'; my $ssh = Net::SSH::Perl->new($host,$username,options =>["interactive +yes","identity_files $ENV{HOME}/.ssh/id_dsa"]); $ssh->login($username); my $cmd; #my $cmd="sudo aptitude update"; if ($cmd) { my($out, $err, $exit) = $ssh->cmd($cmd); print $out if $out; print $err if $err; } else { eval "use Term::ReadKey;"; ReadMode('raw'); eval "END { ReadMode('restore') };"; $ssh->shell; print "Connection to $host closed.\n"; }

Replies are listed 'Best First'.
Re: Interactive commands via ssh
by haukex (Archbishop) on Feb 14, 2017 at 08:49 UTC

    Hi Seq,

    If the machine you are executing these commands from is not Win32, then I can recommend Net::OpenSSH. Although I haven't yet done much of this myself, it does allow communicating interactively with the processes on the remote end. I'm not sure why you said "expect is not an answer", but note that tying Expect together with Net::OpenSSH, as shown in the latter's documentation, would allow you to script interactions with the remote side.

    Hope this helps,
    -- Hauke D

      All those servers are Debian.

      Let's see, how that Net::OpenSSH bends..

      Expect is not an option, cause there will be questions that I can't anticipate.

        I don't think that Net::OpenSSH is answer.

        Can't find interaction...

Re: Interactive commands via ssh
by haukex (Archbishop) on Feb 15, 2017 at 09:13 UTC

    Hi Seq,

    The power of Net::OpenSSH is that it can give you a lot of low-level control, which does mean you may need to implement some low-level stuff yourself, or instead use a higher-level module like Expect. The following works for me (both client and server are Debian-based Linux systems).

    Server-side script that just prompts the user three times and generates some output. Drop this into /tmp/test.pl on the remote machine.

    #!/usr/bin/env perl use warnings; use strict; use IO::Prompt 'prompt'; print STDOUT "I am STDOUT\n"; print STDERR "I am STDERR\n"; for (qw/Bar Quz Baz/) { my $resp = prompt("Foo $_? ", -yn); warn "You said no\n" if lc($resp) eq 'n'; print "<$resp>\n"; } print "Goodbye.\n";

    Client-side script that executes the remote script. Note how it automatically answers two of the prompts, while allowing the user to answer the third.

    #!/usr/bin/env perl use warnings; use strict; use Net::OpenSSH; use Expect; die "Usage: $0 HOST" unless @ARGV==1; my $ssh = Net::OpenSSH->new($ARGV[0]); die $ssh->error if $ssh->error; my @cmd = ('/tmp/test.pl'); my ($pty, $pid) = $ssh->open2pty(@cmd) or die $ssh->error; my $exp = Expect->init($pty); $exp->log_stdout(1); $exp->expect(5, [ qr/foo .+\?/i, sub { my $exp = shift; # prompt user if ($exp->match=~/quz/i) { $exp->send(scalar <STDIN>); } # automatic responses elsif ($exp->match=~/bar/i) { $exp->send("y\n"); } else { $exp->send("n\n"); } exp_continue; } ] ); $exp->soft_close; waitpid($pid, 0); $ssh->disconnect; print "Done.\n";

    Hope this helps,
    -- Hauke D

Re: Interactive commands via ssh
by Anonymous Monk on Feb 14, 2017 at 20:57 UTC
    Puppet. Chef. Salt. cfEngine3. Pick one.