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

I am trying to figure out how to execute multiple sudo cmds with parallel ssh. I have manage successfully to create multiple sequential ssh requests and capture the output.

I tried to follow the instructions at Net::OpenSSH::Parallel @ FAQ - Frequently Asked Questions. I am doing something wrong but I can not figure out where I am going so wrong.

Important Notice In order to make the script to work you need to save all the ssh keys to the host that the script will be executed. "~/.ssh/known_hosts"

Sample of conf.ini file.

[MP 101] host = 127.0.0.1 user = username psw = password port = 22 [MP 100] host = 127.0.0.1 user = username psw = password port = 22

Update: Removing unnecessary code adding minimum needed code:

Sample of code with successful parallel ssh connections with sudo multiple commands.

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use Fcntl qw(:flock); use Config::IniFiles; use Net::OpenSSH::Parallel; select STDOUT; $| = 1; select STDERR; $| = 1; my $timeout = 20; my %sudo_passwords = (); sub devices { my $path = 'conf.ini'; open my $fh , '<' , "".$path."" or die "Could not open file: ".$path." - $!\n"; flock( $fh , LOCK_SH ) or die "Could not lock '".$fh."' - $!\n"; tie my %ini, 'Config::IniFiles', ( -file => "".$path."" ) or die "Error: IniFiles->new: @Config::IniFiles::errors"; close ( $fh ) or die "Could not close '".$fh."' - $!\n"; my @mps = keys ( %ini ); my $maximum_workers = @mps; my $maximum_connections = 2 * $maximum_workers; my $maximum_reconnections = 3; my %opts = ( workers => $maximum_workers, connections => $maximum_connections, reconnections => $maximum_reconnections ); my $pssh = Net::OpenSSH::Parallel->new(%opts); foreach my $hash ( @mps ) { $pssh->add_host( $ini{$hash}{host} , user => $ini{$hash}{user}, port => $ini{$hash}{port}, passwd => $ini{$hash}{psw} ); $sudo_passwords{$ini{$hash}{host}} = $ini{$hash}{psw}; } my @cmd = ( "sudo service ntp stop" , "sudo ntpd -gq" , "sudo service ntp start" ); sub sudo { my ($label, $ssh, @cmd) = @_; $ssh->system({stdin_data => "$sudo_passwords{$label}\n"}, 'sudo', '-Skp', '', '--', @cmd); } $pssh->push('*', parsub => \&sudo, @cmd); #$pssh->push( '*' , command => 'ls' , '/home/username/Downloads' ) +; $pssh->run; return %ini; } # end sub complex my %results = devices();

Output Update: I am getting this error when executing the code above.

Enter Password: Enter Password: sudoerssudoers: sudo service ntp stop: + command not found Request rejected by Privilege Manager : sudo service ntp stop: command not found Request rejected by Privilege Manager

Update: 2 Script works but how to capture output?

Thanks to i5513 I manage to make it work correctly, but I am having difficulties on capturing and redirecting the desired output. I am trying to capture the time slew and store it with the host as hash ref.

Sample of solution code:

sub sudo { my ($label, $ssh, @cmd) = @_; foreach my $c (@cmd) { $ssh->system( {stdin_data => "$sudo_passwords{$label}\n"} , 'sudo' , '-Skp' , '' , '--' , split " " , $c ); ( $dev_data{$label}= $_ ) if ( $_ !~ /ntpd$/ ); } }

Has anybody similar problem and possible solution?

Thank you in advance for your time and effort.

Seeking for Perl wisdom...on the process of learning...not there...yet!

Replies are listed 'Best First'.
Re: Net::OpenSSH::Parallel with sudo commands
by Anonymous Monk on Dec 30, 2014 at 00:25 UTC

    Could you try to reduce the code to the minimum needed to reproduce the problem? (http://sscce.org/)

    I've seen people suggest its use once in a while so I don't want to spread too much FUD, however, it might be noteworthy that Net::OpenSSH::Parallel was last released over two years ago and has no test suite. Quote from Net::OpenSSH::Parallel: "Some people find easier to use Net::OpenSSH combined with Parallel::ForkManager, ..."

Re: Net::OpenSSH::Parallel with sudo commands
by soonix (Chancellor) on Dec 30, 2014 at 12:44 UTC
    • The error messages are not from Perl but from sudo
    • The error messages are interleaved, because you are Suffering from buffering
    • sudo doesn't want to let you in, because the command you want it to execute (or its path) is missing from the sudoers file

      Hello soonix,

      You are absolutely right about the root errors. Thank you for your time and effort they helped me to understand a few things.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: Net::OpenSSH::Parallel with sudo commands
by i5513 (Pilgrim) on Dec 30, 2014 at 13:04 UTC

    Hello,

    Looking at your problem:

    # 1 Your @cmd contains sudo, but at sudo sub you are calling sudo, so +you can remove sudo from commands my @cmd = ( "ls /tmp" , "ls /var" , "ls /usr" ); # 2 You can bucle your commands and execute each of them # You need split by space your command, so system won't interpret argu +ments as part of the command: sub sudo { my ($label, $ssh, @cmd) = @_; foreach my $c (@cmd) { $ssh->system({stdin_data => "$sudo_passwords{$label}\n +"}, 'sudo', '-Skp', '', '--', split " ",$c); } }

    A while ago, I wrote as_root script which doesn't use sudo, but su , maybe you can get some idea from there:

    For parallelize such command I use pdsh

    Take a look to ansible project which have sudo support

    I think it is best to play with pubkeyauthentication (passwordauthentication for automatic tasks are not good idea).

    I hope this help

      Hello i5513,

      Thank you for your time and effort reviewing my code and all the suggestions that you proposed to me.

      Although the solution looks better than before, it still the output is not exactly what I was looking for.

      Sample of output:

      Enter LAN Password: Enter LAN Password: * Stopping NTP server ntpd ...done. * Stopping NTP server ntpd ...done. Enter LAN Password: Enter LAN Password: Enter LAN Password: * Startin +g NTP server ntpd ...done. ntpd: time slew +0.001779s Enter LAN Password: * Starting NTP server ntpd ...done.

      From what I see it dose not work exactly as it should. It is not updating twice the time.

      Well I was also considering the possibility to use this part of code:

      sub sudo_install { my ($label, $ssh, @pkgs) = @_; my ($pty) = $ssh->open2pty('sudo', 'apt-get', 'install', @pkgs); my $expect = Expect->init($pty); $expect->raw_pty(1); $expect->expect($timeout, ":"); $expect->send("$passwd\n"); $expect->expect($timeout, "\n"); $expect->raw_pty(0); while(<$expect>) { print }; close $expect; } $pssh->push('*', parsub => \&sudo_install, 'scummvm');

      I will try to make it work and I will let you know. Again thank you for your time and effort.

      Seeking for Perl wisdom...on the process of learning...not there...yet!