First draft of code to handle arbitrary table data

This commit is contained in:
Bjarni R. Einarsson 2011-09-27 15:16:36 +00:00
parent 14365be2de
commit c6e8fa8ad3
2 changed files with 128 additions and 81 deletions

View File

@ -224,30 +224,57 @@ sub init {
} }
} elsif ($params{mode} =~ /^server::sql/) { } elsif ($params{mode} =~ /^server::sql/) {
$self->set_local_db_thresholds(%params); $self->set_local_db_thresholds(%params);
if ($params{regexp}) {
# sql output is treated as text if ($params{regexp} and ($params{name2} eq $params{name})) {
if ($params{name2} eq $params{name}) { $self->add_nagios_unknown(sprintf "where's the regexp????");
$self->add_nagios_unknown(sprintf "where's the regexp????"); }
} else { else {
$self->{genericsql} = my $data;
$self->{handle}->fetchrow_array($params{selectname}); if ($params{sqlname}) {
if (! defined $self->{genericsql}) { $data = [$self->{handle}->fetchall_array($params{selectname})];
$self->add_nagios_unknown(sprintf "got no valid response for %s",
$params{selectname});
}
} }
} else { else {
# sql output must be a number (or array of numbers) # Backwards compatibility: only fetch one row if we don't
@{$self->{genericsql}} = # have a naming column defined.
$self->{handle}->fetchrow_array($params{selectname}); $data = [[$self->{handle}->fetchrow_array($params{selectname})]];
if (! (defined $self->{genericsql} && }
(scalar(grep { /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/ } @{$self->{genericsql}})) == my $rows = scalar(@{ $data });
scalar(@{$self->{genericsql}}))) { my $cols = scalar(@{ ($rows ? $data->[0] : []) });
if ((0 == $rows) or (0 == $cols)) {
# Invalid: No rows, or first row has no columns.
$self->add_nagios_unknown(sprintf "got no valid response for %s", $self->add_nagios_unknown(sprintf "got no valid response for %s",
$params{selectname}); $params{selectname});
} else { }
# name2 in array elsif (($params{sqlname} and $params{sqlname} > $cols) or
# units in array ($params{sqlinfo} and $params{sqlinfo} > $cols) or
($params{sqleval} and $params{sqleval} > $cols)) {
# Invalid: sqlname, sqlinfo or sqleval column is out of bounds
$self->add_nagios_unknown(sprintf "got too few columns for %s",
$params{selectname});
}
elsif ($params{regexp}) {
$self->{genericsql} = $data;
# No particular conditions...
}
else {
# Scan through the data and make sure it is all either numeric or
# one of our magic columns.
my $problems = 0;
foreach my $row (@{ $data }) {
for (my $i = 1; $i <= $cols; $i++) {
if ($params{sqlname} and ($i == $params{sqlname})) { next; }
if ($params{sqlinfo} and ($i == $params{sqlinfo})) { next; }
if ($row->[$i-1] !~ /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/) {
$problems += 1;
}
}
}
if ($problems) {
$self->add_nagios_unknown(sprintf "got no valid response for %s",
$params{selectname});
} else {
$self->{genericsql} = $data;
}
} }
} }
} elsif ($params{mode} =~ /^my::([^:.]+)/) { } elsif ($params{mode} =~ /^my::([^:.]+)/) {
@ -297,6 +324,7 @@ sub init {
} else { } else {
printf "broken mode %s\n", $params{mode}; printf "broken mode %s\n", $params{mode};
} }
} }
sub dump { sub dump {
@ -410,53 +438,56 @@ sub nagios {
$self->{connectedusers}, $self->{connectedusers},
$self->{warningrange}, $self->{criticalrange}); $self->{warningrange}, $self->{criticalrange});
} elsif ($params{mode} =~ /^server::sql/) { } elsif ($params{mode} =~ /^server::sql/) {
if ($params{regexp}) {
if (substr($params{name2}, 0, 1) eq '!') { foreach my $row (@{ $self->{genericsql} }) {
$params{name2} =~ s/^!//; # the <sqleval> item in the list will be checked, or the first.
if ($self->{genericsql} !~ /$params{name2}/) { my $evalidx = $params{sqleval} ? ($params{sqleval}-1) : 0;
$self->add_nagios_ok( my $data = $row->[$evalidx];
sprintf "output %s does not match pattern %s",
$self->{genericsql}, $params{name2}); if ($params{regexp}) {
} else { my $test = $params{name2};
$self->add_nagios_critical( my $true = !($test =~ s/^!//);
sprintf "output %s matches pattern %s", if ($true == ($data =~ $test)) {
$self->{genericsql}, $params{name2}); $self->add_nagios_ok(sprintf "output %s matches pattern /%s/",
$data, $params{name2});
} }
} else { else {
if ($self->{genericsql} =~ /$params{name2}/) { $self->add_nagios_critical(sprintf "output %s does not match /%s/",
$self->add_nagios_ok( $data, $params{name2});
sprintf "output %s matches pattern %s",
$self->{genericsql}, $params{name2});
} else {
$self->add_nagios_critical(
sprintf "output %s does not match pattern %s",
$self->{genericsql}, $params{name2});
} }
} }
} else { else {
$self->add_nagios( my $info = $params{sqlinfo} ? $row->[$params{sqlinfo}-1] : '';
# the first item in the list will trigger the threshold values my $name = lc($params{sqlname} ? $row->[$params{sqlname}-1]
$self->check_thresholds($self->{genericsql}[0], 1, 5), : ($params{name2} ? $params{name2}
sprintf "%s: %s%s", : $params{selectname}));
$params{name2} ? lc $params{name2} : lc $params{selectname}, $self->add_nagios(
# float as float, integers as integers $self->check_thresholds($data, 1, 5),
join(" ", map { sprintf("%s: %s%s",
(sprintf("%d", $_) eq $_) ? $_ : sprintf("%f", $_) $name,
} @{$self->{genericsql}}), $info ? $info : join(" ", @{ $row }),
$params{units} ? $params{units} : ""); $params{units} ? $params{units} : "")
my $i = 0; );
# workaround... getting the column names from the database would be nicer my $i = 0;
my @names2_arr = split(/\s+/, $params{name2}); # workaround: getting column names from the database would be nicer
foreach my $t (@{$self->{genericsql}}) { my @names2 = split(/\s+/, $params{name2});
$self->add_perfdata(sprintf "\'%s\'=%s%s;%s;%s", my $prefix = lc($params{sqlname} ? $row->[$params{sqlname}-1].'_'
$names2_arr[$i] ? lc $names2_arr[$i] : lc $params{selectname}, : '');
# float as float, integers as integers for (my $i = 0; $i < scalar(@{ $row }); $i++) {
(sprintf("%d", $t) eq $t) ? $t : sprintf("%f", $t), if ($params{sqlname} and ($i+1 == $params{sqlname})) { next; }
$params{units} ? $params{units} : "", if ($params{sqlinfo} and ($i+1 == $params{sqlinfo})) { next; }
($i == 0) ? $self->{warningrange} : "", my $t = $row->[$i];
($i == 0) ? $self->{criticalrange} : "" $self->add_perfdata(
); sprintf("\'%s%s\'=%s%s;%s;%s",
$i++; $prefix,
lc($names2[$i] ? $names2[$i] : $params{selectname}),
# float as float, integer as integer
(sprintf("%d", $t) eq $t) ? $t : sprintf("%f", $t),
$params{units} ? $params{units} : "",
($i == $evalidx) ? $self->{warningrange} : "",
($i == $evalidx) ? $self->{criticalrange} : "")
);
}
} }
} }
} elsif ($params{mode} =~ /^my::([^:.]+)/) { } elsif ($params{mode} =~ /^my::([^:.]+)/) {
@ -592,14 +623,6 @@ sub calculate_result {
length join(" ", @{$self->{nagios}->{perfdata}}) > 200) { length join(" ", @{$self->{nagios}->{perfdata}}) > 200) {
$multiline = 1; $multiline = 1;
} }
if ($multiline) {
my $num_ok = @{$self->{nagios}->{messages}->{ $ERRORS{"OK"} } };
my $num_crit = @{$self->{nagios}->{messages}->{ $ERRORS{"WARNING"} }};
my $num_warn = @{$self->{nagios}->{messages}->{ $ERRORS{"CRITICAL"} }};
my $num_unk = @{$self->{nagios}->{messages}->{ $ERRORS{"UNKNOWN"} }};
$self->{nagios_message} .= sprintf "%s ok, %s warnings, %s criticals and %s unknown\n",
$num_ok, $num_warn,$num_crit, $num_unk;
}
my $all_messages = join(($multiline ? "\n" : ", "), map { my $all_messages = join(($multiline ? "\n" : ", "), map {
join(($multiline ? "\n" : ", "), @{$self->{nagios}->{messages}->{$ERRORS{$_}}}) join(($multiline ? "\n" : ", "), @{$self->{nagios}->{messages}->{$ERRORS{$_}}})
} grep { } grep {

View File

@ -102,7 +102,7 @@ my @modes = (
'Elapsed time (in hours) since a database was last backupped' ], 'Elapsed time (in hours) since a database was last backupped' ],
['server::sql', ['server::sql',
'sql', undef, 'sql', undef,
'any sql command returning a single number' ], 'any sql command' ],
['server::database::listdatabases', ['server::database::listdatabases',
'list-databases', undef, 'list-databases', undef,
'convenience function which lists all databases' ], 'convenience function which lists all databases' ],
@ -174,19 +174,37 @@ EOUS
If only a single database should be checked, use the --name parameter. If only a single database should be checked, use the --name parameter.
The same applies to datafile-related modes. The same applies to datafile-related modes.
Options specific to 'server::sql' mode:
--sqleval
For results with multiple columns, this is the index (counting from
1) of the column to evaluate with --warning and/or --critical. If
this option is missing, the statement is assumed to return only a
single column.
--sqlname
For results with multiple columns, this is the index (counting from
1) of the column use as the output name (instead of --name2). If
this option is missing, only the first row will be parsed.
--sqlinfo
For results with multiple columns, this is the index (counting from
1) of a column to present as a detailed explanation.
In mode sql you can url-encode the statement so you will not have to mess In mode sql you can url-encode the statement so you will not have to mess
around with special characters in your Nagios service definitions. around with special characters in your Nagios service definitions.
Instead of Instead of
--name="select count(*) from master..sysprocesses"
--name="select count(*) from master..sysprocesses"
you can say you can say
--name=select%20count%28%2A%29%20from%20master%2E%2Esysprocesses
--name=select%20count%28%2A%29%20from%20master%2E%2Esysprocesses
For your convenience you can call check_mssql_health with the --encode For your convenience you can call check_mssql_health with the --encode
option and it will encode the standard input. option and it will encode the standard input.
You can find the full documentation for this plugin at You can find the full documentation for this plugin at:
http://www.consol.de/opensource/nagios/check-mssql-health or http://www.consol.de/opensource/nagios/check-mssql-health
http://www.consol.com/opensource/nagios/check-mssql-health or http://www.consol.com/opensource/nagios/check-mssql-health
EOUS EOUS
# #
@ -257,6 +275,9 @@ my @params = (
"name=s", "name=s",
"name2=s", "name2=s",
"regexp", "regexp",
"sqleval=i",
"sqlname=i",
"sqlinfo=i",
"perfdata", "perfdata",
"warning=s", "warning=s",
"critical=s", "critical=s",
@ -505,6 +526,9 @@ my %params = (
regexp => $commandline{regexp}, regexp => $commandline{regexp},
name => $commandline{name}, name => $commandline{name},
name2 => $commandline{name2} || $commandline{name}, name2 => $commandline{name2} || $commandline{name},
sqleval => $commandline{sqleval},
sqlname => $commandline{sqlname},
sqlinfo => $commandline{sqlinfo},
units => $commandline{units}, units => $commandline{units},
eyecandy => $commandline{eyecandy}, eyecandy => $commandline{eyecandy},
statefilesdir => $STATEFILESDIR, statefilesdir => $STATEFILESDIR,