[Pkg-nagios-changes] [pkg-nagios-plugins-contrib] 01/03: check_raid: Update to latest version 3.2.5
Jan Wagner
waja at moszumanska.debian.org
Sun Oct 11 13:37:29 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 22ddfa6f0f1bb52570da8097d19094d706f128b5
Author: Jan Wagner <waja at cyconet.org>
Date: Sun Oct 11 15:22:56 2015 +0200
check_raid: Update to latest version 3.2.5
---
check_raid/check_raid | 833 +++++++++++++++++++++++++++++++-------------------
check_raid/control | 3 +-
2 files changed, 521 insertions(+), 315 deletions(-)
diff --git a/check_raid/check_raid b/check_raid/check_raid
index cd1c6e7..e315050 100644
--- a/check_raid/check_raid
+++ b/check_raid/check_raid
@@ -56,8 +56,10 @@ use strict;
{
package utils;
-my @EXPORT = qw(which find_sudo);
-my @EXPORT_OK = @EXPORT;
+use Exporter 'import';
+
+our @EXPORT = qw(which find_sudo);
+our @EXPORT_OK = @EXPORT;
# registered plugins
our @plugins;
@@ -85,7 +87,7 @@ sub which {
}
our @sudo;
-sub find_sudo() {
+sub find_sudo {
# no sudo needed if already root
return [] unless $>;
@@ -111,29 +113,205 @@ sub find_sudo() {
} # package utils
{
+package sudoers;
+
+use Exporter 'import';
+
+utils->import;
+
+our @EXPORT = qw(sudoers);
+our @EXPORT_OK = @EXPORT;
+
+# update sudoers file
+#
+# if sudoers config has "#includedir" directive, add file to that dir
+# otherwise update main sudoers file
+sub sudoers {
+ my ($dry_run) = @_;
+
+ # build values to be added
+ # go over all registered plugins
+ my @sudo;
+ foreach my $pn (@utils::plugins) {
+ my $plugin = $pn->new;
+
+ # skip inactive plugins (disabled or no tools available)
+ next unless $plugin->active;
+
+ # collect sudo rules
+ my @rules = $plugin->sudo(1) or next;
+
+ push(@sudo, @rules);
+ }
+
+ unless (@sudo) {
+ warn "Your configuration does not need to use sudo, sudoers not updated\n";
+ return;
+ }
+
+ my @rules = join "\n", (
+ "",
+ # setup alias, so we could easily remove these later by matching lines with 'CHECK_RAID'
+ # also this avoids installing ourselves twice.
+ "# Lines matching CHECK_RAID added by $0 -S on ". scalar localtime,
+ "User_Alias CHECK_RAID=nagios",
+ "Defaults:CHECK_RAID !requiretty",
+
+ # actual rules from plugins
+ join("\n", @sudo),
+ "",
+ );
+
+ if ($dry_run) {
+ warn "Content to be inserted to sudo rules:\n";
+ warn "--- sudoers ---\n";
+ print @rules;
+ warn "--- sudoers ---\n";
+ return;
+ }
+
+ my $sudoers = find_file('/usr/local/etc/sudoers', '/etc/sudoers');
+ my $visudo = which('visudo');
+
+ die "Unable to find sudoers file.\n" unless -f $sudoers;
+ die "Unable to write to sudoers file '$sudoers'.\n" unless -w $sudoers;
+ die "visudo program not found\n" unless -x $visudo;
+
+ # parse sudoers file for "#includedir" directive
+ my $sudodir = parse_sudoers_includedir($sudoers);
+ if ($sudodir) {
+ # sudo will read each file in /etc/sudoers.d, skipping file names that
+ # end in ~ or contain a . character to avoid causing problems with
+ # package manager or editor temporary/backup files
+ $sudoers = "$sudodir/check_raid";
+ }
+
+ warn "Updating file $sudoers\n";
+
+ # NOTE: secure as visudo itself: /etc is root owned
+ my $new = $sudoers.".new.".$$;
+
+ # setup to have sane perm for new sudoers file
+ umask(0227);
+
+ open my $fh, '>', $new or die $!;
+
+ # insert old sudoers
+ if (!$sudodir) {
+ open my $old, '<', $sudoers or die $!;
+ while (<$old>) {
+ print $fh $_;
+ }
+ close $old or die $!;
+ }
+
+ # insert the rules
+ print $fh @rules;
+ close $fh;
+
+ # validate sudoers
+ system($visudo, '-c', '-f', $new) == 0 or unlink($new),exit $? >> 8;
+
+ # check if they differ
+ if (filediff($sudoers, $new)) {
+ # use the new file
+ rename($new, $sudoers) or die $!;
+ warn "$sudoers file updated.\n";
+ } else {
+ warn "$sudoers file not changed.\n";
+ unlink($new);
+ }
+}
+
+# return first "#includedir" directive from $sudoers file
+sub parse_sudoers_includedir {
+ my ($sudoers) = @_;
+
+ open my $fh, '<', $sudoers or die "Can't open: $sudoers: $!";
+ while (<$fh>) {
+ if (my ($dir) = /^#includedir\s+(.+)$/) {
+ return $dir;
+ }
+ }
+ close $fh or die $!;
+
+ return undef;
+}
+
+# return FALSE if files are identical
+# return TRUE if files are different
+# return TRUE if any of the files is missing
+sub filediff {
+ my ($file1, $file2) = @_;
+
+ # return TRUE if neither of them exist
+ return 1 unless -f $file1;
+ return 1 unless -f $file2;
+
+ my $f1 = cat($file1);
+ my $f2 = cat($file2);
+
+ # wipe comments
+ $f1 =~ s/^#.+$//m;
+ $f2 =~ s/^#.+$//m;
+
+ # return TRUE if they differ
+ return $f1 ne $f2;
+}
+
+# get contents of a file
+sub cat {
+ my ($file) = @_;
+ open(my $fh, '<', $file) or die "Can't open $file: $!";
+ local $/ = undef;
+ local $_ = <$fh>;
+ close($fh) or die $!;
+
+ return $_;
+}
+
+# find first existing file from list of file paths
+sub find_file {
+ for my $file (@_) {
+ return $file if -f $file;
+ }
+ return undef;
+}
+
+} # package sudoers
+
+{
package plugin;
use Carp qw(croak);
+utils->import;
+
# Nagios standard error codes
my (%ERRORS) = (OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => 3);
-# status to set when RAID is in resync state
-our $resync_status = $ERRORS{WARNING};
+# default plugin options
+our %options = (
+ # status to set when RAID is in resync state
+ resync_status => $ERRORS{WARNING},
-# status to set when RAID is in check state
-our $check_status = $ERRORS{OK};
+ # Status code to use when no raid was detected
+ noraid_state => $ERRORS{UNKNOWN},
-# status to set when PD is spare
-our $spare_status = $ERRORS{OK};
+ # status to set when RAID is in check state
+ check_status => $ERRORS{OK},
-# status to set when BBU is in learning cycle.
-our $bbulearn_status = $ERRORS{WARNING};
+ # status to set when PD is spare
+ spare_status => $ERRORS{OK},
-# status to set when Write Cache has failed.
-our $cache_fail_status = $ERRORS{WARNING};
+ # status to set when BBU is in learning cycle.
+ bbulearn_status => $ERRORS{WARNING},
-# check status of BBU
-our $bbu_monitoring = 0;
+ # status to set when Write Cache has failed.
+ cache_fail_status => $ERRORS{WARNING},
+
+ # check status of BBU
+ bbu_monitoring => 0,
+);
# return list of programs this plugin needs
# @internal
@@ -159,11 +337,19 @@ sub new {
croak 'Odd number of elements in argument hash' if @_ % 2;
+ # convert to hash
+ my %args = @_;
+
+ # merge 'options' from param and class defaults
+ %options = (%options, %{$args{options}}) if $args{options};
+ delete $args{options};
+
my $self = {
program_names => [ $class->program_names ],
commands => $class->commands,
- sudo => $class->sudo ? utils::find_sudo() : '',
- @_,
+ sudo => $class->sudo ? find_sudo() : '',
+ options => \%options,
+ %args,
name => $class,
status => undef,
message => undef,
@@ -173,7 +359,7 @@ sub new {
# lookup program, if not defined by params
if (!$self->{program}) {
- $self->{program} = utils::which(@{$self->{program_names}});
+ $self->{program} = which(@{$self->{program_names}});
}
return bless $self, $class;
@@ -241,7 +427,7 @@ sub ok {
# returns $this to allow fluent api
sub resync {
my ($this) = @_;
- $this->status($resync_status);
+ $this->status($this->{options}{resync_status});
return $this;
}
@@ -249,7 +435,7 @@ sub resync {
# returns $this to allow fluent api
sub check_status {
my ($this) = @_;
- $this->status($check_status);
+ $this->status($this->{options}{check_status});
return $this;
}
@@ -257,7 +443,7 @@ sub check_status {
# returns $this to allow fluent api
sub spare {
my ($this) = @_;
- $this->status($spare_status);
+ $this->status($this->{options}{spare_status});
return $this;
}
@@ -265,7 +451,7 @@ sub spare {
# returns $this to allow fluent api
sub bbulearn {
my ($this) = @_;
- $this->status($bbulearn_status);
+ $this->status($this->{options}{bbulearn_status});
return $this;
}
@@ -273,7 +459,7 @@ sub bbulearn {
# returns $this to allow fluent api
sub cache_fail {
my ($this) = @_;
- $this->status($cache_fail_status);
+ $this->status($this->{options}{cache_fail_status});
return $this;
}
@@ -282,9 +468,9 @@ sub bbu_monitoring {
my ($this, $val) = @_;
if (defined $val) {
- $bbu_monitoring = $val;
+ $this->{options}{bbu_monitoring} = $val;
}
- $bbu_monitoring;
+ $this->{options}{bbu_monitoring};
}
# setup status message text
@@ -342,7 +528,7 @@ sub join_status {
}
# return true if parameter is not in ignore list
-sub valid($) {
+sub valid {
my $this = shift;
my ($v) = lc $_[0];
@@ -357,7 +543,7 @@ use constant M => K * 1024;
use constant G => M * 1024;
use constant T => G * 1024;
-sub format_bytes($) {
+sub format_bytes {
my $this = shift;
my ($bytes) = @_;
@@ -401,6 +587,7 @@ sub nosudo_cmd {
# if command fails, program is exited (caller needs not to worry)
sub cmd {
my ($this, $command, $cb) = @_;
+ my $debug = $utils::debug;
# build up command
my @CMD = $this->{program};
@@ -447,23 +634,23 @@ sub cmd {
if ($op eq '=' and ref $cb eq 'SCALAR') {
# Special: use open2
use IPC::Open2;
- warn "DEBUG EXEC: $op @cmd" if $utils::debug;
+ warn "DEBUG EXEC: $op @cmd" if $debug;
my $pid = open2($fh, $$cb, @cmd) or croak "open2 failed: @cmd: $!";
} elsif ($op eq '>&2') {
# Special: same as '|-' but reads both STDERR and STDOUT
use IPC::Open3;
- warn "DEBUG EXEC: $op @cmd" if $utils::debug;
+ warn "DEBUG EXEC: $op @cmd" if $debug;
my $pid = open3(undef, $fh, $cb, @cmd);
} else {
- warn "DEBUG EXEC: @cmd" if $utils::debug;
+ warn "DEBUG EXEC: @cmd" if $debug;
open($fh, $op, @cmd) or croak "open failed: @cmd: $!";
}
# for dir handles, reopen as opendir
if (-d $fh) {
undef($fh);
- warn "DEBUG OPENDIR: $cmd[0]" if $utils::debug;
+ warn "DEBUG OPENDIR: $cmd[0]" if $debug;
opendir($fh, $cmd[0]) or croak "opendir failed: @cmd: $!";
}
@@ -473,7 +660,7 @@ sub cmd {
} # package plugin
package lsscsi;
-use base 'plugin';
+use parent -norequire, 'plugin';
push(@utils::plugins, __PACKAGE__);
@@ -555,7 +742,7 @@ sub scan {
package metastat;
# Solaris, software RAID
-use base 'plugin';
+use parent -norequire, 'plugin';
push(@utils::plugins, __PACKAGE__);
@@ -578,7 +765,7 @@ sub sudo {
"CHECK_RAID ALL=(root) NOPASSWD: $cmd"
}
-sub active($) {
+sub active {
my ($this) = @_;
# program not found
@@ -648,14 +835,15 @@ sub check {
package megaide;
# MegaIDE RAID controller
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
# Status: BROKEN: no test data
#push(@utils::plugins, __PACKAGE__);
sub sudo {
- my $cat = utils::which('cat');
+ my ($this) = @_;
+ my $cat = $this->which('cat');
"CHECK_RAID ALL=(root) NOPASSWD: $cat /proc/megaide/0/status";
}
@@ -698,7 +886,7 @@ sub check {
package mdstat;
# Linux Multi-Device (md)
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -709,7 +897,7 @@ sub commands {
}
}
-sub active ($) {
+sub active {
my ($this) = @_;
# easy way out. no /proc/mdstat
return 0 unless -e $this->{commands}{mdstat}[1];
@@ -908,7 +1096,7 @@ sub check {
package lsraid;
# Linux, software RAID
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
# Broken: missing test data
@@ -968,7 +1156,7 @@ package megacli;
# TODO: process drive temperatures
# TODO: check error counts
# TODO: hostspare information
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -1348,7 +1536,7 @@ sub check {
package lsvg;
# AIX LVM
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
# Status: broken (no test data)
@@ -1422,7 +1610,7 @@ package ips;
# Serveraid IPS
# Tested on IBM xSeries 346 servers with Adaptec ServeRAID 7k controllers.
# The ipssend version was v7.12.14.
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -1481,7 +1669,7 @@ sub check {
package aaccli;
# Adaptec ServeRAID
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -1559,7 +1747,7 @@ sub check {
package afacli;
# Adaptec AACRAID
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -1613,7 +1801,7 @@ sub check {
}
package mpt;
-use base 'plugin';
+use parent -norequire, 'plugin';
# LSILogic MPT ServeRAID
@@ -1646,7 +1834,7 @@ sub sudo {
);
}
-sub active ($) {
+sub active {
my ($this) = @_;
# return if parent said NO
@@ -1828,14 +2016,15 @@ sub check {
package megaraid;
# MegaRAID
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
# Status: BROKEN: no test data
#push(@utils::plugins, __PACKAGE__);
sub sudo {
- my $cat = utils::which('cat');
+ my ($this) = @_;
+ my $cat = $this->which('cat');
my @sudo;
foreach my $mr (</proc/mega*/*/raiddrives*>) {
@@ -1881,7 +2070,7 @@ sub check {
package gdth;
# Linux gdth RAID
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -1893,7 +2082,7 @@ sub commands {
}
}
-sub active ($) {
+sub active {
my ($this) = @_;
return -d $this->{commands}{proc}[1];
}
@@ -2109,7 +2298,7 @@ sub check {
}
package dpt_i2o;
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -2121,7 +2310,7 @@ sub commands {
}
}
-sub active ($) {
+sub active {
my ($this) = @_;
return -d $this->{commands}{proc}[1];
}
@@ -2164,7 +2353,7 @@ package tw_cli;
# Owned by LSI currently: https://en.wikipedia.org/wiki/3ware
#
# http://www.cyberciti.biz/files/tw_cli.8.html
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -2422,7 +2611,7 @@ sub check {
push(@status, "Drives($c->{drives}): ".$this->join_status(\%ds)) if %ds;
# check BBU
- if ($c->{bbu} && $c->{bbu} ne '-') {
+ if ($this->bbu_monitoring && $c->{bbu} && $c->{bbu} ne '-') {
$this->critical if $c->{bbu} ne 'OK';
push(@status, "BBU: $c->{bbu}");
}
@@ -2438,7 +2627,7 @@ package arcconf;
# check designed from check-aacraid.py, Anchor System - <http://www.anchor.com.au>
# Oliver Hookins, Paul De Audney, Barney Desmond.
# Perl port (check_raid) by Elan Ruusamäe.
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -2450,7 +2639,8 @@ sub program_names {
sub commands {
{
'getstatus' => ['-|', '@CMD', 'GETSTATUS', '1'],
- 'getconfig' => ['-|', '@CMD', 'GETCONFIG', '1', 'AL'],
+ # 'nologs' does not exist in arcconf 6.50. #118
+ 'getconfig' => ['-|', '@CMD', 'GETCONFIG', '$ctrl', 'AL'],
}
}
@@ -2462,7 +2652,7 @@ sub sudo {
my $cmd = $this->{program};
(
"CHECK_RAID ALL=(root) NOPASSWD: $cmd GETSTATUS 1",
- "CHECK_RAID ALL=(root) NOPASSWD: $cmd GETCONFIG 1 AL",
+ "CHECK_RAID ALL=(root) NOPASSWD: $cmd GETCONFIG * AL",
);
}
@@ -2532,12 +2722,6 @@ sub parse_status {
# Tasks seem to be Controller specific, but as we don't support over one controller, let it be global
$s{tasks} = { %task } if %task;
- if ($count > 1) {
- # don't know how to handle this, so better just fail
- $this->unknown->message("More than one Controller found, this is not yet supported due lack of input data.");
- return undef;
- }
-
if ($count == 0) {
# if command completed, but no controllers,
# assume no hardware present
@@ -2547,21 +2731,31 @@ sub parse_status {
return undef;
}
- $s{controllers} = $count;
+ $s{ctrl_count} = $count;
return \%s;
}
-# parse GETCONFIG command
-# parses
-# - ...
+# parse GETCONFIG for all controllers
sub parse_config {
my ($this, $status) = @_;
+ my %c;
+ for (my $i = 1; $i <= $status->{ctrl_count}; $i++) {
+ $c{$i} = $this->parse_ctrl_config($i, $status->{ctrl_count});
+ }
+
+ return { controllers => \%c };
+}
+
+# parse GETCONFIG command for specific controller
+sub parse_ctrl_config {
+ my ($this, $ctrl, $ctrl_count) = @_;
+
# Controller information, Logical/Physical device info
my (%c, @ld, $ld, @pd, $ch, $pd);
- my $fh = $this->cmd('getconfig');
+ my $fh = $this->cmd('getconfig', { '$ctrl' => $ctrl });
my ($section, $subsection, $ok);
while (<$fh>) {
chomp;
@@ -2576,7 +2770,7 @@ sub parse_config {
}
if (my($c) = /^Controllers found: (\d+)/) {
- if ($c != $status->{controllers}) {
+ if ($c != $ctrl_count) {
# internal error?!
$this->unknown->message("Controller count mismatch");
}
@@ -2758,7 +2952,7 @@ sub parse_config {
# not parsed yet
} elsif (/Expander SAS Address\s+:/) {
# not parsed yet
- } elsif (/MaxCache (Capable|Assigned)\s+:\s+(.+)/) {
+ } elsif (/[Mm]axCache (Capable|Assigned)\s+:\s+(.+)/) {
# not parsed yet
} elsif (/Power supply \d+ status/) {
# not parsed yet
@@ -2815,6 +3009,7 @@ sub parse {
my ($this) = @_;
# we chdir to /var/log, as tool is creating 'UcliEvt.log'
+ # this can be disabled with 'nologs' parameter, but not sure do all versions support it
chdir('/var/log') || chdir('/');
my ($status, $config);
@@ -2824,71 +3019,66 @@ sub parse {
return { %$status, %$config };
}
-sub check {
- my $this = shift;
-
- my $data = $this->parse;
- $this->unknown,return unless $data;
+# check for controller status
+sub check_controller {
+ my ($this, $c) = @_;
- # status messages pushed here
my @status;
- # check for controller status
- for my $c ($data->{controller}) {
- $this->critical if $c->{status} !~ /Optimal|Okay/;
- push(@status, "Controller:$c->{status}");
+ $this->critical if $c->{status} !~ /Optimal|Okay/;
+ push(@status, "Controller:$c->{status}");
- if ($c->{defunct_count} > 0) {
- $this->critical;
- push(@status, "Defunct drives:$c->{defunct_count}");
- }
-
- if (defined $c->{logical_failed} && $c->{logical_failed} > 0) {
- $this->critical;
- push(@status, "Failed drives:$c->{logical_failed}");
- }
+ if ($c->{defunct_count} > 0) {
+ $this->critical;
+ push(@status, "Defunct drives:$c->{defunct_count}");
+ }
- if (defined $c->{logical_degraded} && $c->{logical_degraded} > 0) {
- $this->critical;
- push(@status, "Degraded drives:$c->{logical_degraded}");
- }
+ if (defined $c->{logical_failed} && $c->{logical_failed} > 0) {
+ $this->critical;
+ push(@status, "Failed drives:$c->{logical_failed}");
+ }
- if (defined $c->{logical_offline} && $c->{logical_offline} > 0) {
- $this->critical;
- push(@status, "Offline drives:$c->{logical_offline}");
- }
+ if (defined $c->{logical_degraded} && $c->{logical_degraded} > 0) {
+ $this->critical;
+ push(@status, "Degraded drives:$c->{logical_degraded}");
+ }
- if (defined $c->{logical_critical} && $c->{logical_critical} > 0) {
- $this->critical;
- push(@status, "Critical drives:$c->{logical_critical}");
- }
+ if (defined $c->{logical_offline} && $c->{logical_offline} > 0) {
+ $this->critical;
+ push(@status, "Offline drives:$c->{logical_offline}");
+ }
- if (defined $c->{logical_degraded} && $c->{logical_degraded} > 0) {
- $this->critical;
- push(@status, "Degraded drives:$c->{logical_degraded}");
- }
+ if (defined $c->{logical_critical} && $c->{logical_critical} > 0) {
+ $this->critical;
+ push(@status, "Critical drives:$c->{logical_critical}");
+ }
- # current (logical device) tasks
- if ($data->{tasks}->{operation} ne 'None') {
- # just print it. no status change
- my $task = $data->{tasks};
- push(@status, "$task->{type} #$task->{device}: $task->{operation}: $task->{status} $task->{percent}%");
- }
+ if (defined $c->{logical_degraded} && $c->{logical_degraded} > 0) {
+ $this->critical;
+ push(@status, "Degraded drives:$c->{logical_degraded}");
+ }
- # ZMM (Zero-Maintenance Module) status
- if (defined($c->{zmm_status})) {
- push(@status, "ZMM Status: $c->{zmm_status}");
- }
+ # ZMM (Zero-Maintenance Module) status
+ if (defined($c->{zmm_status})) {
+ push(@status, "ZMM Status: $c->{zmm_status}");
+ }
- # Battery status
+ # Battery status
+ if ($this->bbu_monitoring) {
my @s = $this->battery_status($c);
push(@status, @s) if @s;
}
- # check for physical devices
+ return @status;
+}
+
+# check for physical devices
+sub check_physical {
+ my ($this, $p) = @_;
+
my %pd;
- my $pd_resync = 0;
- for my $ch (@{$data->{physical}}) {
+ $this->{pd_resync} = 0;
+ for my $ch (@$p) {
for my $pd (@{$ch}) {
# skip not disks
next if not defined $pd;
@@ -2896,7 +3086,7 @@ sub check {
if ($pd->{status} eq 'Rebuilding') {
$this->resync;
- $pd_resync++;
+ $this->{pd_resync}++;
} elsif ($pd->{status} eq 'Dedicated Hot-Spare') {
$this->spare;
@@ -2911,11 +3101,18 @@ sub check {
}
}
- # check for logical devices
- for my $ld (@{$data->{logical}}) {
+ return \%pd;
+}
+
+# check for logical devices
+sub check_logical {
+ my ($this, $l) = @_;
+
+ my @status;
+ for my $ld (@$l) {
next unless $ld; # FIXME: fix that script assumes controllers start from '0'
- if ($ld->{status} eq 'Degraded' && $pd_resync) {
+ if ($ld->{status} eq 'Degraded' && $this->{pd_resync}) {
$this->warning;
} elsif ($ld->{status} !~ /Optimal|Okay/) {
$this->critical;
@@ -2935,7 +3132,37 @@ sub check {
}
}
- push(@status, "Drives: ".$this->join_status(\%pd)) if %pd;
+ return @status;
+}
+
+sub check {
+ my $this = shift;
+
+ my $data = $this->parse;
+ $this->unknown,return unless $data;
+
+ my @status;
+
+ for my $i (sort {$a cmp $b} keys %{$data->{controllers}}) {
+ my $c = $data->{controllers}->{$i};
+
+ push(@status, $this->check_controller($c->{controller}));
+
+ # current (logical device) tasks
+ if ($data->{tasks}->{operation} ne 'None') {
+ # just print it. no status change
+ my $task = $data->{tasks};
+ push(@status, "$task->{type} #$task->{device}: $task->{operation}: $task->{status} $task->{percent}%");
+ }
+
+ # check physical first, as it setups pd_resync flag
+ my $pd = $this->check_physical($c->{physical});
+
+ push(@status, $this->check_logical($c->{logical}));
+
+ # but report after logical devices
+ push(@status, "Drives: ".$this->join_status($pd)) if $pd;
+ }
$this->ok->message(join(', ', @status));
}
@@ -2997,7 +3224,7 @@ package megarc;
# check designed from check_lsi_megaraid:
# http://www.monitoringexchange.org/cgi-bin/page.cgi?g=Detailed/2416.html;d=1
# Perl port (check_raid) by Elan Ruusamäe.
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -3101,7 +3328,7 @@ sub check {
}
package cmdtool2;
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -3180,7 +3407,7 @@ sub check {
}
package cciss;
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -3686,7 +3913,7 @@ sub check {
}
package hp_msa;
-use base 'plugin';
+use parent -norequire, 'plugin';
# do not register, better use hpacucli
push(@utils::plugins, __PACKAGE__);
@@ -3829,7 +4056,7 @@ package sas2ircu;
# LSI SAS-2 controllers using the SAS-2 Integrated RAID Configuration Utility (SAS2IRCU)
# Based on the SAS-2 Integrated RAID Configuration Utility (SAS2IRCU) User Guide
# http://www.lsi.com/downloads/Public/Host%20Bus%20Adapters/Host%20Bus%20Adapters%20Common%20Files/SAS_SATA_6G_P12/SAS2IRCU_User_Guide.pdf
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -4096,7 +4323,7 @@ sub check {
}
package smartctl;
-use base 'plugin';
+use parent -norequire, 'plugin';
# no registering as standalone plugin
#push(@utils::plugins, __PACKAGE__);
@@ -4171,13 +4398,13 @@ sub check {
}
package hpacucli;
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
sub program_names {
- qw(hpacucli hpssacli);
+ qw(hpacucli);
}
sub commands {
@@ -4339,12 +4566,23 @@ sub check {
$this->ok->message(join(', ', @status));
}
+package hpssacli;
+# extend hpacucli,
+# with the only difference that different program name is used
+use parent -norequire, 'hpacucli';
+
+push(@utils::plugins, __PACKAGE__);
+
+sub program_names {
+ qw(hpssacli);
+}
+
package areca;
## Areca SATA RAID Support
## requires cli64 or cli32 binaries
## For links to manuals and binaries, see this issue:
## https://github.com/glensc/nagios-plugin-check_raid/issues/10
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -4488,7 +4726,7 @@ sub check {
}
package dmraid;
-use base 'plugin';
+use parent -norequire, 'plugin';
# register
push(@utils::plugins, __PACKAGE__);
@@ -4503,7 +4741,7 @@ sub commands {
}
}
-sub active ($) {
+sub active {
my ($this) = @_;
# easy way out. no executable
@@ -4589,6 +4827,134 @@ sub check {
$this->ok->message(join(' ', @status));
}
+package mvcli;
+use parent -norequire, 'plugin';
+
+#push(@utils::plugins, __PACKAGE__);
+
+sub program_names {
+ qw(mvcli);
+}
+
+sub commands {
+ {
+ 'mvcli blk' => ['-|', '@CMD'],
+ 'mvcli smart' => ['-|', '@CMD'],
+ }
+}
+
+sub sudo {
+ my ($this, $deep) = @_;
+ # quick check when running check
+ return 1 unless $deep;
+
+ my $cmd = $this->{program};
+ "CHECK_RAID ALL=(root) NOPASSWD: $cmd"
+}
+
+sub parse_blk {
+ my $this = shift;
+
+ my (@blk, %blk);
+
+ my $fh = $this->cmd('mvcli blk');
+ while (<$fh>) {
+ chomp;
+
+ if (my ($blk_id) = /Block id:\s+(\d+)/) {
+ # block id is first item, so push previous item to list
+ if (%blk) {
+ push(@blk, { %blk });
+ %blk = ();
+ }
+ $blk{blk_id} = int($blk_id);
+ } elsif (my($pd_id) = /PD id:\s+(\d+)/) {
+ $blk{pd_id} = int($pd_id);
+ } elsif (my($vd_id) = /VD id:\s+(\d+)/) {
+ $blk{vd_id} = int($vd_id);
+ } elsif (my($bstatus) = /Block status:\s+(.+)/) {
+ $blk{block_status} = $bstatus;
+ } elsif (my($size) = /Size:\s+(\d+) K/) {
+ $blk{size} = int($size);
+ } elsif (my($offset) = /Starting offset:\s+(\d+) K/) {
+ $blk{offset} = int($offset);
+ } else {
+# warn "[$_]\n";
+ }
+ }
+ close $fh;
+
+ if (%blk) {
+ push(@blk, { %blk });
+ }
+
+ return wantarray ? @blk : \@blk;
+}
+
+sub parse_smart {
+ my ($this, $blk) = @_;
+
+ # collect pd numbers
+ my @pd = map { $_->{pd_id} } @$blk;
+
+ my %smart;
+ foreach my $pd (@pd) {
+ my $fh = $this->cmd('mvcli smart', { '$pd' => $pd });
+ my %attrs = ();
+ while (<$fh>) {
+ chomp;
+
+ if (my($id, $name, $current, $worst, $treshold, $raw) = /
+ ([\dA-F]{2})\s+ # attr
+ (.*?)\s+ # name
+ (\d+)\s+ # current
+ (\d+)\s+ # worst
+ (\d+)\s+ # treshold
+ ([\dA-F]+) # raw
+ /x) {
+ my %attr = ();
+ $attr{id} = $id;
+ $attr{name} = $name;
+ $attr{current} = int($current);
+ $attr{worst} = int($worst);
+ $attr{treshold} = int($treshold);
+ $attr{raw} = $raw;
+ $attrs{$id} = { %attr };
+ } else {
+# warn "[$_]\n";
+ }
+ }
+
+ $smart{$pd} = { %attrs };
+ }
+
+ return \%smart;
+}
+
+sub parse {
+ my $this = shift;
+
+ my $blk = $this->parse_blk;
+ my $smart = $this->parse_smart($blk);
+
+ return {
+ blk => $blk,
+ smart => $smart,
+ };
+}
+
+sub check {
+ my $this = shift;
+
+ my (@status);
+ my @d = $this->parse;
+
+ # not implemented yet
+ $this->unknown;
+
+ $this->message(join('; ', @status));
+}
+
{
package main;
@@ -4599,25 +4965,19 @@ use strict;
use warnings;
use Getopt::Long;
+utils->import;
+sudoers->import;
+
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.4";
-my ($message, $status, $perfdata, $longoutput);
-my ($noraid_state) = $ERRORS{UNKNOWN};
+my ($VERSION) = "3.2.5";
+my ($message, $status);
#####################################################################
$ENV{'BASH_ENV'} = '';
$ENV{'ENV'} = '';
-# find first existing file from list of file paths
-sub find_file {
- for my $file (@_) {
- return $file if -f $file;
- }
- return undef;
-}
-
-sub print_usage() {
+sub print_usage {
print join "\n",
"Usage: check_raid [-h] [-V] [-S] [list of devices to ignore]",
"",
@@ -4649,7 +5009,7 @@ sub print_usage() {
"";
}
-sub print_help() {
+sub print_help {
print "check_raid, v$VERSION\n";
print "Copyright (c) 2004-2006 Steve Shipway,
Copyright (c) 2009-2015, Elan Ruusamäe <glen\@pld-linux.org>
@@ -4661,161 +5021,6 @@ https://github.com/glensc/nagios-plugin-check_raid
print_usage();
}
-# return first "#includedir" directive from $sudoers file
-sub parse_sudoers_includedir {
- my ($sudoers) = @_;
-
- open my $fh, '<', $sudoers or die "Can't open: $sudoers: $!";
- while (<$fh>) {
- if (my ($dir) = /^#includedir\s+(.+)$/) {
- return $dir;
- }
- }
- close $fh or die $!;
-
- return undef;
-}
-
-# return size of file
-# does not check for errors
-sub filesize {
- my ($file) = @_;
- return (stat($file))[7];
-}
-
-# get contents of a file
-sub cat {
- my ($file) = @_;
- open(my $fh, '<', $file) or die "Can't open $file: $!";
- local $/ = undef;
- local $_ = <$fh>;
- close($fh) or die $!;
-
- return $_;
-}
-
-# return FALSE if files are identical
-# return TRUE if files are different
-# return TRUE if any of the files is missing
-sub filediff {
- my ($file1, $file2) = @_;
-
- # return TRUE if neither of them exist
- return 1 unless -f $file1;
- return 1 unless -f $file2;
-
- my $f1 = cat($file1);
- my $f2 = cat($file2);
-
- # wipe comments
- $f1 =~ s/^#.+$//m;
- $f2 =~ s/^#.+$//m;
-
- # return TRUE if they differ
- return $f1 ne $f2;
-}
-
-# update sudoers file
-#
-# if sudoers config has "#includedir" directive, add file to that dir
-# otherwise update main sudoers file
-sub sudoers {
- my ($dry_run) = @_;
-
- # build values to be added
- # go over all registered plugins
- my @sudo;
- foreach my $pn (@utils::plugins) {
- my $plugin = $pn->new;
-
- # skip inactive plugins (disabled or no tools available)
- next unless $plugin->active;
-
- # collect sudo rules
- my @rules = $plugin->sudo(1) or next;
-
- push(@sudo, @rules);
- }
-
- unless (@sudo) {
- warn "Your configuration does not need to use sudo, sudoers not updated\n";
- return;
- }
-
- my @rules = join "\n", (
- "",
- # setup alias, so we could easily remove these later by matching lines with 'CHECK_RAID'
- # also this avoids installing ourselves twice.
- "# Lines matching CHECK_RAID added by $0 -S on ". scalar localtime,
- "User_Alias CHECK_RAID=nagios",
- "Defaults:CHECK_RAID !requiretty",
-
- # actual rules from plugins
- join("\n", @sudo),
- "",
- );
-
- if ($dry_run) {
- warn "Content to be inserted to sudo rules:\n";
- warn "--- sudoers ---\n";
- print @rules;
- warn "--- sudoers ---\n";
- return;
- }
-
- my $sudoers = find_file('/usr/local/etc/sudoers', '/etc/sudoers');
- my $visudo = utils::which('visudo');
-
- die "Unable to find sudoers file.\n" unless -f $sudoers;
- die "Unable to write to sudoers file '$sudoers'.\n" unless -w $sudoers;
- die "visudo program not found\n" unless -x $visudo;
-
- # parse sudoers file for "#includedir" directive
- my $sudodir = parse_sudoers_includedir($sudoers);
- if ($sudodir) {
- # sudo will read each file in /etc/sudoers.d, skipping file names that
- # end in ~ or contain a . character to avoid causing problems with
- # package manager or editor temporary/backup files
- $sudoers = "$sudodir/check_raid";
- }
-
- warn "Updating file $sudoers\n";
-
- # NOTE: secure as visudo itself: /etc is root owned
- my $new = $sudoers.".new.".$$;
-
- # setup to have sane perm for new sudoers file
- umask(0227);
-
- open my $fh, '>', $new or die $!;
-
- # insert old sudoers
- if (!$sudodir) {
- open my $old, '<', $sudoers or die $!;
- while (<$old>) {
- print $fh $_;
- }
- close $old or die $!;
- }
-
- # insert the rules
- print $fh @rules;
- close $fh;
-
- # validate sudoers
- system($visudo, '-c', '-f', $new) == 0 or unlink($new),exit $? >> 8;
-
- # check if they differ
- if (filediff($sudoers, $new)) {
- # use the new file
- rename($new, $sudoers) or die $!;
- warn "$sudoers file updated.\n";
- } else {
- warn "$sudoers file not changed.\n";
- unlink($new);
- }
-}
-
# Print active plugins
sub print_active_plugins {
@@ -4842,7 +5047,7 @@ sub setstate {
# 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() {
+sub git_hash_object {
my $content = "blob ";
$content .= -s $0;
$content .= "\0";
@@ -4877,13 +5082,13 @@ GetOptions(
'h' => \$opt_h, 'help' => \$opt_h,
'S' => \$opt_S, 'sudoers' => \$opt_S,
'W' => \$opt_W, 'warnonly' => \$opt_W,
- 'resync=s' => sub { setstate(\$plugin::resync_status, @_); },
- 'check=s' => sub { setstate(\$plugin::check_status, @_); },
- 'noraid=s' => sub { setstate(\$noraid_state, @_); },
- 'bbulearn=s' => sub { setstate(\$plugin::bbulearn_status, @_); },
- 'cache-fail=s' => sub { setstate(\$plugin::cache_fail_status, @_); },
+ 'resync=s' => sub { setstate(\$plugin_options{resync_status}, @_); },
+ 'check=s' => sub { setstate(\$plugin_options{check_status}, @_); },
+ 'noraid=s' => sub { setstate(\$plugin_options{noraid_state}, @_); },
+ 'bbulearn=s' => sub { setstate(\$plugin_options{bbulearn_status}, @_); },
+ 'cache-fail=s' => sub { setstate(\$plugin_options{cache_fail_status}, @_); },
'plugin-option=s' => sub { my($k, $v) = split(/=/, $_[1], 2); $plugin_options{$k} = $v; },
- 'bbu-monitoring' => \$plugin::bbu_monitoring,
+ 'bbu-monitoring' => \$plugin_options{bbu_monitoring},
'p=s' => \$opt_p, 'plugin=s' => \$opt_p,
'l' => \$opt_l, 'list-plugins' => \$opt_l,
) or exit($ERRORS{UNKNOWN});
@@ -4952,10 +5157,10 @@ foreach my $pn (@plugins) {
$message .= "$pn:[Plugin error]";
next;
}
- if ($plugin->message or $noraid_state == $ERRORS{UNKNOWN}) {
+ if ($plugin->message or $plugin->{options}{noraid_state} == $ERRORS{UNKNOWN}) {
$status = $plugin->status if $plugin->status > $status;
} else {
- $status = $noraid_state if $noraid_state > $status;
+ $status = $plugin->{options}{noraid_state} if $plugin->{options}{noraid_state} > $status;
}
$message .= '; ' if $message;
$message .= "$pn:[".$plugin->message."]";
@@ -4974,8 +5179,8 @@ if ($message) {
print "UNKNOWN: ";
}
print "$message\n";
-} elsif ($noraid_state != $ERRORS{UNKNOWN}) {
- $status = $noraid_state;
+} elsif ($plugin::options{noraid_state} != $ERRORS{UNKNOWN}) {
+ $status = $plugin::options{noraid_state};
print "No RAID configuration found\n";
} else {
$status = $ERRORS{UNKNOWN};
diff --git a/check_raid/control b/check_raid/control
index dec93d3..90f516b 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.4
+Version: 3.2.5
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,
@@ -28,3 +28,4 @@ Description: plugin to check sw/hw RAID status
- Serveraid IPS via ipssend
- Solaris software RAID via metastat
- Areca SATA RAID Support via cli64/cli32
+ - Detecting SCSI devices or hosts with lsscsi
--
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