#!/usr/local/bin/perl # # Check status a cluster of hosts or services via livestatus. # Try to emulate the cli options from stock check_cluster. # # $Header: /home/doke/work/nagios/RCS/check_cluster_livestatus,v 1.2 2017/08/30 15:55:33 doke Exp $ use strict; use warnings; use Getopt::Long; use Monitoring::Livestatus; use Data::Dumper; use vars qw( $verbose $help $services_mode $hosts_mode $label $warning $critical $data $ml @crits @warns @unknowns @oks @ignores ); $warning = 1; $critical = 2; $verbose = 0; $help = 0; sub usage { my( $rc ) = @_; print qq{Usage: $0 [-vh] -s, --service Check service cluster status -h, --host Check host cluster status -l, --label=STRING Optional prepended text output (i.e. "Host cluster") -w, --warning=THRESHOLD Specifies the range of hosts or services in cluster that must be in a non-OK state in order to return a WARNING status level -c, --critical=THRESHOLD Specifies the range of hosts or services in cluster that must be in a non-OK state in order to return a CRITICAL status level -d, --data=LIST The hosts or services in the cluster, separated by commas Hosts are "host1,host2,..." Services are "host1:service1,host2:service2,..." -v, --verbose --help show these instructions }; exit $rc; } GetOptions( 's' => \$services_mode, 'service' => \$services_mode, 'h' => \$hosts_mode, 'host' => \$hosts_mode, 'l=s' => \$label, 'label=s' => \$label, 'w=i' => \$warning, 'warning=i' => \$warning, 'c=i' => \$critical, 'critical=i' => \$critical, 'd=s' => \$data, 'data=s' => \$data, 'v+' => \$verbose, 'verbose+' => \$verbose, 'help' => \$help, ); usage( 0 ) if ( $help ); if ( $services_mode && $hosts_mode ) { push @unknowns, "must specify either service xor host mode"; } elsif ( $services_mode ) { check_services(); } elsif ( $hosts_mode ) { &check_hosts(); } else { push @unknowns, "must specify service or host mode"; } my $rc = 0; my $sep = ''; if ( $#crits >= 0 ) { $rc = 2; print "CRITICAL ", join( ", ", @crits ); $sep = '; '; } if ( $#warns >= 0 ) { $rc = 1 if ( $rc == 0 ); print $sep, "Warning ", join( ", ", @warns ); $sep = '; '; } if ( $#unknowns >= 0 ) { $rc = -1 if ( $rc == 0 ); print $sep, "Unknown ", join( ", ", @unknowns ); $sep = '; '; } if ( $rc == 0 ) { print "Ok ", join( ", ", @oks ); $sep = '; '; } if ( $#ignores >= 0 ) { print $sep, "Ignoring ", join( ", ", @ignores ); } print "\n"; exit $rc; ################## sub check_services { my( @hostservices, $hostservice, $ml, $host, $service, $query, $results, $state, $plugin_output, $nunknowns, $noks, $nwarns, $ncrits, @outputs ); @hostservices = split( m/\s*,\s*/, $data ); if ( $#hostservices < 0 ) { push @unknowns, "no host:services listed"; return; } $ml = Monitoring::Livestatus->new( socket => '/usr/local/nagios/var/rw/live' ); $nunknowns = $noks = $nwarns = $ncrits = 0; foreach $hostservice ( @hostservices ) { ( $host, $service ) = split( m/:/, $hostservice ); if ( $host !~ m/^[\w\d\.-]+/ ) { push @unknowns, "invalid host '$host'"; return; } if ( $service !~ m/^[\w\d\/\._ -]+/ ) { push @unknowns, "invalid service '$service'"; return; } $query = "GET services\n" . "Columns: state plugin_output\n" . "Filter: host_name = $host\n" . "Filter: service_description = $service\n" . "And: 2\n"; $verbose && print "query: $query\n"; $results = $ml->selectall_arrayref( $query ); $verbose && print "results: ", Dumper( $results ), "\n"; if ( ! defined $results || ! defined $results->[0] ) { $nunknowns ++; push @unknowns, "cannot find service $host:$service"; next; } $state = $results->[0][0]; $plugin_output = $results->[0][1]; if ( $state == 2 ) { $ncrits ++; push @outputs, "CRITICAL $host $service $plugin_output"; } elsif ( $state == 1 ) { $nwarns ++; push @outputs, "Warning $host $service $plugin_output"; } elsif ( $state == 3 ) { $nunknowns ++; push @outputs, "Unknown $host $service $plugin_output"; } elsif ( $state == 0 ) { $noks ++; #push @outputs, "Ok $host $service $plugin_output"; } else { $nwarns ++; push @outputs, "invalid state for $host $service"; } } # see if number of criticals exceeds one of the thresholds if ( $ncrits >= $critical ) { push @crits, "$ncrits critical, $nwarns warning, $noks ok"; push @oks, @outputs; } elsif ( $ncrits >= $warning ) { push @warns, "$ncrits critical, $nwarns warning, $noks ok"; push @oks, @outputs; } else { push @oks, "$ncrits critical, $nwarns warning, $noks ok"; push @oks, @outputs; } } sub check_hosts { my( @hosts, $host, $ml, $query, $results, $state, $plugin_output, $ndown, $nup ); @hosts = split( m/\s*,\s*/, $data ); if ( $#hosts < 0 ) { push @unknowns, "no hosts listed"; return; } $ml = Monitoring::Livestatus->new( socket => '/usr/local/nagios/var/rw/live' ); $ndown = $nup = 0; foreach $host ( @hosts ) { if ( $host !~ m/^[\w\d\.-]+/ ) { push @unknowns, "invalid host '$host'"; return; } $query = "GET hosts\n" . "Columns: state plugin_output\n" . "Filter: host_name = $host\n"; $verbose && print "query: $query\n"; $results = $ml->selectall_arrayref( $query ); $verbose && print "results: ", Dumper( $results ), "\n"; if ( ! defined $results || ! defined $results->[0] ) { push @unknowns, "cannot find host $host"; next; } $state = $results->[0][0]; $plugin_output = $results->[0][1]; if ( $state == 1 ) { $ndown ++; push @crits, "DOWN $host $plugin_output"; } elsif ( $state == 0 ) { $nup ++; #push @oks, "UP $host $plugin_output"; } else { push @unknowns, "invalid state for $host"; } } # see if number of criticals exceeds one of the thresholds if ( $ndown >= $critical ) { push @crits, "$ndown down, $nup up"; } elsif ( $ndown >= $warning ) { push @warns, "$ndown down, $nup up"; } else { push @oks, "$ndown down, $nup up"; } }