#!/usr/bin/perl
################################################################
## raid_monitor.pl
##--------------------------------------------------------------
## Date       : 20070127
## Author     : Michael Mikowsk, z_mikowsk@yahoo.com
## Description: Cron job that emails user(s) if RAID disk fails
## License    : GPL v2
#################################################################
use strict;
use Date::Calc qw{ Today_and_Now Date_to_Text };
use MIME::Lite();
use Carp;

use Getopt::Long;

## BEGIN configuration variables
my $smtp_host    = q{smtp.yourisp.net},
my $from_address = q{admin@yourisp.net};
my @to_addrs     = qw(
  bob@yourisp.net
  fred@yahoo.com
);

my @cc_addrs     = qw(
  tammy@msn.com
  edwina@otherisp.com
);

## END configuration variables

## BEGIN other package variables
my $help;
my $my_exec = $0;
my $msg_error;
my $flag_error = 0;
## END other package variables

## BEGIN parse options
GetOptions( help => \$help );

if ( $help ){
  print_help();
  exit 0;
}
## END parse options

## BEGIN get mdstat and process output
my @mdstat_lines = `cat /proc/mdstat`;

MDLOOP:
for my $mdstat_line(@mdstat_lines){
  chomp $mdstat_line;
  $msg_error .= $mdstat_line . qq{\n};

  # process lines like: Personalities : [raid1]
  if($mdstat_line =~ m/^\s*Personalities :/){
    next MDLOOP;
  }
  #  process lines like: md0 : active raid1 sda1[0] sdb1[1]
  if($mdstat_line =~ m/^\s*(md\d+) : ([^ ]+) ([^ ]+)/){
    my ($md_num, $raid_status, $raid_pers) = ($1,$2,$3);
    if($raid_status ne 'active') {
      $flag_error = 1;
      $msg_error .= qq{WARN: $raid_pers $md_num does not appear active\n};
    }
    next MDLOOP;
  }

  # process lines like:   47102464 blocks [2/2] [UU]
  if($mdstat_line =~ m/^\s+(\d+)* blocks \[(\d+)\/(\d+)\] \[([A-z]*)\](.*)$/){
    my ( $md_blocks, $md_count1, $md_count2, $md_status, $md_thingies )
      = ( $1,$2,$3,$4,$5 )
      ;
    if( $md_count1 != $md_count2 ) {
      $flag_error = 1;
      $msg_error
        .= qq{WARN: Array appears degraded, $md_count1 of $md_count2 disks\n}
        ;
    }
    $msg_error .= qq{\n};
    next MDLOOP;
  }
}
## END get mdstat and process output

## silently exit if no error
exit unless $flag_error;

## BEGIN configure mailer
MIME::Lite->send(
 q{smtp},
 $smtp_host,
 Timeout => 30,
);
## END configure mailer

## BEGIN build and send message
my $to_list  = join(',',@to_addrs);
my $cc_list  = join(',',@cc_addrs);
my $hostname =`hostname`;
chomp $hostname;
my $subject  = qq{WARNING: RAID on $hostname};

my @today_and_now = Today_and_Now();
my $str_timedate  = join q{:},@today_and_now[3..5];
$str_timedate    .= q{ } . Date_to_Text(@today_and_now[0..2]);

my $msg      = <<EOT;
WARNING: The RAID on $hostname appears degraded.
$str_timedate 

Diagnostics are listed below:

$msg_error

==================
Message generated by $my_exec
a script by Michael Mikowski

EOT

my $msg_obj = MIME::Lite->build(
  To          => $to_list,
  From        => $from_address,
  Cc          => $cc_list,
  Subject     => $subject,
  Type        => 'text/plain',
  Data        => $msg,
);

  ## BEGIN mail it!
my ($ret,$err) = $msg_obj->send();
if ($err) {
  print qq{Mail sending failed: $err\n};
}
  ## END mail it!
## END build and send message

## BEGIN print_help
sub print_help {
  print <<EOH;
    $my_exec -
      Checks status of RAID devices and emails a list of 
      users if any device is degraded or otherwise abnormal.

      This is designed to be run as a cron job, hourly or
      daily.  You can do this by adding this as a symbolic
      link in the /etc/cron.hourly or /etc/cron.daily directory.

    Arguments:
      --help          Prints this help screen

EOH
}
## END print_help

