????

Your IP : 216.73.216.174


Current Path : /lib/raider/Raider/Jobs/
Upload File :
Current File : //lib/raider/Raider/Jobs/Mdraid.pm

use strict;
use warnings;

package Raider::Jobs::Mdraid;
use base qw( Raider::Jobs );

use Raider::Notification::API;
use Raider::Notification::Email;

=head1 NAME

Raider::Jobs::Mdraid - Mdraid specific tasks for checking raid health

=head1 DESCRIPTION

Checks raid health for Mdraid arrays.

=head1 USAGE

use Raider::Jobs::Mdraid;
my jobsMdraid = Raider::Jobs::Mdraid->new();

=head1 METHODS

=head2 run_job

Takes all needed actions for checking raid health.

=head2 get_array_list(\%args)

Returns a list of arrays.

=head2 array_is_ok(\%args)

Returns true if array is healthy.

=cut


sub run_job {
  my $self = shift;

  my $conf_file = $self->read_conf_file();
  unless ($conf_file->{'enable_mdraid_notifications'}) {
    $self->logger({cat => 'i', msg => "Run job for device 'Mdraid' suppressed by config file."});
    return;
  }

  my $degraded_raids = 0;
  my @degraded_md_devices = ();

  # We only want to health check the whitelisted MD devices if defined.
  my ($md_devices,$mdstat_contents) = $self->get_md_devices({ whitelisted_only => 1 });
  for my $md_device ( @{ $md_devices } ) {
    
    unless ( $self->array_is_ok({ md_device => $md_device, mdstat_contents => $mdstat_contents }) ) {
      $degraded_raids = 1;
      push(@degraded_md_devices, $md_device);
    }
  };

  my $notifEmail = Raider::Notification::Email->new();
  my $notifAPI = Raider::Notification::API->new();

  if ( $degraded_raids ) {

    my $output = "Degraded MD device(s): [@degraded_md_devices]\nroot ~ # cat /proc/mdstat\n$mdstat_contents\nroot ~ #\n";

    if ( $notifAPI->can_alert({ notify_type => 'Mdraid' }) ) {
      $self->logger({ cat => 'w', msg => 'Mdraid RAID Alarm Detected' });
      my $notify_msg = "Mdraid RAID Alarm Detected on [$Raider::Base::base_conf{'hostname'}] at [$self->{uniq_id}]\nDetails:\n $output";
      if ( $notifAPI->can_api() ) {
        $notifAPI->send_notification({ 
          message => $notify_msg
        });
      }
      else {
        $notifEmail->send_notification({ 
            subject => "RAID Controller Alarm on $Raider::Base::base_conf{'hostname'}",
            message => $notify_msg
          });
      }
      $notifAPI->place_alert({notify_type => 'Mdraid'});
    }
    else {
      $self->logger({ cat => 'w', msg => 'Notification for Mdraid suppressed, alert file for today already exists.' });
    }
  }
  else {
    # health is ok, clear alerts for device
    $notifAPI->clear_alerts_for_device('Mdraid');
  }
}  

sub get_md_devices {
  my $self = shift;
  my $opts = shift;

  my @md_devices = ();
  my $mdstat_contents = do {
    local $/ = undef;
    open my $fh, "<", '/proc/mdstat' || $self->logger({ cat => 'c', msg => "Unable to open /proc/mdstat: [$!]" });
    <$fh>;
  };

  # If we are told to only get whitelisted devices, and if mdraid_monitoring_whitelisted_devices is enabled, record what is whitelisted for later use.
  my $whitelisted_md_device;
  if ( defined($opts->{whitelisted_only}) && $opts->{whitelisted_only} ) {
    my $conf_file = $self->read_conf_file();
    if ( defined($conf_file->{'mdraid_monitoring_whitelisted_devices'}) && $conf_file->{'mdraid_monitoring_whitelisted_devices'} ) {
      for my $md_device ( split /:/, $conf_file->{'mdraid_monitoring_whitelisted_devices'} ) {
        $whitelisted_md_device->{ $md_device } = 1;
      }
    }
  }

  for my $line ( split /^/, $mdstat_contents ) {
    if ( $line =~ /^(md\d+)(\s+):\s+/ ) {
      # If we have whitelisted MD devices specified, respect that.
      if ( ref($whitelisted_md_device) eq 'HASH' ) {
        if ( defined($whitelisted_md_device->{ $1 }) ) {
          push(@md_devices, $1);  
        }
        else {
          $self->logger({ cat => 'w', msg => "Ignoring health check of non-whitelisted MD device [$1]" });
          next;
        }
      }
      else {
        push(@md_devices, $1);
      }
    }
  }

  return (\@md_devices,$mdstat_contents);
}

sub array_is_ok {
  my $self = shift;
  my $opts = shift;

  my $ideal_disks = 0;
  my $disks_in_use = 0;
  
  my $passed_md = 0;
  for my $line ( split /^/, $opts->{mdstat_contents} ) {  
  
    if ( $passed_md ) {
      if ( $line =~ /blocks/ && $line =~ /\[(\d+)\/(\d+)\]/ ) {
        $ideal_disks = $1;
        $disks_in_use = $2;
        last; # Found what we wanted, break loop.
      }
    }  
    
    if ( $line =~ /^$opts->{md_device}(\s+)?:\s+\S+/ ) {
      $passed_md = 1;
      next;
    }
    else {
      $passed_md = 0;
    }
  }

  # degraded if actually used disks is less than ideal.
  if ( $disks_in_use < $ideal_disks ) {
    return 0;
  }
  else {
    return 1;
  }
}


1;