mirror of
https://github.com/sudo-project/sudo.git
synced 2025-08-22 09:57:41 +00:00
Convert from using IPC::Open3 to IPC::Run.
Run tests in a pty so check_ttyname works as expected. Explicitly set short command line options letters in GetOptions(). Add a debug flag to help see what is going on internally. Add hook for die() to kill running jobs when we are dying. SSH_AGENT_PID will not be present if the agent is forwarded. In close_persistent_connections() only close active connections.
This commit is contained in:
parent
16ae61dcd7
commit
a44a005f0b
@ -7,20 +7,20 @@
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Socket;
|
|
||||||
use POSIX qw(setsid :sys_wait_h :signal_h);
|
|
||||||
use Fcntl ":flock";
|
use Fcntl ":flock";
|
||||||
use File::Temp ":mktemp";
|
use File::Temp ":mktemp";
|
||||||
use FileHandle;
|
use FileHandle;
|
||||||
use Getopt::Long;
|
use Getopt::Long qw(:config no_ignore_case bundling);
|
||||||
use Pod::Usage;
|
|
||||||
use IPC::Open3;
|
|
||||||
use IO::Socket::IP -register;
|
use IO::Socket::IP -register;
|
||||||
|
use IPC::Run qw(harness start pump finish run timeout);
|
||||||
|
use POSIX qw(setsid :sys_wait_h :signal_h);
|
||||||
use Parse::CPAN::Meta;
|
use Parse::CPAN::Meta;
|
||||||
|
use Pod::Usage;
|
||||||
|
|
||||||
my $checklogs = 0;
|
my $checklogs = 0;
|
||||||
my $cleanup_only = 0;
|
my $cleanup_only = 0;
|
||||||
my $conf_file = 'build_pkgs.conf';
|
my $conf_file = 'build_pkgs.conf';
|
||||||
|
my $debug = 0;
|
||||||
my $help = 0;
|
my $help = 0;
|
||||||
my $ignore_cache = 0;
|
my $ignore_cache = 0;
|
||||||
my $quiet = 0;
|
my $quiet = 0;
|
||||||
@ -35,16 +35,21 @@ my $main_pid = $$;
|
|||||||
GetOptions("check-logs" => \$checklogs,
|
GetOptions("check-logs" => \$checklogs,
|
||||||
"cleanup" => \$cleanup_only,
|
"cleanup" => \$cleanup_only,
|
||||||
"config|c=s" => \$conf_file,
|
"config|c=s" => \$conf_file,
|
||||||
"help" => \$help,
|
"debug|d" => \$debug,
|
||||||
"quiet" => \$quiet,
|
"help|h" => \$help,
|
||||||
"verbose" => \$verbose,
|
"quiet|q" => \$quiet,
|
||||||
"ignore-cache" => \$ignore_cache,
|
"verbose|v" => \$verbose,
|
||||||
"file=s" => \$tarball,
|
"ignore-cache|i" => \$ignore_cache,
|
||||||
|
"file|f=s" => \$tarball,
|
||||||
"repository|R=s" => \$repo,
|
"repository|R=s" => \$repo,
|
||||||
"revision|r=s" => \$rev)
|
"revision|r=s" => \$rev)
|
||||||
or pod2usage(2);
|
or pod2usage(2);
|
||||||
pod2usage(1) if $help;
|
pod2usage(1) if $help;
|
||||||
|
|
||||||
|
# Debug and verbose override quiet.
|
||||||
|
$verbose = 1 if $debug;
|
||||||
|
$quiet = 0 if $verbose;
|
||||||
|
|
||||||
# Read config data (using Parse::CPAN::Meta is cheating a bit).
|
# Read config data (using Parse::CPAN::Meta is cheating a bit).
|
||||||
my @yaml = Parse::CPAN::Meta->load_file($conf_file) ||
|
my @yaml = Parse::CPAN::Meta->load_file($conf_file) ||
|
||||||
die "$0: unable to read $conf_file: $!\n";
|
die "$0: unable to read $conf_file: $!\n";
|
||||||
@ -131,12 +136,11 @@ $INFO = "USR1" unless exists $SIG{INFO};
|
|||||||
|
|
||||||
$SIG{$INFO} = \&info;
|
$SIG{$INFO} = \&info;
|
||||||
$SIG{CHLD} = \&reaper;
|
$SIG{CHLD} = \&reaper;
|
||||||
$SIG{INT} = \&killall;
|
$SIG{HUP} = \&shut_down;
|
||||||
$SIG{TERM} = \&killall;
|
$SIG{INT} = \&shut_down;
|
||||||
$SIG{HUP} = \&killall;
|
$SIG{QUIT} = \&shut_down;
|
||||||
|
$SIG{TERM} = \&shut_down;
|
||||||
# We redirect input from /dev/null for non-interactive commands.
|
$SIG{__DIE__} = \&die_hook;
|
||||||
open(my $devnull, "+>", "/dev/null") or die "$0: can't open /dev/null: $!\n";
|
|
||||||
|
|
||||||
# Prevent macOS from going to sleep while we are running.
|
# Prevent macOS from going to sleep while we are running.
|
||||||
system("/usr/bin/caffeinate -i -w $main_pid") if -x "/usr/bin/caffeinate";
|
system("/usr/bin/caffeinate -i -w $main_pid") if -x "/usr/bin/caffeinate";
|
||||||
@ -155,7 +159,7 @@ foreach my $platform (@platforms) {
|
|||||||
|
|
||||||
# Open persistent ssh connections to VM servers
|
# Open persistent ssh connections to VM servers
|
||||||
foreach my $server (keys %vm_servers) {
|
foreach my $server (keys %vm_servers) {
|
||||||
open_persistent_connection($server);
|
$active_hosts{$server} = 1 if open_persistent_connection($server) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Power on VMs as needed
|
# Power on VMs as needed
|
||||||
@ -241,7 +245,7 @@ sub cleanup_build_dir {
|
|||||||
|
|
||||||
# Remove any remove temporary directories
|
# Remove any remove temporary directories
|
||||||
my $status = run_remote_command($conf, "rm -rf sudo_build.????????",
|
my $status = run_remote_command($conf, "rm -rf sudo_build.????????",
|
||||||
'>&STDERR');
|
\*STDERR);
|
||||||
exit($status >> 8);
|
exit($status >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,6 +289,7 @@ sub run_job {
|
|||||||
$SIG{$INFO} = "DEFAULT";
|
$SIG{$INFO} = "DEFAULT";
|
||||||
$SIG{INT} = \&worker_cleanup;
|
$SIG{INT} = \&worker_cleanup;
|
||||||
$SIG{TERM} = \&worker_cleanup;
|
$SIG{TERM} = \&worker_cleanup;
|
||||||
|
$SIG{__DIE__} = undef;
|
||||||
sigprocmask(SIG_SETMASK, $oldsigset);
|
sigprocmask(SIG_SETMASK, $oldsigset);
|
||||||
|
|
||||||
# Show platform and ssh host in ps.
|
# Show platform and ssh host in ps.
|
||||||
@ -312,7 +317,7 @@ sub run_job {
|
|||||||
my $temporary;
|
my $temporary;
|
||||||
for (my $i = 0; $i < 20; $i++) {
|
for (my $i = 0; $i < 20; $i++) {
|
||||||
$temporary = mktemp("sudo_build.XXXXXXXX");
|
$temporary = mktemp("sudo_build.XXXXXXXX");
|
||||||
$status = run_remote_command($conf, "mkdir $temporary", '>&BUILDLOG');
|
$status = run_remote_command($conf, "mkdir $temporary", \*BUILDLOG);
|
||||||
last if $status == 0;
|
last if $status == 0;
|
||||||
}
|
}
|
||||||
if ($status != 0) {
|
if ($status != 0) {
|
||||||
@ -320,12 +325,12 @@ sub run_job {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $files = "${build_script} ${test_script} ${tarball}";
|
my @files = ($build_script, $test_script, $tarball);
|
||||||
printf BUILDLOG "copy %s -> %s:%s\n", $files, $host, "$temporary/";
|
printf BUILDLOG "copy %s -> %s:%s\n", join(' ', @files), $host, "$temporary/";
|
||||||
$status = copy_to_remote($files, "$temporary/", $host, '>&BUILDLOG',
|
$status = copy_to_remote(\@files, "$temporary/", $host, \*BUILDLOG,
|
||||||
$conf->{"proxy_cmd"});
|
$conf->{"proxy_cmd"});
|
||||||
if ($status != 0) {
|
if ($status != 0) {
|
||||||
warn "$platform: unable to scp $files $host:$temporary/" unless $exiting;
|
warn "$platform: unable to copy files to $host:$temporary/" unless $exiting;
|
||||||
$exit_value = 1;
|
$exit_value = 1;
|
||||||
goto remove_tmp;
|
goto remove_tmp;
|
||||||
}
|
}
|
||||||
@ -336,7 +341,7 @@ sub run_job {
|
|||||||
"${cache}/config.cache.${platform}",
|
"${cache}/config.cache.${platform}",
|
||||||
$host, "$temporary/config.cache";
|
$host, "$temporary/config.cache";
|
||||||
copy_to_remote("${cache}/config.cache.${platform}",
|
copy_to_remote("${cache}/config.cache.${platform}",
|
||||||
"$temporary/config.cache", $host, '>&BUILDLOG',
|
"$temporary/config.cache", $host, \*BUILDLOG,
|
||||||
$conf->{"proxy_cmd"});
|
$conf->{"proxy_cmd"});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +353,8 @@ sub run_job {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$status = run_remote_command($conf,
|
$status = run_remote_command($conf,
|
||||||
"cd $temporary && ./$build_script_base ${osversion}$tarball_base", '>&BUILDLOG');
|
"cd $temporary && ./$build_script_base ${osversion}$tarball_base",
|
||||||
|
\*BUILDLOG);
|
||||||
if ($status != 0) {
|
if ($status != 0) {
|
||||||
warn "$platform: build failed on $host\n" unless $exiting;
|
warn "$platform: build failed on $host\n" unless $exiting;
|
||||||
$exit_value = 2;
|
$exit_value = 2;
|
||||||
@ -358,7 +364,7 @@ sub run_job {
|
|||||||
printf BUILDLOG "copy %s:%s -> %s\n", $host,
|
printf BUILDLOG "copy %s:%s -> %s\n", $host,
|
||||||
"$temporary/artifacts/*", $artifacts;
|
"$temporary/artifacts/*", $artifacts;
|
||||||
$status = copy_from_remote("$temporary/artifacts/\*", $artifacts,
|
$status = copy_from_remote("$temporary/artifacts/\*", $artifacts,
|
||||||
$host, '>&BUILDLOG', $conf->{"proxy_cmd"});
|
$host, \*BUILDLOG, $conf->{"proxy_cmd"});
|
||||||
if ($status != 0) {
|
if ($status != 0) {
|
||||||
warn "$platform: unable to scp $host:$temporary/artifacts/* $artifacts" unless $exiting;
|
warn "$platform: unable to scp $host:$temporary/artifacts/* $artifacts" unless $exiting;
|
||||||
$exit_value = 4;
|
$exit_value = 4;
|
||||||
@ -371,7 +377,7 @@ sub run_job {
|
|||||||
"$temporary/config.cache", "${cache}/config.cache.${platform}";
|
"$temporary/config.cache", "${cache}/config.cache.${platform}";
|
||||||
$status = copy_from_remote("$temporary/config.cache",
|
$status = copy_from_remote("$temporary/config.cache",
|
||||||
"${cache}/config.cache.${platform}", $host,
|
"${cache}/config.cache.${platform}", $host,
|
||||||
'>&BUILDLOG', $conf->{"proxy_cmd"});
|
\*BUILDLOG, $conf->{"proxy_cmd"});
|
||||||
}
|
}
|
||||||
|
|
||||||
$now = localtime();
|
$now = localtime();
|
||||||
@ -386,7 +392,7 @@ sub run_job {
|
|||||||
}
|
}
|
||||||
print TESTLOG "Test started $now\n\n";
|
print TESTLOG "Test started $now\n\n";
|
||||||
$status = run_remote_command($conf,
|
$status = run_remote_command($conf,
|
||||||
"cd $temporary && ./$test_script_base $srcdir", '>&TESTLOG');
|
"cd $temporary && ./$test_script_base $srcdir", \*TESTLOG, "-tt");
|
||||||
print TESTLOG "\nTest completed $now\n";
|
print TESTLOG "\nTest completed $now\n";
|
||||||
if ($status != 0) {
|
if ($status != 0) {
|
||||||
warn "$platform: test failure on $host\n" unless $exiting;
|
warn "$platform: test failure on $host\n" unless $exiting;
|
||||||
@ -397,7 +403,7 @@ sub run_job {
|
|||||||
|
|
||||||
# Remove temporary build dir
|
# Remove temporary build dir
|
||||||
remove_tmp:
|
remove_tmp:
|
||||||
run_remote_command($conf, "rm -rf \"$temporary\"", '>&BUILDLOG');
|
run_remote_command($conf, "rm -rf \"$temporary\"", \*BUILDLOG);
|
||||||
close(BUILDLOG);
|
close(BUILDLOG);
|
||||||
|
|
||||||
exit($exit_value);
|
exit($exit_value);
|
||||||
@ -479,26 +485,46 @@ sub reaper {
|
|||||||
$SIG{CHLD} = \&reaper;
|
$SIG{CHLD} = \&reaper;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub killall {
|
# Kill all workers and wait for them to finish.
|
||||||
|
# Note that the reaper is not called for the workers.
|
||||||
|
sub kill_workers {
|
||||||
|
my $signame = shift;
|
||||||
|
my @jobs = keys %workers;
|
||||||
|
|
||||||
|
if (@jobs) {
|
||||||
|
$SIG{CHLD} = undef;
|
||||||
|
foreach (@jobs) {
|
||||||
|
kill($signame, $_);
|
||||||
|
}
|
||||||
|
sleep(2);
|
||||||
|
foreach (@jobs) {
|
||||||
|
kill(SIGKILL, $_);
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
last unless waitpid(-1, WNOHANG) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Shut down cleanly on signal and exit.
|
||||||
|
sub shut_down {
|
||||||
my $signame = shift;
|
my $signame = shift;
|
||||||
|
|
||||||
print "Shutting down...\n" if $verbose;
|
print "Shutting down...\n" if $verbose;
|
||||||
|
|
||||||
$SIG{CHLD} = undef;
|
kill_workers($signame);
|
||||||
foreach (keys %workers) {
|
|
||||||
kill($signame, $_);
|
|
||||||
}
|
|
||||||
sleep(2);
|
|
||||||
foreach (keys %workers) {
|
|
||||||
kill(SIGKILL, $_);
|
|
||||||
}
|
|
||||||
for (;;) {
|
|
||||||
last unless waitpid(-1, WNOHANG) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Hook that is called when we die().
|
||||||
|
sub die_hook {
|
||||||
|
# Don't do anything special if called from an eval block
|
||||||
|
die @_ if $^S;
|
||||||
|
|
||||||
|
kill_workers(SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Signal handler for SIGINFO (or SIGUSR1 on non-BSD).
|
||||||
sub info {
|
sub info {
|
||||||
while (my ($host, $c) = each %concurrency) {
|
while (my ($host, $c) = each %concurrency) {
|
||||||
if (exists $c->{'queue'}) {
|
if (exists $c->{'queue'}) {
|
||||||
@ -517,18 +543,17 @@ sub info {
|
|||||||
|
|
||||||
# Build up the ssh command line
|
# Build up the ssh command line
|
||||||
sub ssh_cmdline {
|
sub ssh_cmdline {
|
||||||
my ($dest, $cmd, $opts) = @_;
|
my ($host, $cmd, @opts) = @_;
|
||||||
my $cmdline;
|
|
||||||
|
|
||||||
$cmdline = 'ssh -n -x -oPreferredAuthentications=publickey -oStrictHostKeyChecking=no -oServerAliveInterval=15 -oServerAliveCountMax=3';
|
my @cmdline = qw(ssh -x -oPreferredAuthentications=publickey -oStrictHostKeyChecking=no -oServerAliveInterval=15 -oServerAliveCountMax=3);
|
||||||
$cmdline .= ' ' . $opts if defined($opts);
|
push(@cmdline, @opts) if @opts;
|
||||||
$cmdline .= ' ' . $dest;
|
push(@cmdline, $host);
|
||||||
$cmdline .= ' "' . $cmd . '"' if defined($cmd);
|
push(@cmdline, $cmd) if defined($cmd);
|
||||||
|
|
||||||
$cmdline;
|
@cmdline;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Use scp to copy a file from local to remote
|
# Use scp to copy one or more files from local to remote
|
||||||
sub copy_to_remote {
|
sub copy_to_remote {
|
||||||
my ($src, $dst, $host, $output, $proxy) = @_;
|
my ($src, $dst, $host, $output, $proxy) = @_;
|
||||||
|
|
||||||
@ -538,9 +563,12 @@ sub copy_to_remote {
|
|||||||
return $status if $status != 0;
|
return $status if $status != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $cmdline = "scp -Bq -oPreferredAuthentications=publickey -oStrictHostKeyChecking=no -oControlPath=$sockets/$host $src $host:$dst";
|
my @cmd = qw(scp -Bq -oPreferredAuthentications=publickey -oStrictHostKeyChecking=no);
|
||||||
my $child = open3($devnull, $output, $output, $cmdline);
|
push(@cmd, "-oControlPath=$sockets/$host");
|
||||||
waitpid($child, 0);
|
push(@cmd, ref $src ? @$src : $src);
|
||||||
|
push(@cmd, "$host:$dst");
|
||||||
|
run(\@cmd, '<', \undef, '>&', $output, debug => $debug);
|
||||||
|
|
||||||
return $?;
|
return $?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,16 +582,18 @@ sub copy_from_remote {
|
|||||||
return $status if $status != 0;
|
return $status if $status != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $cmdline = "scp -Bq -oPreferredAuthentications=publickey -oStrictHostKeyChecking=no -oControlPath=$sockets/$host $host:$src $dst";
|
my @cmd = qw(scp -Bq -oPreferredAuthentications=publickey -oStrictHostKeyChecking=no);
|
||||||
my $child = open3($devnull, $output, $output, $cmdline);
|
push(@cmd, "-oControlPath=$sockets/$host");
|
||||||
waitpid($child, 0);
|
push(@cmd, "$host:$src", $dst);
|
||||||
|
run(\@cmd, '<', \undef, '>&', $output, debug => $debug);
|
||||||
|
|
||||||
return $?;
|
return $?;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run a command over ssh on the remote host and to output handle.
|
# Run a command over ssh on the remote host and to output handle.
|
||||||
# A persistent connection is opened if one does not already exit.
|
# A persistent connection is opened if one does not already exit.
|
||||||
sub run_remote_command {
|
sub run_remote_command {
|
||||||
my ($conf, $cmd, $output) = @_;
|
my ($conf, $cmd, $output, @opts) = @_;
|
||||||
my $host = $conf->{'ssh_host'};
|
my $host = $conf->{'ssh_host'};
|
||||||
my $sock_file = "$sockets/$host";
|
my $sock_file = "$sockets/$host";
|
||||||
my ($writer, $child);
|
my ($writer, $child);
|
||||||
@ -587,11 +617,23 @@ sub run_remote_command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# No need for proxy here, the persistent connection handles it.
|
# No need for proxy here, the persistent connection handles it.
|
||||||
my $cmdline = ssh_cmdline($host, $cmd, "-S $sock_file");
|
# For tty mode, we need to allocate a pty and do things the hard way.
|
||||||
|
my @cmdline = ssh_cmdline($host, $cmd, "-S", $sock_file, @opts);
|
||||||
#warn "$host: $cmdline\n" if $debug;
|
if (grep(@opts, "-t")) {
|
||||||
$child = open3($devnull, $output, $output, $cmdline);
|
my ($inbuf, $outbuf);
|
||||||
waitpid($child, 0);
|
my $h = harness(\@cmdline, '<pty<', \$inbuf, '>pty>', \$outbuf, debug => $debug);
|
||||||
|
for (;;) {
|
||||||
|
pump $h;
|
||||||
|
if (defined($outbuf)) {
|
||||||
|
print $output $outbuf;
|
||||||
|
undef $outbuf;
|
||||||
|
}
|
||||||
|
last unless $h->pumpable;
|
||||||
|
}
|
||||||
|
$h->finish();
|
||||||
|
} else {
|
||||||
|
run(\@cmdline, '<', \undef, '>&', $output, debug => $debug);
|
||||||
|
}
|
||||||
|
|
||||||
return $?;
|
return $?;
|
||||||
}
|
}
|
||||||
@ -600,33 +642,32 @@ sub run_remote_command {
|
|||||||
# The connection will persist until shut down.
|
# The connection will persist until shut down.
|
||||||
sub open_persistent_connection {
|
sub open_persistent_connection {
|
||||||
my ($dest, $output, $proxy) = @_;
|
my ($dest, $output, $proxy) = @_;
|
||||||
my ($cmdline, $outbuf);
|
my ($outbuf, @cmdline);
|
||||||
|
|
||||||
# Handle user@host form
|
# Handle user@host form
|
||||||
my @tmp = split(/\@/, $dest);
|
my @tmp = split(/\@/, $dest);
|
||||||
my $host = pop(@tmp);
|
my $host = pop(@tmp);
|
||||||
|
|
||||||
my $ssh_opts = "-f -M -N -S $sockets/$host -oControlPersist=yes";
|
my @ssh_opts = qw(-f -M -N -oControlPersist=yes);
|
||||||
$ssh_opts .= " -oProxyCommand=\"$proxy\"" if defined($proxy);
|
push(@ssh_opts, "-S", "$sockets/$host");
|
||||||
|
push(@ssh_opts, "-oProxyCommand=$proxy") if defined($proxy);
|
||||||
|
|
||||||
if (-S "$sockets/$host") {
|
if (-S "$sockets/$host") {
|
||||||
$cmdline = ssh_cmdline($dest, undef, "-S $sockets/$host -Ocheck");
|
@cmdline = ("ssh", "-S", "$sockets/$host", "-Ocheck", $host);
|
||||||
$outbuf = `ssh -S $sockets/$host -Ocheck $host 2>&1`;
|
run(\@cmdline, '<', \undef, '>&', \$outbuf, debug => $debug);
|
||||||
return 0 if $outbuf =~ /^Master running/;
|
return 0 if $outbuf =~ /^Master running/;
|
||||||
unlink("$sockets/$host");
|
unlink("$sockets/$host");
|
||||||
}
|
}
|
||||||
|
|
||||||
$cmdline = ssh_cmdline($dest, undef, $ssh_opts);
|
@cmdline = ssh_cmdline($dest, undef, @ssh_opts);
|
||||||
$outbuf = `$cmdline 2>&1`;
|
run(\@cmdline, '<', \undef, '>&', \$outbuf, debug => $debug);
|
||||||
if (length($outbuf) > 0) {
|
if (length($outbuf) > 0) {
|
||||||
if ($outbuf =~ /already exists, disabling multiplexing/) {
|
if ($outbuf =~ /already exists, disabling multiplexing/) {
|
||||||
# We may lose the race to create the socket, that's OK.
|
# We may lose the race to create the socket, that's OK.
|
||||||
$? = 0;
|
$? = 0;
|
||||||
} else {
|
} else {
|
||||||
# Write to $output if set to something like '>&BUILDLOG'
|
$output = \*STDERR unless defined($output);
|
||||||
local *STDERR;
|
print $output $outbuf;
|
||||||
open *STDERR, $output if defined($output);
|
|
||||||
warn $outbuf;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -636,25 +677,26 @@ sub open_persistent_connection {
|
|||||||
# Close a persistent connection
|
# Close a persistent connection
|
||||||
sub close_persistent_connection {
|
sub close_persistent_connection {
|
||||||
my $host = shift;
|
my $host = shift;
|
||||||
my $ret = 0;
|
my $ret = 1;
|
||||||
|
|
||||||
|
# Strip off optional user@ if present.
|
||||||
|
$host =~ s/^.*@//;
|
||||||
|
|
||||||
if (-S "$sockets/$host") {
|
if (-S "$sockets/$host") {
|
||||||
# TODO: error handling
|
my $outbuf;
|
||||||
my $output = `ssh -oControlPath=$sockets/$host -Oexit $host 2>&1`;
|
my @cmdline = ("ssh", "-S", "$sockets/$host", "-Oexit", $host);
|
||||||
$ret = $?;
|
run(\@cmdline, '<', \undef, '>&', \$outbuf, debug => $debug);
|
||||||
|
$ret = 0 unless ($? == 0 && $outbuf =~ /Exit request sent/);
|
||||||
}
|
}
|
||||||
|
|
||||||
$ret;
|
$ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Close all persistent connections, regardless of who opened them.
|
# Close all active persistent connections.
|
||||||
sub close_persistent_connections {
|
sub close_persistent_connections {
|
||||||
return unless defined($sockets);
|
if (defined($sockets)) {
|
||||||
if (opendir(my $dir, $sockets)) {
|
foreach my $host (keys %active_hosts) {
|
||||||
my @connections = grep { !/^\./ && -S "$sockets/$_" } readdir($dir);
|
close_persistent_connection($host);
|
||||||
closedir($dir);
|
|
||||||
foreach my $h (@connections) {
|
|
||||||
close_persistent_connection($h);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -662,32 +704,43 @@ sub close_persistent_connections {
|
|||||||
sub vm_is_running {
|
sub vm_is_running {
|
||||||
# vim-cmd vmsvc/power.getstate VMID
|
# vim-cmd vmsvc/power.getstate VMID
|
||||||
my ($host, $vmid) = @_;
|
my ($host, $vmid) = @_;
|
||||||
|
my $outbuf;
|
||||||
|
|
||||||
my $cmd = "ssh -l root $host vim-cmd vmsvc/power.getstate $vmid 2>&1";
|
my @cmdline = ssh_cmdline($host, "vim-cmd vmsvc/power.getstate $vmid");
|
||||||
my @output = `$cmd`;
|
run(\@cmdline, '<', \undef, '>&', \$outbuf, debug => $debug);
|
||||||
return 1 if grep(/Powered on/, @output);
|
|
||||||
return 0;
|
$outbuf =~ /Powered on/;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub vm_poweron {
|
sub vm_poweron {
|
||||||
# vim-cmd vmsvc/power.on VMID
|
# vim-cmd vmsvc/power.on VMID
|
||||||
my ($host, $vmid) = @_;
|
my ($host, $vmid) = @_;
|
||||||
|
my $outbuf;
|
||||||
|
|
||||||
print "Powering on VM $vmid on $host\n" if $verbose;
|
print "Powering on VM $vmid on $host\n" if $verbose;
|
||||||
my $cmd = "ssh -l root $host vim-cmd vmsvc/power.on $vmid 2>&1";
|
my @cmdline = ssh_cmdline($host, "vim-cmd vmsvc/power.on $vmid");
|
||||||
my @output = `$cmd`;
|
run(\@cmdline, '<', \undef, '>&', \$outbuf, debug => $debug);
|
||||||
return 1 if grep(/Powering on VM/, @output);
|
|
||||||
return 0;
|
$outbuf =~ /Powering on VM/;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub vm_shutdown {
|
sub vm_shutdown {
|
||||||
# vim-cmd vmsvc/power.shutdown VMID
|
# vim-cmd vmsvc/power.shutdown VMID
|
||||||
my ($host, $vmid) = @_;
|
my ($host, $vmid) = @_;
|
||||||
|
my $outbuf;
|
||||||
|
|
||||||
print "Shutting down VM $vmid on $host\n" if $verbose;
|
print "Shutting down VM $vmid on $host\n" if $verbose;
|
||||||
my $cmd = "ssh -l root $host vim-cmd vmsvc/power.shutdown $vmid 2>&1";
|
my @cmdline = ssh_cmdline($host, "vim-cmd vmsvc/power.shutdown $vmid");
|
||||||
# Cannot complete operation because VMware Tools is not running in this virtual machine
|
run(\@cmdline, '<', \undef, '>&', \$outbuf, debug => $debug);
|
||||||
system($cmd);
|
|
||||||
|
# Check for, e.g. vim.fault.ToolsUnavailable or vim.fault.InvalidPowerState
|
||||||
|
if ($outbuf =~ /vim\.fault\.ToolsUnavailable/) {
|
||||||
|
warn "unable to shut down $vmid @ $host: VM tools not installed\n";
|
||||||
|
} elsif ($outbuf =~ /vim\.fault\.InvalidPowerState/) {
|
||||||
|
# Not powered on, ignore the error
|
||||||
|
$outbuf = "";
|
||||||
|
}
|
||||||
|
$outbuf !~ /vim\.fault\./;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Try to connect to port 22 on the host.
|
# Try to connect to port 22 on the host.
|
||||||
@ -737,21 +790,20 @@ sub create_tarball {
|
|||||||
|
|
||||||
sub start_ssh_agent {
|
sub start_ssh_agent {
|
||||||
# Use existing agent if possible
|
# Use existing agent if possible
|
||||||
if (exists $ENV{'SSH_AUTH_SOCK'} && exists $ENV{'SSH_AGENT_PID'}) {
|
if (exists $ENV{'SSH_AUTH_SOCK'} && -S $ENV{'SSH_AUTH_SOCK'}) {
|
||||||
if (-S $ENV{'SSH_AUTH_SOCK'} && kill(0, $ENV{'SSH_AGENT_PID'})) {
|
return undef;
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Need to start a new agent and add keys
|
# Need to start a new agent and add keys
|
||||||
my $output = `ssh-agent -s`;
|
my @cmdline = qw(ssh-agent -s);
|
||||||
foreach (split(/\n/, $output)) {
|
run(\@cmdline, '<', \undef, '>&', sub {
|
||||||
s/;.*//;
|
$_ = shift;
|
||||||
|
s/;[^;]*$//;
|
||||||
my ($var, $val) = (/^([^=]+)=(.*)$/);
|
my ($var, $val) = (/^([^=]+)=(.*)$/);
|
||||||
if (defined($var) && defined($val)) {
|
if (defined($var) && defined($val)) {
|
||||||
$ENV{$var} = $val;
|
$ENV{$var} = $val;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
system("ssh-add");
|
system("ssh-add");
|
||||||
|
|
||||||
return $ENV{'SSH_AGENT_PID'};
|
return $ENV{'SSH_AGENT_PID'};
|
||||||
@ -832,6 +884,7 @@ sub grep_log {
|
|||||||
s/\x1b\[[\d;]*m//g; # remove escape codes
|
s/\x1b\[[\d;]*m//g; # remove escape codes
|
||||||
if (/[Ww]arning:|[Ee]rror:|\*\*\* |ftp: /) {
|
if (/[Ww]arning:|[Ee]rror:|\*\*\* |ftp: /) {
|
||||||
# Some things we ignore
|
# Some things we ignore
|
||||||
|
next if /ermanently added .* to the list of known hosts/;
|
||||||
next if /warning\/error mail subject/;
|
next if /warning\/error mail subject/;
|
||||||
next if /must be cleared at boot time|Clock skew detected|in the future|-no(-fast)?-install|remember to run 'libtool --finish|has not been installed in|relinking '/;
|
next if /must be cleared at boot time|Clock skew detected|in the future|-no(-fast)?-install|remember to run 'libtool --finish|has not been installed in|relinking '/;
|
||||||
# RPM warnings we don't care about
|
# RPM warnings we don't care about
|
||||||
|
Loading…
x
Reference in New Issue
Block a user