[Pkg-nagios-changes] [pkg-nagios-plugins-contrib] 01/02: check_raid: Update to 3.2.4
Jan Wagner
waja at moszumanska.debian.org
Wed Jul 8 11:56:13 UTC 2015
This is an automated email from the git hooks/post-receive script.
waja pushed a commit to branch master
in repository pkg-nagios-plugins-contrib.
commit 45d50da59fe329c52040ff626be708f20188b31e
Author: Jan Wagner <waja at cyconet.org>
Date: Wed Jul 8 12:53:22 2015 +0200
check_raid: Update to 3.2.4
---
check_raid/check_raid | 380 ++++++++++++++++++++++++++------------------------
check_raid/control | 2 +-
2 files changed, 200 insertions(+), 182 deletions(-)
diff --git a/check_raid/check_raid b/check_raid/check_raid
index 1dae914..cd1c6e7 100644
--- a/check_raid/check_raid
+++ b/check_raid/check_raid
@@ -74,10 +74,11 @@ unshift(@paths, qw(/usr/local/nrpe /usr/local/bin /sbin /usr/sbin /bin /usr/sbin
# lookup program from list of possible filenames
# search is performed from $PATH plus additional hardcoded @paths
+# NOTE: we do not check for execute bit as it may fail for non-root. #104
sub which {
for my $prog (@_) {
for my $path (@paths) {
- return "$path/$prog" if -x "$path/$prog";
+ return "$path/$prog" if -f "$path/$prog";
}
}
return undef;
@@ -85,6 +86,9 @@ sub which {
our @sudo;
sub find_sudo() {
+ # no sudo needed if already root
+ return [] unless $>;
+
# detect once
return \@sudo if @sudo;
@@ -92,7 +96,10 @@ sub find_sudo() {
push(@sudo, $sudo);
# detect if sudo supports -A, issue #88
- open(my $fh , '-|', $sudo, '-h') or die "Can't run 'sudo -h': $!";
+ use IPC::Open3;
+ my $fh;
+ my @cmd = ($sudo, '-h');
+ my $pid = open3(undef, $fh, undef, @cmd) or die "Can't run 'sudo -h': $!";
local $/ = undef;
local $_ = <$fh>;
close($fh) or die $!;
@@ -176,11 +183,11 @@ sub new {
sub active {
my $this = shift;
- # program not found
+ # no tool found, return false
return 0 unless $this->{program};
- # program not executable
- -x $this->{program};
+ # program file must exist, don't check for execute bit. #104
+ -f $this->{program};
}
# set status code for plugin result
@@ -2665,6 +2672,10 @@ sub parse_config {
# not parsed yet
} elsif ($subsection eq 'Controller Vital Product Data') {
# not parsed yet
+ } elsif ($subsection eq 'RAID Properties') {
+ # not parsed yet
+ } elsif ($subsection eq 'Controller BIOS Setting Information') {
+ # not parsed yet
} else {
warn "SUBSECTION of [$section] NOT PARSED: [$subsection] [$_]";
}
@@ -2870,35 +2881,8 @@ sub check {
}
# Battery status
- if (defined($c->{battery_status}) and $c->{battery_status} ne "Not Installed") {
- push(@status, "Battery Status: $c->{battery_status}");
-
- if ($c->{battery_overtemp} ne "No") {
- $this->critical;
- push(@status, "Battery Overtemp: $c->{battery_overtemp}");
- }
-
- push(@status, "Battery Capacity Remaining: $c->{battery_capacity}%");
- if ($c->{battery_capacity} < 50) {
- $this->critical;
- }
- if ($c->{battery_capacity} < 25) {
- $this->warning;
- }
-
- if ($c->{battery_time} < 1440) {
- $this->warning;
- }
- if ($c->{battery_time} < 720) {
- $this->critical;
- }
-
- if ($c->{battery_time} < 60) {
- push(@status, "Battery Time: $c->{battery_time}m");
- } else {
- push(@status, "Battery Time: $c->{battery_time_full}");
- }
- }
+ my @s = $this->battery_status($c);
+ push(@status, @s) if @s;
}
# check for physical devices
@@ -2956,6 +2940,54 @@ sub check {
$this->ok->message(join(', ', @status));
}
+# check battery status in $c
+sub battery_status {
+ my ($this, $c) = @_;
+
+ my @status;
+
+ if (!defined($c->{battery_status}) || $c->{battery_status} eq 'Not Installed') {
+ return;
+ }
+
+ push(@status, "Battery Status: $c->{battery_status}");
+
+ # if battery status is 'Failed', none of the details below are available. #105
+ if ($c->{battery_status} eq 'Failed') {
+ $this->critical;
+ return @status;
+ }
+
+ # detailed battery checks
+ if ($c->{battery_overtemp} ne 'No') {
+ $this->critical;
+ push(@status, "Battery Overtemp: $c->{battery_overtemp}");
+ }
+
+ push(@status, "Battery Capacity Remaining: $c->{battery_capacity}%");
+ if ($c->{battery_capacity} < 50) {
+ $this->critical;
+ }
+ if ($c->{battery_capacity} < 25) {
+ $this->warning;
+ }
+
+ if ($c->{battery_time} < 1440) {
+ $this->warning;
+ }
+ if ($c->{battery_time} < 720) {
+ $this->critical;
+ }
+
+ if ($c->{battery_time} < 60) {
+ push(@status, "Battery Time: $c->{battery_time}m");
+ } else {
+ push(@status, "Battery Time: $c->{battery_time_full}");
+ }
+
+ return @status;
+}
+
package megarc;
# LSI MegaRaid or Dell Perc arrays
# Check the status of all arrays on all Lsi MegaRaid controllers on the local
@@ -3166,6 +3198,9 @@ sub commands {
'detect hpsa' => ['<', '/sys/module/hpsa/refcnt'],
'detect cciss' => ['<', '/proc/driver/cciss'],
'cciss proc' => ['<', '/proc/driver/cciss/$controller'],
+
+ # for lsscsi, issue #109
+ 'lsscsi list' => ['-|', '@CMD', '-g'],
}
}
@@ -3214,9 +3249,10 @@ sub detect {
my ($fh, @devs);
- # try lsscsi first
- my $lsscsi = lsscsi->new();
- if ($lsscsi->active) {
+ # try lsscsi first if enabled and allowed
+ my $lsscsi = lsscsi->new('commands' => $this->{commands});
+ my $use_lsscsi = defined($this->{use_lsscsi}) ? $this->{use_lsscsi} : $lsscsi->active;
+ if ($use_lsscsi) {
# for cciss_vol_status < 1.10 we need /dev/sgX nodes, columns which are type storage
@devs = $lsscsi->list_sg;
@@ -3328,7 +3364,7 @@ sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s };
# we process until we find end of sentence (dot at the end of the line)
sub consume_diagnostic {
- my ($this, $fh, $s) = @_;
+ my ($this, $fh) = @_;
my $diagnostic = '';
while (1) {
@@ -3341,6 +3377,18 @@ sub consume_diagnostic {
return trim($diagnostic);
}
+# process to skip lines with physical location:
+# " connector 1I box 1 bay 4 ..."
+sub consume_disk_map {
+ my ($this, $fh) = @_;
+
+ while (my $s = <$fh>) {
+ chomp $s;
+ # connector 1I box 1 bay 4
+ last unless $s =~ /^\s+connector\s/;
+ }
+}
+
sub parse {
my $this = shift;
my @devs = @_;
@@ -3390,13 +3438,15 @@ sub parse {
# volume status, print_volume_status()
# /dev/cciss/c0d0: (Smart Array P400i) RAID 1 Volume 0 status: OK
# /dev/sda: (Smart Array P410i) RAID 1 Volume 0 status: OK.
- if (my($file, $board_name, $raid_level, $volume_number, $certain, $status) = m{
+ # /dev/sda: (Smart Array P410i) RAID 5 Volume 0 status: OK. At least one spare drive designated. At least one spare drive has failed.
+ if (my($file, $board_name, $raid_level, $volume_number, $certain, $status, $spare_drive_status) = m{
^(/dev/[^:]+):\s # File
\(([^)]+)\)\s # Board Name
(RAID\s\d+|\([^)]+\))\s # RAID level
Volume\s(\d+) # Volume number
(\(\?\))?\s # certain?
status:\s(.*?)\. # status (without a dot)
+ (.*)? # spare drive status messages
}x) {
$cdev = $file;
$c{$file}{volumes}{$volume_number} = {
@@ -3405,6 +3455,7 @@ sub parse {
volume_number => $volume_number,
certain => int(not defined $certain),
status => $status,
+ spare_drive_status => trim($spare_drive_status),
};
$c{$file}{board_name} = $board_name;
@@ -3487,6 +3538,23 @@ sub parse {
next if $got;
}
+ # show_disk_map(" Failed drives:", file, fd, id, controller_lun, ctlrtype,
+ # show_disk_map(" 'Replacement' drives:", file, fd, id, controller_lun, ctlrtype,
+ # show_disk_map(" Drives currently substituted for by spares:", file, fd, id, controller_lun, ctlrtype,
+ if (/^ Failed drives:/ ||
+ /^ 'Replacement' drives:/ ||
+ /^ Drives currently substituted for by spares:/
+ ) {
+ # could store this somewhere, ignore for now
+ $this->consume_disk_map($fh);
+ next;
+ }
+
+ if (my($total_failed) = /Total of (\d+) failed physical drives detected on this logical drive\./) {
+ $c{$cdev}{phys_failed} = $total_failed;
+ next;
+ }
+
warn "Unparsed[$_]";
}
close($fh);
@@ -3621,12 +3689,7 @@ package hp_msa;
use base 'plugin';
# do not register, better use hpacucli
-#push(@utils::plugins, __PACKAGE__);
-
-sub new {
- my $self = shift;
- $self->SUPER::new(tty_device => "/dev/ttyS0", @_);
-}
+push(@utils::plugins, __PACKAGE__);
sub active {
my $this = shift;
@@ -3637,6 +3700,9 @@ sub active {
sub detect {
my $this = shift;
+ # allow --plugin-option=hp_msa-enabled to force this plugin to be enabled
+ return 1 if exists $this->{options}{'hp_msa-enabled'};
+
for my $file (</sys/block/*/device/model>) {
open my $fh, '<', $file or next;
my $model = <$fh>;
@@ -3649,7 +3715,8 @@ sub detect {
sub check {
my $this = shift;
- my $ctldevice = $this->{tty_device};
+ # allow --plugin-option=hp_msa-serial=/dev/ttyS2 to specify serial line
+ my $ctldevice = $this->{options}{'hp_msa-serial'} || '/dev/ttyS0';
# status messages pushed here
my @status;
@@ -4103,14 +4170,14 @@ sub check {
$this->ok->message($this->join_status(\%status));
}
-package hpssacli;
+package hpacucli;
use base 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
sub program_names {
- __PACKAGE__;
+ qw(hpacucli hpssacli);
}
sub commands {
@@ -4132,14 +4199,11 @@ sub sudo {
);
}
-sub check {
+sub scan_targets {
my $this = shift;
- # status messages pushed here
- my @status;
-
# TODO: allow target customize:
- # hpssacli <target> is of format:
+ # hpacucli <target> is of format:
# [controller all|slot=#|wwn=#|chassisname="AAA"|serialnumber=#|chassisserialnumber=#|ctrlpath=#:# ]
# [array all|<id>]
# [physicaldrive all|allunassigned|[#:]#:#|[#:]#:#-[#:]#:#]
@@ -4153,6 +4217,7 @@ sub check {
while (<$fh>) {
# Numeric slot
if (my($model, $slot) = /^(\S.+) in Slot (.+)/) {
+ $slot =~ s/ \(RAID Mode\)//;
$slot =~ s/ \(Embedded\)//;
$targets{"slot=$slot"} = $model;
$this->unknown if $slot !~ /^\d+$/;
@@ -4166,16 +4231,16 @@ sub check {
}
close $fh;
- unless (%targets) {
- $this->warning;
- $this->message("No Controllers were found on this machine");
- return;
- }
+ return \%targets;
+}
- # Scan logical drives
- for my $target (sort {$a cmp $b} keys %targets) {
- my $model = $targets{$target};
- # check each controllers
+# Scan logical drives
+sub scan_luns {
+ my ($this, $targets) = @_;
+
+ my %luns;
+ while (my($target, $model) = each %$targets) {
+ # check each controller
my $fh = $this->cmd('logicaldrive status', { '$target' => $target });
my ($array, %array);
@@ -4208,141 +4273,47 @@ sub check {
}
$this->unknown unless close $fh;
- my @cstatus;
- while (my($array, $d) = each %array) {
- my ($astatus, $ld) = @$d;
-
- my @astatus;
- # extra details for non-normal arrays
- foreach my $lun (sort { $a cmp $b } keys %$ld) {
- my $s = $ld->{$lun};
- push(@astatus, "LUN$lun:$s");
-
- if ($s eq 'OK' or $s eq 'Disabled') {
- } elsif ($s eq 'Failed' or $s eq 'Interim Recovery Mode') {
- $this->critical;
- } elsif ($s eq 'Rebuild' or $s eq 'Recover') {
- $this->warning;
- }
- }
- push(@cstatus, "Array $array($astatus)[". join(',', @astatus). "]");
- }
- push(@status, "$model: ".join(', ', @cstatus));
+ $luns{$target} = { %array };
}
- return unless @status;
-
- $this->ok->message(join(', ', @status));
+ return \%luns;
}
-package hpacucli;
-use base 'plugin';
-
-# register
-push(@utils::plugins, __PACKAGE__);
-
-sub program_names {
- __PACKAGE__;
-}
+# parse hpacucli output into logical structure
+sub parse {
+ my $this = shift;
-sub commands {
- {
- 'controller status' => ['-|', '@CMD', 'controller', 'all', 'show', 'status'],
- 'logicaldrive status' => ['-|', '@CMD', 'controller', '$target', 'logicaldrive', 'all', 'show'],
+ my $targets = $this->scan_targets;
+ if (!$targets) {
+ return $targets;
}
-}
-
-sub sudo {
- my ($this, $deep) = @_;
- # quick check when running check
- return 1 unless $deep;
-
- my $cmd = $this->{program};
- (
- "CHECK_RAID ALL=(root) NOPASSWD: $cmd controller all show status",
- "CHECK_RAID ALL=(root) NOPASSWD: $cmd controller * logicaldrive all show",
- );
+ my $luns = $this->scan_luns($targets);
+ return { 'targets' => $targets, 'luns' => $luns };
}
sub check {
my $this = shift;
- # status messages pushed here
- my @status;
-
- # TODO: allow target customize:
- # hpacucli <target> is of format:
- # [controller all|slot=#|wwn=#|chassisname="AAA"|serialnumber=#|chassisserialnumber=#|ctrlpath=#:# ]
- # [array all|<id>]
- # [physicaldrive all|allunassigned|[#:]#:#|[#:]#:#-[#:]#:#]
- # [logicaldrive all|#]
- # [enclosure all|#:#|serialnumber=#|chassisname=#]
- # [licensekey all|<key>]
-
- # Scan controllers
- my (%targets);
- my $fh = $this->cmd('controller status');
- while (<$fh>) {
- # Numeric slot
- if (my($model, $slot) = /^(\S.+) in Slot (.+)/) {
- $slot =~ s/ \(Embedded\)//;
- $targets{"slot=$slot"} = $model;
- $this->unknown if $slot !~ /^\d+$/;
- next;
- }
- # Named Entry
- if (my($model, $cn) = /^(\S.+) in (.+)/) {
- $targets{"chassisname=$cn"} = $cn;
- next;
- }
- }
- close $fh;
-
- unless (%targets) {
- $this->warning;
- $this->message("No Controllers were found on this machine");
+ my $ctrl = $this->parse;
+ unless ($ctrl) {
+ $this->warning->message("No Controllers were found on this machine");
return;
}
- # Scan logical drives
- for my $target (sort {$a cmp $b} keys %targets) {
- my $model = $targets{$target};
- # check each controllers
- my $fh = $this->cmd('logicaldrive status', { '$target' => $target });
-
- my ($array, %array);
- while (<$fh>) {
- # "array A"
- # "array A (Failed)"
- # "array B (Failed)"
- if (my($a, $s) = /^\s+array (\S+)(?:\s*\((\S+)\))?$/) {
- $array = $a;
- # Offset 0 is Array own status
- # XXX: I don't like this one: undef could be false positive
- $array{$array}[0] = $s || 'OK';
- }
+ # status messages pushed here
+ my @status;
- # skip if no active array yet
- next unless $array;
+ for my $target (sort {$a cmp $b} keys %{$ctrl->{targets}}) {
+ my $model = $ctrl->{targets}->{$target};
- # logicaldrive 1 (68.3 GB, RAID 1, OK)
- # capture only status
- if (my($drive, $s) = /^\s+logicaldrive (\d+) \([\d.]+ .B, [^,]+, ([^\)]+)\)$/) {
- # Offset 1 is each logical drive status
- $array{$array}[1]{$drive} = $s;
- next;
- }
+ my @cstatus;
+ foreach my $array (sort { $a cmp $b } keys %{$ctrl->{luns}->{$target}}) {
+ my ($astatus, $ld) = @{$ctrl->{luns}->{$target}{$array}};
- # Error: The controller identified by "slot=attr_value_slot_unknown" was not detected.
- if (/Error:/) {
- $this->unknown;
+ # check array status
+ if ($astatus ne 'OK') {
+ $this->critical;
}
- }
- $this->unknown unless close $fh;
-
- my @cstatus;
- while (my($array, $d) = each %array) {
- my ($astatus, $ld) = @$d;
my @astatus;
# extra details for non-normal arrays
@@ -4359,6 +4330,7 @@ sub check {
}
push(@cstatus, "Array $array($astatus)[". join(',', @astatus). "]");
}
+
push(@status, "$model: ".join(', ', @cstatus));
}
@@ -4629,7 +4601,7 @@ use Getopt::Long;
my ($opt_V, $opt_d, $opt_h, $opt_W, $opt_S, $opt_p, $opt_l);
my (%ERRORS) = (OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => 3);
-my ($VERSION) = "3.2.3";
+my ($VERSION) = "3.2.4";
my ($message, $status, $perfdata, $longoutput);
my ($noraid_state) = $ERRORS{UNKNOWN};
@@ -4868,6 +4840,36 @@ sub setstate {
$$key = $ERRORS{$value};
}
+# obtain git hash of check_raid.pl
+# http://stackoverflow.com/questions/460297/git-finding-the-sha1-of-an-individual-file-in-the-index#comment26055597_460315
+sub git_hash_object() {
+ my $content = "blob ";
+ $content .= -s $0;
+ $content .= "\0";
+ open my $fh, '<', $0 or die $!;
+ local $/ = undef;
+ $content .= <$fh>;
+ close($fh) or die $!;
+
+ # try Digest::SHA1
+ my $digest;
+ eval {
+ require Digest::SHA1;
+ $digest = Digest::SHA1::sha1_hex($content);
+ };
+
+ return $digest;
+}
+
+# plugin options (key=>value pairs) passed as 'options' key to each plugin constructor.
+# the options are global, not plugin specific, but it's recommended to prefix option with plugin name.
+# the convention is to have PLUGIN_NAME-OPTION_NAME=OPTION_VALUE syntax to namespace each plugin option.
+#
+# so "--plugin-option=hp_msa-serial=/dev/ttyS2" would define option 'serial'
+# for 'hp_msa' plugin with value '/dev/ttyS2'.
+#
+my %plugin_options;
+
Getopt::Long::Configure('bundling');
GetOptions(
'V' => \$opt_V, 'version' => \$opt_V,
@@ -4880,6 +4882,7 @@ GetOptions(
'noraid=s' => sub { setstate(\$noraid_state, @_); },
'bbulearn=s' => sub { setstate(\$plugin::bbulearn_status, @_); },
'cache-fail=s' => sub { setstate(\$plugin::cache_fail_status, @_); },
+ 'plugin-option=s' => sub { my($k, $v) = split(/=/, $_[1], 2); $plugin_options{$k} = $v; },
'bbu-monitoring' => \$plugin::bbu_monitoring,
'p=s' => \$opt_p, 'plugin=s' => \$opt_p,
'l' => \$opt_l, 'list-plugins' => \$opt_l,
@@ -4896,6 +4899,21 @@ if ($opt_V) {
print "check_raid Version $VERSION\n";
exit $ERRORS{'OK'};
}
+
+if ($opt_d) {
+ print "check_raid Version $VERSION\n";
+ my $git_ver = `git describe --tags 2>/dev/null`;
+ if ($git_ver) {
+ print "Using git: $git_ver";
+ }
+ my $hash = git_hash_object();
+ if ($hash) {
+ print "git hash object: $hash\n";
+ }
+ print "See CONTRIBUTING.md how to report bugs with debug data:\n";
+ print "https://github.com/glensc/nagios-plugin-check_raid/blob/master/CONTRIBUTING.md\n\n";
+}
+
if ($opt_h) {
print_help();
exit $ERRORS{'OK'};
@@ -4917,7 +4935,7 @@ $utils::debug = $opt_d;
my @plugins = $opt_p ? grep { my $p = $_; grep { /^$p$/ } split(/,/, $opt_p) } @utils::plugins : @utils::plugins;
foreach my $pn (@plugins) {
- my $plugin = $pn->new;
+ my $plugin = $pn->new(options => \%plugin_options);
# skip inactive plugins (disabled or no tools available)
next unless $plugin->active;
diff --git a/check_raid/control b/check_raid/control
index 58a99c0..dec93d3 100644
--- a/check_raid/control
+++ b/check_raid/control
@@ -1,7 +1,7 @@
Homepage: https://github.com/glensc/nagios-plugin-check_raid
Watch: https://github.com/glensc/nagios-plugin-check_raid "/glensc/nagios-plugin-check_raid/tree/([0-9.]+)"
Suggests: cciss-vol-status (>= 1.10), mpt-status
-Version: 3.2.3
+Version: 3.2.4
Uploaders: Bernd Zeimetz <bzed at debian.org>
Description: plugin to check sw/hw RAID status
The plugin looks for any known types of RAID configurations,
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-nagios/pkg-nagios-plugins-contrib.git
More information about the Pkg-nagios-changes
mailing list