#!/usr/bin/perl # # AUTHORS: # Copyright (C) 2008 Altinity Limited # Written by Neil Ferguson, kindly sponsored by GotVMail # # This file is part of Opsview # # Opsview is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # Opsview is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Opsview; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # use strict; use lib qw ( /usr/local/nagios/perl/lib ); use Net::SNMP; use Getopt::Std; # About us my $script = "check_snmp_vmware_gueststate"; my $script_version = "0.2"; my $hostname = ''; # SNMP variables my $oid_sysDescr = ".1.3.6.1.2.1.1.1.0"; # Used to check whether SNMP is actually responding my $oid_vmbase = ".1.3.6.1.4.1.6876."; my $oid_vm_name = "2.1.1.2."; my $oid_pwr_state = "2.1.1.6."; my $oid_os_state = "2.1.1.8."; my $oid_state = $oid_os_state; my $community = "public"; # Default community my $timeout = 10; # SNMP timeout my $retval = 3; # Innocent until proven guilty my $retmsg = ""; # Text to return from plugin my $version = "2c"; my $mode = "specificvm"; my $state_type = "h"; # p = power switch, otherwise host alive (vmtools) my $vm_name = ""; my $runwarn = 0; my $runcrit = 0; my $pwrwarn = 0; my $pwrcrit = 0; our ( $s, $e ); # Command line arguments our ( $opt_h, $opt_H, $opt_C, $opt_t, $opt_n, $opt_p, $opt_w, $opt_c, $opt_x, $opt_d ); getopts("hH:c:t:n:pw:C:x:d:"); if ($opt_h) { usage(); exit 0; } if ($opt_H) { $hostname = $opt_H; } else { print "No hostname specified\n"; usage(); exit 3; } if ($opt_C) { $community = $opt_C; } if ($opt_t) { # Validity test - must be numeric unless ( $opt_t =~ /^[0-9]+$/ ) { print "Specify time in seconds - $opt_t is not a valid integer\n"; exit 3; } $timeout = $opt_t; } if ($opt_n) { $vm_name = $opt_n; } else { $mode = "aggregate"; } if ($opt_p) { $state_type = "p"; $oid_state = $oid_pwr_state; } # Thresholds if ($opt_w) { if ( $opt_w =~ /^\d+$/ ) { $runwarn = $opt_w; } else { print "Warning values must be integers\n"; exit 3; } } if ($opt_c) { if ( $opt_c =~ /^\d+$/ ) { $runcrit = $opt_c; } else { print "Critical values must be integers\n"; exit 3; } } if ($opt_x) { if ( $opt_x =~ /^\d+$/ ) { $pwrwarn = $opt_x; } else { print "Warning values must be integers\n"; exit 3; } } if ($opt_d) { if ( $opt_d =~ /^\d+$/ ) { $pwrcrit = $opt_d; } else { print "Critical values must be integers\n"; exit 3; } } sub usage { print < -C [...] Options: -H Hostname or IP address -C SNMP community string -t SNMP timeout (in seconds) -n Guest name to check state for. If you omit this option, the check will provide a summary instead. -p Check power switch state, not OS state -w Warning threshold for VMs powered on -c Critical threshold for VMs powered on -x Warning threshold for VMs running -d Critical threshold for VMs running Note: 'Powered on' refers to the power 'switch' state in VMware 'Running' refers to the OS (VMware tools) state -------------------------------------------------------------------- Copyright 2008 Altinity Limited Plugin development was sponsored by GotVMail (http://www.gotvmail.com) This program is free software; you can redistribute it or modify it under the terms of the GNU General Public License ------------------------------------------------------------------ EOF } # Call this when you know you'll get a single value back sub get_oid_value { our ( $oid, $result, $status, $returnstring ); $oid = shift(@_); if ( !defined( $s->get_request($oid) ) ) { if ( !defined( $s->get_request($oid_sysDescr) ) ) { print "SNMP agent not responding\n"; exit 3; } else { #print "SNMP OID does not exist\n"; return ""; } } foreach ( $s->var_bind_names() ) { $result = $s->var_bind_list()->{$_}; } if ( $result eq "noSuchObject" || $result eq "noSuchInstance" ) { return ""; } return $result; } sub get_vm_state { my $name = shift; my $i = 0; my $result; # Avoid accidental infinite loops by limiting # ourselves to 100 VMs while ( $i < 100 ) { $result = get_oid_value( $oid_vmbase . $oid_vm_name . $i ); if ( $result eq "" ) { last; } elsif ( $result =~ /^$name$/i ) { return get_oid_value( $oid_vmbase . $oid_state . $i ); } $i++; } return "Not found!"; } sub get_vm_state_totals { our ( $pwr_state, $os_state ); my $i = 0; my $power_on = 0; my $power_off = 0; my $os_on = 0; my $os_off = 0; # Avoid accidental infinite loops by limiting # ourselves to 100 VMs while ( $i < 100 ) { $pwr_state = get_oid_value( $oid_vmbase . $oid_pwr_state . $i ); $os_state = get_oid_value( $oid_vmbase . $oid_os_state . $i ); if ( $os_state eq "" && $pwr_state eq "" ) { last; } else { if ( $pwr_state eq "poweredOn" ) { $power_on++; } else { $power_off++; } if ( $os_state eq "running" ) { $os_on++; } else { $os_off++; } } $i++; } return ( $power_on, $power_off, $os_on, $os_off ); } # Create the SNMP session $version = "2c"; ( $s, $e ) = Net::SNMP->session( -community => $community, -hostname => $hostname, -version => $version, -timeout => $timeout, ); if ( !defined( $s->get_request($oid_sysDescr) ) ) { # If we can't connect using SNMPv1 lets try as SNMPv2 $s->close(); sleep 0.5; $version = "1"; ( $s, $e ) = Net::SNMP->session( -community => $community, -hostname => $hostname, -version => $version, -timeout => $timeout, ); if ( !defined( $s->get_request($oid_sysDescr) ) ) { print "Agent not responding, tried SNMP v1 and v2\n"; exit 3; } } # Check for an SNMP error first... if ( $s->error ) { print "UNKNOWN - " . $s->error . "|\n"; exit 3; } # Aggregate mode or specific? if ( $mode eq "aggregate" ) { my @result = get_vm_state_totals(); my $pwr_on = shift(@result); my $pwr_off = shift(@result); my $os_on = shift(@result); my $os_off = shift(@result); my $provisioned = $os_on + $os_off; my $result_text = "OK"; my $result_code = 0; # Check thresholds if ( $os_on < $runwarn || $pwr_on < $pwrwarn ) { $result_text = "WARNING"; $result_code = 1; } elsif ( $os_on < $runcrit || $pwr_on < $pwrcrit ) { $result_text = "CRITICAL"; $result_code = 2; } # No warning/critical states, just informational print "$result_text - $pwr_on/$pwr_off pwr on/off, $os_on/$os_off OS running/not running, total $provisioned| " . "powered_on=$pwr_on;$pwrwarn;$pwrcrit;; powered_off=$pwr_off;;;; os_on=$os_on;$runwarn;$runcrit;; os_off=$os_off;;;; provisioned=$provisioned;;;;\n"; exit $result_code; } else { my $state = get_vm_state($vm_name); if ( $state eq "poweredOn" || $state eq "running" ) { print "OK - VM $vm_name is $state | vmstate=1;;;;\n"; exit 0; } else { print "CRITICAL - VM $vm_name is $state | vmstate=0;;;;\n"; exit 2; } }