Handle hostnames with upper-case letters
[webmin.git] / cluster-shell / run.cgi
1 #!/usr/local/bin/perl
2 # run.cgi
3 # Actually run the command on all servers and show the output
4
5 require './cluster-shell-lib.pl';
6 &ReadParse();
7 &error_setup($text{'run_err'});
8
9 if ($in{'clear'}) {
10         # Just clearing history
11         &lock_file($commands_file);
12         unlink($commands_file);
13         &unlock_file($commands_file);
14         &webmin_log("clear");
15         &redirect("");
16         exit;
17         }
18
19 $in{'cmd'} ||= $in{'old'};
20 $in{'cmd'} =~ /\S/ || &error($text{'run_ecmd'});
21
22 # Build the list of servers
23 @servers = &servers::list_servers();
24 @sel = split(/\0/, $in{'server'});
25 foreach $s (@sel) {
26         if ($s eq "ALL") {
27                 push(@run, grep { $_->{'user'} } @servers);
28                 }
29         elsif ($s =~ /^group_(.*)$/) {
30                 # All members of a group
31                 ($group) = grep { $_->{'name'} eq $1 }
32                                 &servers::list_all_groups(\@servers);
33                 foreach $m (@{$group->{'members'}}) {
34                         push(@run, grep { $_->{'host'} eq $m && $_->{'user'} }
35                                         @servers);
36                         }
37                 }
38         elsif ($s eq '*') {
39                 # This server
40                 push(@run, ( { 'desc' => $text{'index_this'} } ));
41                 }
42         else {
43                 # A single remote server
44                 push(@run, grep { $_->{'host'} eq $s } @servers);
45                 }
46         }
47 @run = &unique(@run);
48 @run || &error($text{'run_enone'});
49
50 &ui_print_header(undef, $text{'run_title'}, "");
51
52 # Setup error handler for down hosts
53 sub inst_error
54 {
55 $inst_error_msg = join("", @_);
56 }
57 &remote_error_setup(\&inst_error);
58
59 # Run one each one in parallel and display the output
60 $p = 0;
61 foreach $s (@run) {
62         local ($rh = "READ$p", $wh = "WRITE$p");
63         pipe($rh, $wh);
64         select($wh); $| = 1; select(STDOUT);
65         if (!fork()) {
66                 # Do the install in a subprocess
67                 close($rh);
68
69                 &remote_foreign_require($s->{'host'}, "webmin",
70                                         "webmin-lib.pl");
71                 if ($inst_error_msg) {
72                         # Failed to contact host ..
73                         print $wh &serialise_variable([ 0, $inst_error_msg ]);
74                         exit;
75                         }
76
77                 # Run the command and capture output
78                 local $q = quotemeta($in{'cmd'});
79                 local $rv = &remote_eval($s->{'host'}, "webmin",
80                                          "\$x=`($q) </dev/null 2>&1`");
81
82                 print $wh &serialise_variable([ 1, $rv ]);
83                 close($wh);
84                 exit;
85                 }
86         close($wh);
87         $p++;
88         }
89
90 # Get back all the results
91 $p = 0;
92 foreach $s (@run) {
93         local $rh = "READ$p";
94         local $line = <$rh>;
95         close($rh);
96         local $rv = &unserialise_variable($line);
97
98         local $d = $s->{'desc'} || $s->{'host'};
99
100         if (!$line) {
101                 # Comms error with subprocess
102                 print "<b>",&text('run_failed', $d, "Unknown reason"),
103                       "</b><p>\n";
104                 }
105         elsif (!$rv->[0]) {
106                 # Error with remote server
107                 print "<b>",&text('run_failed', $d, $rv->[1]),"</b><p>\n";
108                 }
109         else {
110                 # Done - show output
111                 print "<b>",&text('run_success', $d),"</b>\n";
112                 print "<ul><pre>".&html_escape($rv->[1])."</pre></ul><p>\n";
113                 }
114         $p++;
115         }
116
117 # Save command and server
118 &open_lock_tempfile(COMMANDS, ">>$commands_file");
119 &print_tempfile(COMMANDS, $in{'cmd'},"\n");
120 &close_tempfile(COMMANDS);
121 $config{'server'} = join(" ", @sel);
122 &save_module_config();
123
124 &webmin_log("run", undef, undef, { 'cmd' => $in{'cmd'},
125                                    'run' => [ map { $_->{'host'} } @run ] });
126
127 &ui_print_footer("", $text{'index_return'});
128