From cd33094b28d8a9b0aeba7261725e3cae0e4985fe Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Thu, 29 Dec 2016 14:10:36 +0100 Subject: [PATCH] Implement --exec @node cmd [args...] This command might be usefull, e.g. if sshd is not responding. Examples: clusterd --exec @theinternet restart sshd.service clusterd --exec @theinternet dmesg clusterd --exec @theinternet 'grep sshd /var/log/messages|tail -100' The remote command is executed by bash, so the pipe in the last example is on the remote node stdout and stderr are delivered seperatly and might be redirected to different channels on the local side. If the remote command exits with a non-zero exit status, the local command fails with exit status 1. The slave part already existed, because we once had a remote execution command. We removed it, because it was considered to be to dangerous. The former remote execution command allowed parallel execution on all nodes, which enabled an admin to kill all systems by mistake in an instance. Now we only enable remote execution on a single node. --- clusterd | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/clusterd b/clusterd index 5ec48f5..9b01eb3 100755 --- a/clusterd +++ b/clusterd @@ -1274,6 +1274,22 @@ sub expand_netgroup_hosts { return @out; } +sub exec_at { + my ($host,@cmd)=@_; + sync_cluster_pw() or die "$CLUSTER_PW_FILE: $!\n"; + my $s=new IO::Socket::INET(PeerAddr=>$host,PeerPort=>$CLP_PORT); + unless (defined $s) { + die "$host: $!\n"; + } + clp_send_message($s,'CMD',@cmd); + my $pbuffer=''; + my $olbuffer=''; + my $elbuffer=''; + Donald::Select::reader($s,\&cmd_rx,$host,$s,\$pbuffer,\$olbuffer,\$elbuffer); + $slave=1; + Donald::Select::run() if $slave;; +} + sub lsof { my ($pattern)=@_; sync_cluster_pw() or die "$CLUSTER_PW_FILE: $!\n"; @@ -1367,13 +1383,13 @@ sub cmd_msg { } elsif ($channel eq 'O') { my $msg=$$olbufref.substr($data,1); for ($msg=~/([^\n]*\n)/gs) { - print "$host $_"; + print "$host: $_"; } ($$olbufref)=$msg=~/([^\n]*)\z/; } elsif ($channel eq 'E') { my $msg=$$elbufref.substr($data,1); for ($msg=~/([^\n]*\n)/gs) { - print STDERR "$host $_"; + print STDERR "$host: $_"; } ($$elbufref)=$msg=~/([^\n]*)\z/; } @@ -1389,6 +1405,7 @@ usage: $0 [options] --push-amd-tar # broadcast /etc/amd --send-restart # broadcast a restart request to all nodes --exec mkmotd # execute /usr/sbin/mkmotd.pl on all nodes + --exec @node cmd [args...] # execute cmd on node --flush-gidcache # flush rpc auth.unix.gid cache on all nodes --lsof=pattern @@ -1423,9 +1440,15 @@ if (defined $options{'push'}) { $donald_s=new Donald::Select::INET(Proto=>'udp') or die "$!\n"; push_file($donald_s,$options{'push'}); } elsif (defined $options{'exec'}) { - sync_cluster_pw() or die "$CLUSTER_PW_FILE: $!\n"; - $donald_s=new Donald::Select::INET(Proto=>'udp') or die "$!\n"; - send_exec($donald_s,$options{'exec'}); + if (substr($options{'exec'},0,1) eq '@') { + length(length($options{'exec'})>1) or die USAGE; + @ARGV>=1 or die USAGE; + exec_at(substr($options{'exec'},1),@ARGV); + } else { + sync_cluster_pw() or die "$CLUSTER_PW_FILE: $!\n"; + $donald_s=new Donald::Select::INET(Proto=>'udp') or die "$!\n"; + send_exec($donald_s,$options{'exec'}); + } } elsif (defined $options{'push_amd_tar'}) { sync_cluster_pw() or die "$CLUSTER_PW_FILE: $!\n"; $donald_s=new Donald::Select::INET(Proto=>'udp') or die "$!\n";