2020-10-16 00:32:37 +08:00
|
|
|
#! /usr/bin/env perl
|
|
|
|
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
|
|
|
|
use common::sense;
|
|
|
|
|
|
|
|
use File::Basename;
|
|
|
|
use lib dirname(__FILE__) . '/../../../lib/perl';
|
|
|
|
use OVH::Result;
|
|
|
|
use OVH::Bastion;
|
|
|
|
use OVH::Bastion::Plugin qw( :DEFAULT help );
|
|
|
|
|
|
|
|
my ($list, $stepByStep, $noPauseOnFailure, $noConfirm, $noStdin, $command);
|
|
|
|
my $remainingOptions = OVH::Bastion::Plugin::begin(
|
|
|
|
argv => \@ARGV,
|
|
|
|
header => "clush",
|
|
|
|
options => {
|
|
|
|
'list=s' => \$list,
|
|
|
|
'step-by-step' => \$stepByStep,
|
|
|
|
'no-pause-on-failure' => \$noPauseOnFailure,
|
|
|
|
'no-confirm' => \$noConfirm,
|
|
|
|
'no-stdin' => \$noStdin,
|
|
|
|
'command=s' => \$command,
|
|
|
|
},
|
2021-06-21 17:59:44 +08:00
|
|
|
helptext => <<"EOF",
|
2020-10-16 00:32:37 +08:00
|
|
|
Launch a remote command on several machines sequentially (clush-like)
|
|
|
|
|
|
|
|
Usage: --osh SCRIPT_NAME [OPTIONS] --command '"remote command"'
|
|
|
|
|
2021-06-21 17:59:44 +08:00
|
|
|
--list HOSTLIST Comma-separated list of the hosts (hostname or IP) to run the command on
|
|
|
|
--user USER Specify which remote user should we use to connect (default: BASTION_ACCOUNT)
|
|
|
|
--port PORT Specify which port to connect to (default: 22)
|
2020-10-16 00:32:37 +08:00
|
|
|
--step-by-step Pause before running the command on each host
|
2020-10-22 18:09:09 +08:00
|
|
|
--no-pause-on-failure Don't pause if the remote command failed (returned exit code != 0)
|
2020-10-16 00:32:37 +08:00
|
|
|
--no-confirm Skip confirmation of the host list and command
|
|
|
|
--command '"remote cmd"' Command to be run on the remote hosts. If you're in a shell, quote it twice as shown.
|
|
|
|
EOF
|
|
|
|
);
|
|
|
|
|
|
|
|
#
|
|
|
|
# code
|
|
|
|
#
|
|
|
|
my $fnret;
|
|
|
|
|
|
|
|
#
|
|
|
|
# params check
|
|
|
|
#
|
|
|
|
|
|
|
|
if (not $list) {
|
|
|
|
help();
|
|
|
|
osh_exit 'ERR_MISSING_PARAMETER', "Missing mandatory parameter 'list'";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (not $command) {
|
|
|
|
help();
|
|
|
|
osh_exit 'ERR_MISSING_PARAMETER', "Missing mandatory parameter 'command'";
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# and test external command call
|
|
|
|
#
|
|
|
|
my %hosts;
|
|
|
|
foreach my $host (split /,/, $list) {
|
|
|
|
if ($host !~ /^[a-zA-Z0-9.-]+$/) {
|
|
|
|
osh_exit 'ERR_INVALID_PARAMETER', "This doesn't appear to be a valid host '$host'";
|
|
|
|
}
|
|
|
|
$hosts{$host} = 1;
|
|
|
|
}
|
|
|
|
my @hosts = keys %hosts;
|
|
|
|
|
|
|
|
if (not @hosts) {
|
|
|
|
help();
|
|
|
|
osh_exit 'ERR_INVALID_PARAMETER', "Host list to execute the command on is empty";
|
|
|
|
}
|
|
|
|
|
|
|
|
osh_info "Will execute a command on " . scalar(@hosts) . " hosts ($list)";
|
|
|
|
osh_info "The command to be executed is: $command";
|
|
|
|
|
|
|
|
if (not $noConfirm) {
|
|
|
|
osh_info "Press ENTER to proceed, or CTRL+C to cancel.";
|
|
|
|
<STDIN>;
|
|
|
|
}
|
|
|
|
|
|
|
|
my %ret;
|
|
|
|
foreach my $host (@hosts) {
|
|
|
|
osh_info "************************";
|
|
|
|
osh_info "Working on $host";
|
|
|
|
osh_info "************************";
|
|
|
|
if ($stepByStep) {
|
|
|
|
osh_info("Press ENTER to execute the command on this host");
|
|
|
|
<STDIN>;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $shellc = $host;
|
|
|
|
$user and $shellc = "$user\@$host";
|
|
|
|
$port and $shellc .= " --port $port";
|
|
|
|
|
|
|
|
# relaunch the user's shell (aka osh.pl) to connect to the host
|
|
|
|
my @cmd = ($ENV{'SHELL'}, '-c', "--quiet $shellc -- $command");
|
|
|
|
|
2022-06-30 21:00:29 +08:00
|
|
|
$fnret =
|
|
|
|
OVH::Bastion::execute(cmd => \@cmd, noisy_stderr => 1, noisy_stdout => 1, expects_stdin => $noStdin ? 0 : 1);
|
2020-10-16 00:32:37 +08:00
|
|
|
if ($fnret and $fnret->value() and $fnret->value()->{'sysret'} != 0 and not $noPauseOnFailure) {
|
2022-06-30 21:00:29 +08:00
|
|
|
osh_warn("Last command failed (return code: "
|
|
|
|
. $fnret->value()->{'sysret'}
|
|
|
|
. "), press ENTER to continue or CTRL+C to stop here");
|
2020-10-16 00:32:37 +08:00
|
|
|
<STDIN>;
|
|
|
|
}
|
|
|
|
|
2022-06-30 21:00:29 +08:00
|
|
|
$ret{$host} =
|
|
|
|
{stderr => $fnret->value->{'stderr'}, stdout => $fnret->value->{'stdout'}, sysret => $fnret->value->{'sysret'}};
|
2020-10-16 00:32:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
osh_ok(\%ret);
|