#!/usr/bin/perl ################################################################### # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # For information : david.barbion@adeoservices.com #################################################################### # Author: Alexandre Branquinho # Based on script check_msa by Angelo Conforti http://exchange.nagios.org/directory/Plugins/Hardware/Storage-Systems/SAN-and-NAS/check_msa/details # # Check MSA2012i G1 Storage Array hardware, almost every part # The checks are made over Telnet (or SSH?) connection # Not tested with another MSA2xxx other than MSA2012i, but can work # # Needs Net::Telnet, XML::Simple and Switch # Please see http://h10032.www1.hp.com/ctg/Manual/c02710176.pdf as CLI reference. use Net::Telnet; use XML::Simple; use Getopt::Long; use Switch; %ERRORS=(0=>'OK',1=>'WARNING',2=>'CRITICAL',3=>'UNKNOWN',4=>'DEPENDENT'); Getopt::Long::Configure("bundling"); GetOptions( 'u:s' => \$usuario, 'p:s' => \$senha, 'h:s' => \$end_storage, 't:s' => \$comando ); unless (defined($usuario)) { $usuario = "manage"; } unless (defined($senha)) { $senha = "!manage"; } unless (defined($end_storage)) { ajuda(); } unless (defined($comando)) { ajuda(); } $t = new Net::Telnet (Timeout => 10, Prompt => '/# /', -output_record_separator => "\n", -telnetmode => 0, -binmode => 0); $t->max_buffer_length("2048000"); $t->open($end_storage); $t->login($usuario, $senha); $t->cmd("set cli-parameters api"); $t->cmd("set cli-parameters pager disabled"); $t->cmd("set cli-parameters temperature-scale c"); $t->cmd("set cli-parameters units GB"); $status = ""; $exit = 0; sub enviacomando($) { ($cmd) = @_; $linhas = ""; $t->print($cmd); $t->getline(); while ($linha = $t->getline()) { $linhas .= $linha; last if ($linha =~ /<\/RESPONSE>/); } return $linhas; } my @comm = split(/\s/, $comando); $comando = $comm[0]; switch ($comando) { case "channels" { channels(); } case "redundancy" { redundancy(); } case "disks" { disks(); } case "enclosure" { enclosure(); } case "frus" { frus(); } case "sensors" { sensors(); } case "vdisks" { vdisks(); } else { ajuda(); } } sub channels() { $linhas = enviacomando("show channels"); $channels = XMLin($linhas, ForceArray => 1, KeyAttr => {PROPERTY => 'name'}); foreach my $channel (@{$channels->{'OBJECT'}}) { next unless ($channel->{'name'} eq 'name'); next unless ($channel->{'PROPERTY'}->{'type'}->{'content'} eq "Host"); $state = $channel->{'PROPERTY'}->{'status'}->{'content'}; unless ($state eq "Up") { if ($exit < 2) { $exit = 2; } } $status = sprintf("$status [(%s-%s,%s,%s) %s]", $channel->{'PROPERTY'}->{'controller'}->{'content'}, $channel->{'PROPERTY'}->{'channel'}->{'content'}, $channel->{'PROPERTY'}->{'actual-speed'}->{'content'}, $channel->{'PROPERTY'}->{'primary-ip-address'}->{'content'}, $state); } } sub redundancy() { $linhas = enviacomando("show redundancy-mode"); $redundancy = XMLin($linhas, ForceArray => 1, KeyAttr => {OBJECT => 'name', PROPERTY => 'name'}); $reduntant = $redundancy->{'OBJECT'}->{'system-redundancy'}->{'PROPERTY'}->{'redundancy-status'}->{'content'}; $status = sprintf("$status [%s (%s, %s,%s %s),(%s %s,%s)]", "Controladoras:", "A:",$redundancy->{'OBJECT'}->{'system-redundancy'}->{'PROPERTY'}->{'controller-a-status'}->{'content'}, "B:",$redundancy->{'OBJECT'}->{'system-redundancy'}->{'PROPERTY'}->{'controller-b-status'}->{'content'}, "Redundancia:",$redundancy->{'OBJECT'}->{'system-redundancy'}->{'PROPERTY'}->{'redundancy-status'}->{'content'}, $redundancy->{'OBJECT'}->{'system-redundancy'}->{'PROPERTY'}->{'redundancy-mode'}->{'content'}); unless ($reduntant eq "Redundant Operation" or $reduntant eq "Redundant") { if ($exit < 2) { $exit = 2; } } } sub disks() { $linhas = enviacomando("show disks"); $disks = XMLin($linhas, ForceArray => 1, KeyAttr => {PROPERTY => 'name'}); foreach my $disk (@{$disks->{'OBJECT'}}) { next unless ($disk->{'name'} eq 'drive'); $listadiscos = "$listadiscos $disk->{'PROPERTY'}->{'slot'}->{'content'}"; $state = $disk->{'PROPERTY'}->{'status'}->{'content'}; $rodando = $disk->{'PROPERTY'}->{'job-running'}->{'content'}; $error = $disk->{'PROPERTY'}->{'error'}->{'content'}; switch ($rodando) { case "DRSC" { $tarefa = "The disk is being scrubbed"; } case "EXPD" { $tarefa = "The vdisk is being expanded"; } case "INIT" { $tarefa = "The vdisk is being initialized"; } case "LOWF" { $tarefa = "A low-level format is in progress"; } case "RCON" { $tarefa = "The vdisk is being reconstructed"; } case "VRFY" { $tarefa = "The vdisk is being verified"; } case "VRSC" { $tarefa = "The vdisk is being scrubbed"; } } unless ($error eq "0") { $status = sprintf("$status [Disco %s (Estado %s,Tam %s Tb,Pai Ctrl %s) %s]", $disk->{'PROPERTY'}->{'slot'}->{'content'}, $state, $disk->{'PROPERTY'}->{'size'}->{'content'}, $disk->{'PROPERTY'}->{'owner'}->{'content'}, $tarefa); if ($exit < 2) { $exit = 2; } } } if ($exit <1) { $status = "$status Discos $listadiscos: OK"; } } sub enclosure() { $linhas = enviacomando("show enclosure-status"); $enc= XMLin($linhas, ForceArray => 1, KeyAttr => {PROPERTY => 'name'}); foreach my $encl (@{$enc->{'OBJECT'}}) { next unless ($encl->{'name'} eq 'enclosure-environmental'); $state = $encl->{'PROPERTY'}->{'status'}->{'content'}; unless ($state eq "OK") { if ($exit < 2) { $exit = 2; } } $status = sprintf("$status [%s %s %s %s]", $encl->{'PROPERTY'}->{'vendor'}->{'content'}, $encl->{'PROPERTY'}->{'product-id'}->{'content'}, $encl->{'PROPERTY'}->{'chassis'}->{'content'}, $state); } foreach my $encl (@{$enc->{'OBJECT'}}) { next unless ($encl->{'name'} eq 'enclosure-component'); $state = $encl->{'PROPERTY'}->{'status'}->{'content'}; $tipo=$encl->{'PROPERTY'}->{'type'}->{'content'}; $num=$encl->{'PROPERTY'}->{'enclosure-unit-number'}->{'content'}; $addata=$encl->{'PROPERTY'}->{'additional-data'}->{'content'}; unless ($state eq "OK") { $status = "$status [$tipo $num $addata $state]"; if ($exit < 2) { $exit = 2; } } } } sub frus() { $linhas = enviacomando("show frus"); $frus = XMLin($linhas, ForceArray => 1, KeyAttr => {PROPERTY => 'name'}); foreach my $fru (@{$frus->{'OBJECT'}}) { next unless ($fru->{'name'} eq 'midplane-fru'); $listafrus = "$listafrus $fru->{'PROPERTY'}->{'name'}->{'content'}"; $state = $fru->{'PROPERTY'}->{'fru-status'}->{'content'}; $desc = $fru->{'PROPERTY'}->{'description'}->{'content'}; $shname = $fru->{'PROPERTY'}->{'fru-shortname'}->{'content'}; $loc = $fru->{'PROPERTY'}->{'fru-location'}->{'content'}; unless ($state eq "OK") { $status = "$status [$shname: $desc,$loc / $state]"; if ($exit < 2) { $exit = 2; } } } foreach my $fru (@{$frus->{'OBJECT'}}) { next unless ($fru->{'name'} eq 'enclosure-fru'); $listafrus = "$listafrus $fru->{'PROPERTY'}->{'name'}->{'content'}"; $state = $fru->{'PROPERTY'}->{'fru-status'}->{'content'}; $desc = $fru->{'PROPERTY'}->{'description'}->{'content'}; $shname = $fru->{'PROPERTY'}->{'fru-shortname'}->{'content'}; $loc = $fru->{'PROPERTY'}->{'fru-location'}->{'content'}; unless ($state eq "OK") { $status = "$status [$shname: $desc,$loc / $state]"; if ($exit < 2) { $exit = 2; } } } if ($exit < 1) { $status = "$status $listafrus: OK"; } } sub sensors() { $linhas = enviacomando("show sensor-status"); $sensors = XMLin($linhas, ForceArray => 1, KeyAttr => {PROPERTY => 'name'}); foreach my $sensor (@{$sensors->{'OBJECT'}}) { next unless ($sensor->{'name'} eq 'sensor'); $item = $sensor->{'PROPERTY'}->{'sensor-name'}->{'content'}; $value = $sensor->{'PROPERTY'}->{'value'}->{'content'}; $state = $sensor->{'PROPERTY'}->{'status'}->{'content'}; unless ($state eq "OK") { $status = "$status [$item $value $state]"; if ($exit < 2) { $exit = 2; } } } if ($exit < 2) { $status="$status Sensores OK"; } } sub vdisks() { $linhas = enviacomando("show vdisks"); $vdisks = XMLin($linhas, ForceArray => 1, KeyAttr => {PROPERTY => 'name'}); foreach my $vdisk (@{$vdisks->{'OBJECT'}}) { next unless ($vdisk->{'name'} eq 'virtual-disk'); $state = $vdisk->{'PROPERTY'}->{'status'}->{'content'}; unless ($state eq "FTOL") { if ($state eq "FTDN" or $state eq "UP" or $state eq "CRIT") { if ($exit < 1) { $exit = 1; } } if ($state eq "OFFL" or $state eq "QRCR" or $state eq "QROF") { if ($exit < 2) { $exit = 2; } } } $status = sprintf("$status [Vdisk: %s (%s Usados,%s Livres,%s,%s Discos/%s Spares,Particoes %s) Status %s,Pai: Ctrl %s]", $vdisk->{'PROPERTY'}->{'name'}->{'content'}, $vdisk->{'PROPERTY'}->{'size'}->{'content'}, $vdisk->{'PROPERTY'}->{'freespace'}->{'content'}, $vdisk->{'PROPERTY'}->{'raidtype'}->{'content'}, $vdisk->{'PROPERTY'}->{'diskcount'}->{'content'}, $vdisk->{'PROPERTY'}->{'sparecount'}->{'content'}, $vdisk->{'PROPERTY'}->{'num-array-partitions'}->{'content'}, $state, $vdisk->{'PROPERTY'}->{'owner'}->{'content'}, ); } } $t->close(); printf("%s:%s\n",$ERRORS{$exit},$status); exit $exit; sub ajuda() { print "Check MSA Health - Alexandre Branquinho "."\n"; print "--------------------------------------------------------------"."\n"; print "Usage: check_msa [-u ] [-p ] -h -t "."\n"; print "\n"; print "If not provided, default manage username and password will be used."."\n"; print "The following types of checks are available:"."\n"; print "\n"; print "channel - checks the status of the hosts ports"."\n"; print "redundancy - checks the status of the controllers redundancy"."\n"; print "disks - checks various informations about the physical disks"."\n"; print "enclosure - checks the status of enclosure's components"."\n"; print "frus - checks the status of all field-replaceable units"."\n"; print "sensors - checks all sensors of the storage"."\n"; print "vdisks - checks the status of the virtual disks"."\n"; exit(1); }