#! /usr/bin/env perl # Script to start any virtuals which are down. Designed to be run # from a cron job. The first pass, it will determine a virtual down # and create a flag file in /tmp/virtname.down. # On the next pass, it will see the virtual is still down and the # flag file exists in /tmp. At that point, it will attempt to start the # virtual and remove the file. # On any pass, if it sees a virtual is up, it will remove the flag file # if it exists. # # A config file may include domain names and any number of # mailto: entries. For example: # mailto: ops@example.com, admin@example.com # remote1 # remote2 # # A domain will trigger a notification when first detected down and again # when a restart is attempted. use strict; use warnings; use File::Spec::Functions qw(rel2abs); use File::Basename; use Sys::Hostname qw(hostname); my $configFileSuffix = '.cfg'; my @servers; my @mailRecipients; # loads the config file into @servers and @mailRecipients. sub loadConfig { my ($confName, $servers, $mailRecipients) = @_; if ( -f $confName ) { open my $CONF, '<', $confName or die "Could not read $confName: $!\n"; while ( my $line = <$CONF> ) { chomp $line; $line =~ s/\r$//; next if $line =~ /^\s*#/; next if $line =~ /^\s*$/; if ( $line =~ /^\s*mailto\s*:\s*(.+?)\s*$/i ) { my @recipients = split /[\s,;]+/, $1; push @$mailRecipients, grep { length $_ } @recipients; next; } push @$servers, $line; } close $CONF; } } sub sendMail { my ($recipients, $subject, $message) = @_; return unless @$recipients; my %seen; my @to = grep { !$seen{$_}++ } @$recipients; if ( -x '/usr/sbin/sendmail' ) { open my $mailer, '|-', '/usr/sbin/sendmail', '-t' or die "Could not open /usr/sbin/sendmail: $!\n"; print $mailer "To: " . join(', ', @to) . "\n"; print $mailer "From: checkVirtuals@" . hostname() . "\n"; print $mailer "Subject: $subject\n"; print $mailer "Content-Type: text/plain; charset=UTF-8\n"; print $mailer "\n"; print $mailer $message; close $mailer or warn "sendmail returned an error while sending '$subject'\n"; return; } if ( -x '/usr/bin/mail' ) { open my $mailer, '|-', '/usr/bin/mail', '-s', $subject, @to or die "Could not open /usr/bin/mail: $!\n"; print $mailer $message; close $mailer or warn "mail returned an error while sending '$subject'\n"; return; } warn "No mail transport found; skipping email notification for '$subject'\n"; } # Figure out full path and name of script so we can find config file. my ( $scriptname, $path ) = fileparse( $0 ); $path = rel2abs($path); # remove any suffix, if it exists if ( $scriptname =~ m/^(.*)\.[^.]+$/ ) { $scriptname = $1; } my $configFile = $path . '/' . $scriptname . $configFileSuffix; loadConfig( $configFile, \@servers, \@mailRecipients ); die "No configuration file found at $configFile\n" unless @servers; # find all running virtuals my $output = `virsh list 2>/dev/null`; # go through each virtual in @servers and make sure it is running foreach my $server ( @servers ) { my $flagFile = "/tmp/$server.down"; if ( $output =~ /(?:^|\s)$server(?:\s|$)/m ) { unlink $flagFile if -e $flagFile; next; } if ( -e $flagFile ) { print "$server has been down for a while, starting back up\n"; my $subject = "Virtual domain $server still down; attempting restart"; my $body = "The domain $server is still not running and the restart flag exists.\n"; $body .= "Attempting restart with: /usr/bin/virsh start $server\n"; $body .= "Checked at: " . scalar(localtime()) . "\n"; sendMail( \@mailRecipients, $subject, $body ); my $startStatus = system('/usr/bin/virsh start ' . $server); if ( $startStatus == 0 ) { unlink $flagFile; } else { warn "Failed to start $server with /usr/bin/virsh; leaving flag file in place\n"; } next; } my $subject = "Virtual domain $server is down"; my $body = "The domain $server is not running.\n"; $body .= "Created flag file: $flagFile\n"; $body .= "Checked at: " . scalar(localtime()) . "\n"; sendMail( \@mailRecipients, $subject, $body ); system('touch ' . quotemeta($flagFile)); } 1;