Here is a small and convenient tool to execute same command over a set of Linux machines.
To use the tool we need to configure the machines for password-less SSH, also need Perl module Net::OpenSSH. We have to create a file $HOME/.allhosts and put the IP addresses or host names in this file in separate lines.
Configuring password-less access to all the machines you have
generate punblic and private keys
$ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
$ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
copy the public and private keys to all the machines you want to passwordless access:
scp ~/.ssh/id_rsa.pub userid@machine-ip:~/.ssh/id_rsa.pub
scp ~/.ssh/id_rsa userid@machine-ip:~/.ssh/id_rsa
scp ~/.ssh/id_rsa userid@machine-ip:~/.ssh/id_rsa
Add the public key to the authorized keys files on every machines:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
Now you will be able to ssh from any of these machines to any of these machines without a password
Install perl Net::OpenSSH module as shown below:
$sudo yum install perl-CPAN
$sudo perl -MCPAN -e "install Net::OpenSSH"
Examples
to kill all the java processes running in the machines listed in yout $HOME/.allhosts, issue the below command:
$ perl multihostcmd.pl "ps -ef | grep java | grep -v grep | awk ' { print \$2 }' | xargs kill -9"
Of course you will need permission to kill those processs
To check all the users logged to these machines, issue the below command
$ perl multihostcmd.pl who
$ perl multihostcmd.pl who
Below is the script (you may also access it in github ):
#!/usr/bin/perl
############################################################################
# Save this in a a file, say multihostcmd.pl
############################################################################
use threads (
'yield',
'stack_size' => 64 * 4096,
'exit' => 'threads_only',
'stringify'
);
use Cwd qw(abs_path);
use Net::OpenSSH;
#
# executeCmdRemote
# executes the command on a remote host
# command execution happens over ssh
#
sub executeCmdRemote {
my ( $host, $command, @others ) = @_;
my $ssh = Net::OpenSSH->new($host,
master_opts => [-o => "ConnectionAttempts=2", -o => "ConnectTimeout=5"] );
if ($ssh->error) {
return;
}
($out, $err, @others) = $ssh->capture2({timeout => 20}, $command);
$outdata = "FROM $host ******************************************\n";
if ($out ne "") {
$outdata .= $out;
}
if ($err ne "") {
$outdata .= $err;
}
$outdata .= "\nEND OF DATA FROM $host ************************************* \n\n";
print $outdata;
}
#
# readHostFile
# reads from the file $HOME/.allhosts where this file contain a list of hosts
# each line on this file denotes a host name or host ip
# The given command is executed on this host
#
sub readHostFile {
my ($array, @others) = @_;
$hostfile = $ENV{'HOME'} . '/.allhosts';
if (! -e $hostfile) {
print $hostfile . ' doesn\'t exist';
return;
}
if (! -f $hostfile) {
print $hostfile . ' is not a regular file';
return;
}
open FH, "< $hostfile" || return;
@$array = <FH>;
close FH;
}
sub main {
if ( $#ARGV < 0 ) {
$executing_script = abs_path($0);
print "Usage: $executing_script command-to-execute\n";
exit(1);
}
$cmdline = join( ' ', @ARGV );
my @hostarry = ();
readHostFile(\@hostarry);
if ($#hostarry < 0) {
print "Empty list for hosts";
exit(1);
}
my $thr = undef;
my @allthreads = ();
foreach my $host (@hostarry) {
$host =~ s/^\s+//;
$host =~ s/\s+$//;
if ($host eq "") {
next;
}
# Create a thread to execute the command on the remote host
$thr = threads->create('executeCmdRemote', $host, $cmdline);
push @allthreads, $thr;
}
foreach $thr (@allthreads){
$thr->join();
}
}
# Call main
main();
No comments:
Post a Comment