Skip to content

Instantly share code, notes, and snippets.

@eqhmcow
Last active December 29, 2024 03:54
Show Gist options
  • Save eqhmcow/954c9749a8050e9f43eb9c5c5f2f351e to your computer and use it in GitHub Desktop.
Save eqhmcow/954c9749a8050e9f43eb9c5c5f2f351e to your computer and use it in GitHub Desktop.
quick and dirty ssh then sudo then run commands in a loop w/ IPC::Run and Parallel::ForkManager
#!/usr/bin/perl
use strict;
use warnings;
$|++;
use IPC::Run qw/start pump finish timeout/;
use Parallel::ForkManager;
use Getopt::Long;
my (@servers, $servers, $server_file, $command_file, $output_dir, $quiet);
$servers = '';
$server_file = '';
$command_file = '';
$output_dir = '';
GetOptions(
's|servers=s' => \$servers,
'sf|server-file=s' => \$server_file,
'cf|command-file=s' => \$command_file,
'output-dir=s' => \$output_dir,
'quiet' => \$quiet,
'help' => sub { usage(); exit 0 },
) or die "Error parsing arguments";
# must specify commands or command file but not both
die "Cannot specify both commands and command-file arguments"
if (scalar @ARGV and $command_file ne '');
# commands from command line
my $cmd = "@ARGV";
# or from file
if ($command_file ne '') {
@ARGV = $command_file;
while (<>) {
$cmd .= $_;
}
}
die "must specify a command"
if ($cmd =~ m/^\s*$/);
# fix up cmd; newlines -> semicolons
$cmd =~ s/\s*;\s*\n/ ; /g;
$cmd =~ s/\n/ ; /g;
$cmd =~ s/^\s*;\s*//;
# must specify servers or server-file but not both
die "Cannot specify both servers and server-file arguments"
if ($servers ne '' and $server_file ne '');
# servers from command line
if ($servers ne '') {
$servers =~ s/^\s*//;
$servers =~ s/\s*$//;
$servers =~ s/,+/,/g;
@servers = split(m/\s*,\s*|\s+/, $servers);
}
# or from file
if ($server_file ne '') {
@ARGV = $server_file;
while (<>) {
chomp;
next if m/^\s*#/;
s/^\s*//;
s/\s*$//;
next if m/^\s*$/;
push @servers, $_;
}
}
die "must specify at least one server"
unless scalar @servers;
warn "running $cmd against @servers servers";
warn "is that ok";
$_ = readline STDIN;
die unless m/^y/;
my $pm = new Parallel::ForkManager(256);
foreach my $server (@servers) {
my $pid = $pm->start() and next;
my $b = "[$server]";
print "$b ssh to $server\n";
my $out_fh;
if ($output_dir ne '') {
my $output_file = "$output_dir/$server.out";
open($out_fh, '>', $output_file) or die "Can't open $output_file: $!";
}
my $h = start([ 'ssh', '-qt', $server, $cmd ], '<pty<', \my $in, '>pty>', \my $output);
while ($h->pump()) {
if ($output =~ m/\n/) {
$output =~ s/^(.*\n)//;
my $d = $1;
$d =~ s/\015\012/\012/g;
if ($output_dir ne '') {
print $out_fh $d;
}
unless ($quiet) {
chomp $d;
$d =~ s/^/$b /g;
$d =~ s/\n/\n$b /g;
print "$d\n";
}
}
}
$h->finish();
$output =~ s/\015\012/\012/g;
if ($output_dir ne '') {
print $out_fh $output;
close $out_fh;
}
unless ($quiet) {
chomp $output;
$output =~ s/^/$b /g;
$output =~ s/\n/\n$b /g;
print "$output\n";
}
$pm->finish();
}
$pm->wait_all_children();
sub usage {
print <<"END_USAGE";
Usage: $0 [options] [command]
Options:
-s or --servers - List of servers
--sf or --server-file - File to read for list of servers
--cf or --command-file - File to read for list of commands
--output-dir - Directory to write output to
--quiet - Don't print output to stdout
--help - Show this help message
END_USAGE
}
exit 0;
@triangletodd
Copy link

I know this name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment