????
| Current Path : /lib/raider/Raider/Jobs/ |
| 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;