????

Your IP : 216.73.216.174


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

use strict;
use warnings;

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

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

=head1 NAME

Raider::Jobs::Adaptec - Adaptec/Microsemi specific tasks for checking raid health

=head1 DESCRIPTION

Performs various health checks for Adaptec/Microsemi cards.

=head1 USAGE

use Raider::Jobs::Adaptec;
my jobsAdaptec = Raider::Jobs::Adaptec->new();

=head1 METHODS

=head2 run_job()

Takes all needed actions for checking 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

my $icmd = '/usr/StorMan/arcconf';

sub run_job {
  my ($self, $opts) = @_;

  $self->icmd_in_path({icmd => $icmd});
  my $output;
  my $raid_bad = 0;
  my $bbu_bad = 0;
  my $temp_bad = 0;
  my $unhealthy = 0;

  # Health checks
  for my $controller (@{$self->get_controller_list()}) {

    # RAID LD
    for my $u (@{$self->get_array_list({c => $controller})}) {
      my $health_check = `$icmd getconfig $controller LD $u`;
      unless ($self->array_is_ok({health_check => $health_check})) {
        $output .= "root ~ # $icmd getconfig $controller LD $u\n";
        $output .= "$health_check\n";
        $output .= "root ~ #\n";
        $raid_bad = 1;
        $unhealthy = 1;
      }
    };

    if ($opts->{bbu_check} || $opts->{cntlr_temp_checks}) {
      my $cntlr_get_config = `$icmd getconfig $controller AD`;

      # ZMM (Zero Maintenance Module)
      # Essentially, ZMM is an evolutionary improvement upon BBU. The main difference
      # is that unlike BBU, no external dedicated battery is required.
      if ($cntlr_get_config =~ /Controller\s+ZMM\s+Information/i) {
        # TODO? Actually report on its status..
        #    --------------------------------------------------------
        #    Controller ZMM Information
        #    --------------------------------------------------------
        #    Status                                   : ZMM not installed
        $self->logger({
          cat => 'i',
          msg => 'ZMM is supported/detected, as such any BBU check will be skipped on this controller'
        });
      }
      # BBU (Battery Backup Unit)
      elsif ($opts->{bbu_check}) {
        # BBU checks are enabled, and no ZMM is present, so proceed checking BBU.
        if ($cntlr_get_config !~ /\s+Status(\s+)?:\s+Not\s+Installed/i ) {
BBU_E:    for my $line (split /^/, $cntlr_get_config) {
            if ($line =~ /^\s+Status(\s+)?:\s+\S+/i) {
              $self->logger({cat => 'i', msg => "Adaptec BBU detected on adapter $controller"});

              # Consider BBU bad state if status is not 'Optimal', and BBU is less than 100%
              # charged (FS#5883, work around rounding error).
              if ($line !~ /^\s+Status(\s+)?:\s+Optimal/i
                  && $line !~ /Capacity\s+remaining(\s+)?:\s+100\s+percent/i) {
                $self->logger({cat => 'w', msg => "Adaptec BBU health abnormal on adapter $controller"});
                $bbu_bad = 1;
                $unhealthy = 1;
                $output .= "Error detected with BBU on Adapter $controller. Details below:\n";
                $output .= "root ~ # $icmd getconfig $controller AD";
                $output .= "$cntlr_get_config\n";
                $output .= "root ~ #\n";
                last BBU_E;
              }
            }
          }
        }
      }

      # Controller temperature
      if ($opts->{cntlr_temp_checks}) {
TMP_E:  for my $line (split /^/, $cntlr_get_config) {
          if ($line =~ /^\s+Temperature(\s+)?:\s+(.+)/i) {
            my $tmp_details = $2;
            if ($tmp_details !~ /Abnormal/i) {
              $self->logger({cat => 'i', msg => "Adaptec controller temperature is normal [$tmp_details]"});
            }
            else {
              $temp_bad = 1;
              $unhealthy = 1;
              $self->logger({cat => 'w', msg => "Adaptec controller temperature abnormal [$tmp_details]"});
              $output .= "Controller [$controller] temperature abnormal [$tmp_details]. Details below:\n";
              $output .= "root ~ # $icmd getconfig $controller AD";
              $output .= "$cntlr_get_config\n";
              $output .= "root ~ #\n";
              last TMP_E;
            }
          }
        }
      }
    }
  };

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

  if ($unhealthy) {
    if ($notifAPI->can_alert({notify_type => 'Adaptec'})) {
      my $notify_summary;
      my $temp_msg = 'Adaptec Temperature Warning ';
      my $raid_msg = 'Adaptec Hardware RAID Alarm Detected ';
      my $bbu_msg = 'Adaptec BBU Alarm Detected ';
      $notify_summary .= $raid_msg if $raid_bad;
      $notify_summary .= $temp_msg if $temp_bad;
      $notify_summary .= $bbu_msg if $bbu_bad;

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

sub get_controller_list {
  my ($self) = @_;
  
  my $controller_raw = `$icmd getconfig 0`;
  $controller_raw =~ /Controllers\s+found:\s+(\d+)/i;
  my $ctotal = $1;
  my @ctotal_final = map { 0 + $_ } 1..$ctotal;

  return \@ctotal_final;
}

sub get_array_list {
  my ($self, $opts) = @_;

  my @array_list;
  for my $line ( split /^/, `$icmd getconfig $opts->{c} LD` ) {
    if ( $line =~ /Logical\s+device\s+number\s+(\d+)/i ) {
      push(@array_list, $1);
    }
  }

  return \@array_list;
}

sub array_is_ok {
  my ($self, $opts) = @_;

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

  # Check raid health. Ignore rebuilding array if set in config.
  my $conf_file = $self->read_conf_file();
  if ($conf_file->{'ignore_rebuilding_array'}) {
    if ($opts->{health_check} !~ /Status\s+of\s+logical\s+device(\s+)?:\s+Optimal/i
        && $opts->{health_check} !~ /Group\s+\S+\s+Segment\s+\d+(\s+)?:\s+Rebuilding/i ) {
      return 0;
    }
  }
  elsif ($opts->{health_check} !~ /Status\s+of\s+logical\s+device(\s+)?:\s+Optimal/i) {
    return 0;
  }

  return 1;
}


1;