diff --git a/cluster-shutdown/check.pl b/cluster-shutdown/check.pl new file mode 100755 index 000000000..941d284e6 --- /dev/null +++ b/cluster-shutdown/check.pl @@ -0,0 +1,32 @@ +#!/usr/local/bin/perl +# Send email when a system is down + +$no_acl_check++; +require './cluster-shutdown-lib.pl'; +&foreign_require("mailboxes", "mailboxes-lib.pl"); + +@servers = grep { $_->{'user'} } &servers::list_servers(); +%up = &get_all_statuses(\@servers); +$last_status_file = "$module_config_directory/last"; + +&read_file($last_status_file, \%oldstatus); + +foreach $s (@servers) { + if (!$up{$s} && $oldstatus{$s->{'id'}}) { + # Just went down .. send email + local $mail = + { 'headers' => [ [ 'From', 'webmin@'.&get_system_hostname() ], + [ 'To', $config{'email'} ], + [ 'Subject', "System $s->{'host'} is down" ], + ], + 'attach' => + [ { 'headers' => [ [ 'Content-type', 'text/plain' ] ], + 'data' => "The system $s->{'host'} has gone down!" } ] + }; + &mailboxes::send_mail($mail, undef, undef, 0, $config{'smtp'}); + } + $oldstatus{$s->{'id'}} = $up{$s}; + } + +&write_file($last_status_file, \%oldstatus); + diff --git a/cluster-shutdown/cluster-shutdown-lib.pl b/cluster-shutdown/cluster-shutdown-lib.pl new file mode 100644 index 000000000..ba718c9a1 --- /dev/null +++ b/cluster-shutdown/cluster-shutdown-lib.pl @@ -0,0 +1,55 @@ + +do '../web-lib.pl'; +&init_config(); +do '../ui-lib.pl'; +&foreign_require("servers", "servers-lib.pl"); +%access = &get_module_acl(); + +$cron_cmd = "$module_config_directory/check.pl"; + +sub find_cron_job +{ +&foreign_require("cron", "cron-lib.pl"); +local ($job) = grep { $_->{'command'} eq $cron_cmd } &cron::list_cron_jobs(); +return $job; +} + +# get_all_statuses(&servers) +# Returns a hash mapping servers to their statuses. The possible values are: +# 0 = down +# 1 = up +# 2 = up but login is not possible +# 3 = up but login failed +sub get_all_statuses +{ +# Check which ones are up, in parallel +my ($servers) = @_; +my %pid; +foreach my $s (@$servers) { + my $pid; + if (!($pid = fork())) { + my $out = `ping -c 1 -w 1 $s->{'host'} 2>&1`; + if ($config{'login'} && !$?) { + # Attempt a Webmin login too + if (!$s->{'user'}) { + exit(101); + } + local $err = &servers::test_server($s->{'host'}); + exit($err ? 102 : 0); + } + exit($? ? 1 : 0); + } + $pid{$s} = $pid; + } +my %up; +foreach my $s (@$servers) { + my $pid = waitpid($pid{$s}, 0); + $up{$s} = $? == 0 ? 1 : + $?/256 == 101 ? 2 : + $?/256 == 102 ? 3 : 0; + } +return %up; +} + +1; + diff --git a/cluster-shutdown/config b/cluster-shutdown/config new file mode 100644 index 000000000..c844ad194 --- /dev/null +++ b/cluster-shutdown/config @@ -0,0 +1 @@ +login=0 diff --git a/cluster-shutdown/config.info b/cluster-shutdown/config.info new file mode 100644 index 000000000..fc6af65d8 --- /dev/null +++ b/cluster-shutdown/config.info @@ -0,0 +1 @@ +login=Attempt Webmin login when testing servers?,1,1-Yes,0-No diff --git a/cluster-shutdown/defaultacl b/cluster-shutdown/defaultacl new file mode 100644 index 000000000..95efc1ec9 --- /dev/null +++ b/cluster-shutdown/defaultacl @@ -0,0 +1,2 @@ +reboot=1 +shut=1 diff --git a/cluster-shutdown/images/.xvpics/icon.gif b/cluster-shutdown/images/.xvpics/icon.gif new file mode 100644 index 000000000..20ef9810c Binary files /dev/null and b/cluster-shutdown/images/.xvpics/icon.gif differ diff --git a/cluster-shutdown/images/icon.gif b/cluster-shutdown/images/icon.gif new file mode 100644 index 000000000..8c16688bd Binary files /dev/null and b/cluster-shutdown/images/icon.gif differ diff --git a/cluster-shutdown/images/smallicon.gif b/cluster-shutdown/images/smallicon.gif new file mode 100644 index 000000000..a74c16f08 Binary files /dev/null and b/cluster-shutdown/images/smallicon.gif differ diff --git a/cluster-shutdown/index.cgi b/cluster-shutdown/index.cgi new file mode 100755 index 000000000..c1fbe4c92 --- /dev/null +++ b/cluster-shutdown/index.cgi @@ -0,0 +1,67 @@ +#!/usr/local/bin/perl +# Show a list of cluster servers that can be shut down + +require './cluster-shutdown-lib.pl'; +&ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1); + +@servers = grep { $_->{'user'} } &servers::list_servers(); +%up = &get_all_statuses(\@servers); + +if (@servers) { + print &ui_form_start("shutdown.cgi", "post"); + @links = ( &select_all_link("id"), + &select_invert_link("id") ); + print &ui_links_row(\@links); + print &ui_columns_start([ "", + $text{'index_host'}, + $text{'index_desc'}, + $text{'index_os'}, + $text{'index_up'} ]); + foreach $s (@servers) { + ($st) = grep { $_->[0] eq $s->{'type'} } @servers::server_types; + print &ui_checked_columns_row( + [ $s->{'host'}, + $s->{'desc'}, + $st->[1], + $up{$s} == 1 ? + "$text{'yes'}" : + $up{$s} == 2 ? + "$text{'index_nu'}" : + $up{$s} == 3 ? + "$text{'index_nl'}" : + "$text{'no'}" ], + undef, "id", $s->{'id'}); + } + print &ui_columns_end(); + print &ui_links_row(\@links); + push(@buts, [ "shut", $text{'index_shut'} ]) if ($access{'shut'}); + push(@buts, [ "reboot", $text{'index_reboot'} ]) if ($access{'reboot'}); + print &ui_form_end(\@buts); + } +else { + print "",&text('index_none', "../servers/"),"
\n"; + } + +if (@servers) { + # Show email notification form + print "
\n"; + next; + } + &remote_foreign_require($server->{'host'}, "init", + "init-lib.pl"); + $cmd = $pfx eq 'shut' ? $iconfig->{'shutdown_command'} + : $iconfig->{'reboot_command'}; + $out = &remote_eval($server->{'host'}, "init", + "system('$cmd')"); + print &text('shut_done'),"
\n"; + } + + &ui_print_footer("", $text{'index_return'}); + } +else { + # Ask first + &ui_print_header(undef, $text{$pfx.'_title'}, ""); + + print &ui_form_start("shutdown.cgi", "post"); + foreach $id (@ids) { + print &ui_hidden("id", $id); + ($server) = grep { $_->{'id'} eq $id } @servers; + push(@names, $server->{'host'}); + } + print &ui_hidden($pfx, 1); + print "
\n"; + print &ui_submit($text{'shut_ok'}, "confirm"),"
\n"; + print "",$text{'shut_sel'},"\n", + join(" ", map { "$_" } @names),"
\n"; + print "