connection => [0, 'Simple connection check.'],
custom_query => [0, 'Run a custom query.'],
database_commitratio => [0, 'Report if the commitratio of a database is too low.'],
+ database_hitratio => [0, 'Report if the hitratio of a database is too low.'],
database_size => [0, 'Report if a database is too big.'],
dbstats => [1, 'Returns stats from pg_stat_database: Cacti output only'],
disabled_triggers => [0, 'Check if any triggers are disabled'],
## Check the commitratio of one or more databases
check_database_commitratio() if $action eq 'database_commitratio';
+## Check the hitratio of one or more databases
+check_database_hitratio() if $action eq 'database_hitratio';
+
## Check the size of one or more databases
check_database_size() if $action eq 'database_size';
} ## end of check_database_commitratio
+sub check_database_hitratio {
+
+ ## Check the hitratio of one or more databases
+ ## Supports: Nagios, MRTG
+ ## mrtg reports the largest two databases
+ ## By default, checks all databases
+ ## Can check specific one(s) with include
+ ## Can ignore some with exclude
+ ## Warning and criticals are percentages
+ ## Limit to a specific user (db owner) with the includeuser option
+ ## Exclude users with the excludeuser option
+
+ my ($warning, $critical) = validate_range({type => 'percent'});
+
+ $SQL = qq{
+SELECT
+ round(100.*sd.blks_hit/(sd.blks_read+sd.blks_hit), 2) AS dhitratio,
+ d.datname,
+ u.usename
+FROM pg_stat_database sd
+JOIN pg_database d ON (d.oid=sd.datid)
+JOIN pg_user u ON (u.usesysid=d.datdba)
+WHERE sd.blks_read+sd.blks_hit<>0
+$USERWHERECLAUSE
+};
+ if ($opt{perflimit}) {
+ $SQL .= " ORDER BY 1 DESC LIMIT $opt{perflimit}";
+ }
+
+ my $info = run_command($SQL, { regex => qr{\d+}, emptyok => 1, } );
+ my $found = 0;
+
+ for $db (@{$info->{db}}) {
+ my $min = 101;
+ $found = 1;
+ my %s;
+ for my $r (@{$db->{slurp}}) {
+
+ next if skip_item($r->{datname});
+
+ if ($r->{dhitratio} <= $min) {
+ $min = $r->{dhitratio};
+ }
+ $s{$r->{datname}} = $r->{dhitratio};
+ }
+
+ if ($MRTG) {
+ do_mrtg({one => $min, msg => "DB: $db->{dbname}"});
+ }
+ if ($min > 100) {
+ $stats{$db->{dbname}} = 0;
+ if ($USERWHERECLAUSE) {
+ add_ok msg('no-match-user');
+ }
+ else {
+ add_unknown msg('no-match-db');
+ }
+ next;
+ }
+
+ my $msg = '';
+ for (reverse sort {$s{$b} <=> $s{$a} or $a cmp $b } keys %s) {
+ $msg .= "$_: $s{$_} ";
+ $db->{perf} .= sprintf ' %s=%s;%s;%s',
+ perfname($_), $s{$_}, $warning, $critical;
+ }
+ if (length $critical and $min <= $critical) {
+ add_critical $msg;
+ }
+ elsif (length $warning and $min <= $warning) {
+ add_warning $msg;
+ }
+ else {
+ add_ok $msg;
+ }
+ }
+
+ ## If no results, probably a version problem
+ if (!$found and keys %unknown) {
+ (my $first) = values %unknown;
+ if ($first->[0][0] =~ /pg_database_size/) {
+ ndie msg('dbsize-version');
+ }
+ }
+
+ return;
+
+} ## end of check_database_hitratio
+
+
sub check_database_size {
## Check the size of one or more databases
For MRTG output, returns the percentage of the database with the smallest commitratio on the first line,
and the name of the database on the fourth line.
+=head2 B<database_hitratio>
+
+(C<symlink: check_postgres_database_hitratio>) Checks the hit ratio of all databases and complains when they are too low.
+There is no need to run this command more than once per database cluster.
+Databases can be filtered with
+the I<--include> and I<--exclude> options. See the L</"BASIC FILTERING"> section
+for more details.
+They can also be filtered by the owner of the database with the
+I<--includeuser> and I<--excludeuser> options.
+See the L</"USER NAME FILTERING"> section for more details.
+
+The warning and critical options should be specified as percentages. There are not
+defaults for this action: the warning and critical must be specified. The warning value
+cannot be greater than the critical value. The output returns all databases sorted by
+hitratio, smallest first.
+
+Example: Warn if any database on host flagg is less than 90% in hitratio, and critical if less then 80%.
+
+ check_postgres_database_hitratio --host=flagg --warning='90%' --critical='80%'
+
+For MRTG output, returns the percentage of the database with the smallest hitratio on the first line,
+and the name of the database on the fourth line.
+
=head2 B<database_size>
(C<symlink: check_postgres_database_size>) Checks the size of all databases and complains when they are too big.
--- /dev/null
+#!perl
+
+## Test the "database_size" action
+
+use 5.006;
+use strict;
+use warnings;
+use Data::Dumper;
+use Test::More tests => 23;
+use lib 't','.';
+use CP_Testing;
+
+use vars qw/$dbh $dbh2 $SQL $count $host $t $result $user/;
+
+my $cp = CP_Testing->new({default_action => 'database_hitratio'});
+
+$dbh = $cp->test_database_handle();
+
+my $S = q{Action 'database_hitratio'};
+my $label = 'POSTGRES_DATABASE_HITRATIO';
+
+$cp->drop_all_tables();
+
+$t=qq{$S returned expected text when warning level is specified in percentages};
+like ($cp->run('-w 0%'), qr{^$label OK:}, $t);
+
+$t=qq{$S returned expected text when warning level is specified in percentages};
+like ($cp->run('-w 100%'), qr{^$label WARNING:}, $t);
+
+$t=qq{$S returned expected text when critical level is specified};
+like ($cp->run('-c 0%'), qr{^$label OK:}, $t);
+
+$t=qq{$S returned expected text when warning level and critical level are specified};
+like ($cp->run('-w 0% -c 0%'), qr{^$label OK:}, $t);
+
+$t=qq{$S fails when called with an invalid option};
+like ($cp->run('foobar=12'), qr{^\s*Usage:}, $t);
+
+$t=qq{$S fails when called with an invalid warning option};
+like ($cp->run('-w felz'), qr{^ERROR: Invalid 'warning' option: must be a percentage}, $t);
+like ($cp->run('-w 23%%'), qr{^ERROR: Invalid 'warning' option: must be a percentage}, $t);
+
+$t=qq{$S fails when called with an invalid critical option};
+like ($cp->run('-c felz'), qr{^ERROR: Invalid 'critical' option: must be a percentage}, $t);
+like ($cp->run('-c 23%%'), qr{^ERROR: Invalid 'critical' option: must be a percentage}, $t);
+
+$t=qq{$S fails when the warning or critical percentages is negative};
+like ($cp->run('-w -10%'), qr{^ERROR: Invalid 'warning' option: must be a percentage}, $t);
+like ($cp->run('-c -20%'), qr{^ERROR: Invalid 'critical' option: must be a percentage}, $t);
+
+$t=qq{$S with includeuser option returns nothing};
+like ($cp->run('--includeuser mycatbeda -w 10%'), qr{^$label OK:.+ }, $t);
+
+$t=qq{$S has critical option trump the warning option};
+like ($cp->run('-w 100% -c 100%'), qr{^$label CRITICAL}, $t);
+like ($cp->run('--critical=100% --warning=99%'), qr{^$label CRITICAL}, $t);
+
+$t=qq{$S returns correct MRTG output when no rows found};
+like ($cp->run('--output=MRTG -w 10% --includeuser nosuchuser'), qr{^101}, $t);
+
+$t=qq{$S returns correct MRTG output when rows found};
+like ($cp->run('--output=MRTG -w 10%'), qr{\d+\n0\n\nDB: postgres\n}s, $t);
+
+$t=qq{$S works when include forces no matches};
+like ($cp->run('-w 1% --include blargy'), qr{^$label UNKNOWN: .+No matching databases}, $t);
+
+$t=qq{$S works when include has valid database};
+like ($cp->run('-w 1% --include=postgres'), qr{$label OK: .+postgres}, $t);
+
+$t=qq{$S works when exclude excludes nothing};
+like ($cp->run('-w 90% --exclude=foobar'), qr{$label OK: DB "postgres"}, $t);
+
+$t=qq{$S works when include and exclude make a match};
+like ($cp->run('-w 5% --exclude=postgres --include=postgres'), qr{$label OK: DB "postgres"}, $t);
+
+$t=qq{$S works when exclude and include make a match};
+like ($cp->run('-w 5% --include=postgres --exclude=postgres'), qr{$label OK: DB "postgres"}, $t);
+
+$t=qq{$S returned correct performance data with include};
+like ($cp->run('-w 5% --include=postgres'), qr{ \| time=\d\.\d\ds postgres=\d+}, $t);
+
+$t=qq{$S with includeuser option returns nothing};
+like ($cp->run('--includeuser postgres --includeuser mycatbeda -w 10%'), qr{No matching entries found due to user exclusion}, $t);
+
+exit;