????

Your IP : 216.73.216.174


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

use strict;
use warnings;

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

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

=head1 NAME

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

=head1 DESCRIPTION

Checks raid health for MegaraidSAS cards.

=head1 USAGE

use Raider::Jobs::MegaraidSAS;
my jobs3ware = Raider::Jobs::MegaraidSAS->new();

=head1 METHODS

=head2 get_icmd()

Returns the PATH to the icmd.

=head2 run_job

Takes all needed actions for checking raid health.

=head2 get_controller_list()

Returns a list of controllers.

=head2 get_array_list(\%args)

Returns a list of arrays.

=head2 array_is_ok(\%args)

Returns true if array is healthy.

=cut

sub get_icmd {
  my $self = shift;
  my $arch = $self->get_arch();
  my $icmd;
  if ( $arch eq '64bit' ) {
    $icmd = '/opt/MegaRAID/MegaCli/MegaCli64';
  }
  elsif ( $arch eq '32bit' ) {
    $icmd = '/opt/MegaRAID/MegaCli/MegaCli';
  }
  else {
    $self->logger({ cat => 'c', msg => "get_arch() returned an invalid value: '$arch'" });
  }
  return $icmd;
}

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

  my $icmd = $self->get_icmd();
  $self->icmd_in_path({ icmd => "$icmd" });
  my $output;
  my $controller_list_ref = $self->get_controller_list({ icmd => "$icmd" });
  my @controller_list = @$controller_list_ref;  
  my $raid_bad = 0;
  my $bbu_bad = 0;

  # Health checks
  for my $controller ( @controller_list ) {

    # RAID
    my $array_list_ref = $self->get_array_list({ icmd => "$icmd", c => "$controller" });
    my @array_list = @$array_list_ref;
    for my $u ( @array_list ) {
      my $health_check = `$icmd -LDInfo -L$u -a$controller`;
      unless ( $self->array_is_ok({ health_check => $health_check }) ) {
        $output .= "root ~ # $icmd -LDInfo -L$u -a$controller\n";
        $output .= "$health_check\n";
        $output .= "root ~ #\n";
        $raid_bad = 1;
      }
    };

    # BBU
    if ( $opts->{'bbu_check'} ) {
      for my $line ( split /^/, `$icmd -AdpAllInfo -a$controller` ) {
        if ( $line =~ /^BBU(\s+)?:\s+Present/i ) {
          $self->logger({ cat => 'i', msg => "BBU detected on adapter $controller" });
          my $bbu_check_cmd = `$icmd -AdpBbuCmd -GetBbuStatus -a$controller`;
        
          # Prevent appending entry for good BBUs that were set bad by previous
          # controller. 
          my $needs_append = 0;

          # MegaCLI Ver 8.02.21 uses "Operational" , MegaCLI Ver 8.07.06 uses "Optimal".
          # FS#5916 - Don't report state 'Learning'.
          if ( $bbu_check_cmd !~ /Battery\s+State(\s+)?:\s+[Operational|Optimal|Learning]/i ) {
            $bbu_bad = 1;
            $needs_append = 1;
          }

          # 'Battery State:' field will show as "Failed" on charging, account for this.
          if ( $bbu_check_cmd =~ /Charging\s+Status(\s+)?:\s+Discharging/i ) {
            $bbu_bad = 0;
          }

          # If utility says we need replacing, always report.
          if ( $bbu_check_cmd =~ /Battery\s+Replacement\s+required(\s+)?:\s+Yes/i ) {
            $bbu_bad = 1;
            $needs_append = 1;
          }

          if ( $needs_append ) {
            $self->logger({ cat => 'w', msg => "Error detected with BBU on adapter $controller" });

            my $bbu_check_cmd_pretty = "root ~ # $icmd -AdpBbuCmd -GetBbuStatus -a$controller\n";
            $bbu_check_cmd_pretty .= "$bbu_check_cmd\n";
            $bbu_check_cmd_pretty .= "root ~ #\n";

            $output .= "Error detected with BBU on Adapter $controller. Details below:\n";
            $output .= $bbu_check_cmd_pretty;
            
          }
        }
      }
    }

  };

  my $notIfAPI = Raider::Notification::API->new();
  my $notIfEmail = Raider::Notification::Email->new();

  if ( $raid_bad || $bbu_bad ) {
    if ( $notIfAPI->can_alert({ notify_type => 'MegaraidSAS' }) ) {
     
      # First alarm today. Log some additional information.
      my $megacli_cfg_display = `$icmd -CfgDsply -aALL`;
      $self->logger({ cat => 'i', msg => "First invocation of MegaraidSAS alarm today; Full details:\n$megacli_cfg_display" });

      my $notify_summary;
      if ( $raid_bad && $bbu_bad ) {
        $notify_summary = 'MegaraidSAS Hardware RAID and BBU Alarm Detected';
      }
      elsif ( $raid_bad && ! $bbu_bad  ) {
        $notify_summary = 'MegaraidSAS Hardware RAID Alarm Detected';
      }
      elsif ( $bbu_bad && ! $raid_bad ) {
        $notify_summary = 'MegaraidSAS BBU Alarm Detected';
      }

      $self->logger({ cat => 'w', msg => $notify_summary });
      my $notify_msg = "$notify_summary 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 => 'MegaraidSAS'});
    }
    else {
      $self->logger({ cat => 'w', msg => 'Notification for MegaraidSAS suppressed, alert file for today already exists.' });
    }
  }
  else {
    # health is ok, clear alerts for device
    $notIfAPI->clear_alerts_for_device('MegaraidSAS');
  }
}

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

  my @ctrls = ();
  for my $line ( split /^/, `$opts->{icmd} -AdpAllInfo -aALL` ) {
    if ( $line =~ /Adapter\s+#(\d+)/i ) {
      push(@ctrls, $1);
    }
  }

  return \@ctrls;
}

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

  my $utotal = 0;
  for my $line ( split /^/, `$opts->{icmd} -AdpAllInfo -a$opts->{c}` ) {
    if ( $line =~ /^Virtual\s+Drives\s+:\s+(\d+)/i ) {
      $utotal = $1;
    }
  }
  $utotal--;
  my @array_list = map { 0 + $_ } 0..$utotal;

  return \@array_list;
}

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

  $self->logger({ cat => 'c', msg => "array_is_ok() missing an argument!" }) unless ( $opts->{health_check} );

  if ( $opts->{health_check} =~ /State(\s+)?:\s+Optimal|Virtual\s+Drive\s+\d+\s+Does\s+not\s+Exist/i ) {
    return 1;
  }

  # CacheCade virtual drives don't always have a State field (FS#5948).
  # ~/ssullivan 2013/04/08
  if ( $opts->{health_check} =~ /Virtual\s+Drive\s+Type(\s+)?:\s+CacheCade/i ) {
    if ( $opts->{health_check} =~ /State(\s+)?:\s+(\S+)/i ) {
      if ( $2 =~ /Optimal/i ) {
        return 1;
      }
      else {
        return 0;
      }
    }
    else {
      return 1;
    }  
  }

  return 0;
}


1;