#! /usr/bin/perl -w # Check Microsoft Cluster Server (MSCS) # via HP Management Agents for Server # # Plugin uses SNMP connection to server (CPQCLUS1.MIB). # # Copyright (C) 2007 by Herbert Stadler # email: hestadler@gmx.at # License Information: # This program 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 3 of the License, or # (at your option) any later version. # # This program 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 this program; if not, see . # # ############################################################################ use POSIX; use strict; use Getopt::Long; #use Data::Dumper; use lib "."; use lib "/usr/lib/nagios/plugins"; use lib "/usr/lib64/nagios/plugins"; use lib "/usr/local/nagios/libexec"; use utils qw(%ERRORS); use Net::SNMP qw(oid_lex_sort oid_base_match :debug); my ($opt_version,$opt_help,$opt_verbose,$opt_pgo); my ($opt_addhosts,$opt_timeout,$opt_license,$opt_quorumdisk); my ($opt_hostname,$opt_community,$opt_port,$opt_snmpvers); my ($opt_snmpdebug,$opt_snmptimeout); my ($PROGNAME,$REVISION); my ($state,$msg); my ($g_snmpdebug); my (@t_pgo); my $DEFAULT_TIMEOUT =30; my $DEFAULT_SNMPTIMEOUT =2; # MIB OID's of CPQCLUS1.MIB my $Cluster_oid ="1.3.6.1.4.1.232.15"; my $ClMibRev_group ="1.3.6.1.4.1.232.15.1"; my $ClMibRevMajor_scalar ="1.3.6.1.4.1.232.15.1.1.0"; my $ClMibRevMinor_scalar ="1.3.6.1.4.1.232.15.1.2.0"; my $ClMibCondition_scalar ="1.3.6.1.4.1.232.15.1.3.0"; my $ClOsCommon_group ="1.3.6.1.4.1.232.15.2.1.4"; my $ClOsCommonPollFreq_scalar ="1.3.6.1.4.1.232.15.2.1.4.1.0"; my $ClOsCommonModuleTable ="1.3.6.1.4.1.232.15.2.1.4.2"; my $ClOsCommonModuleEntry ="1.3.6.1.4.1.232.15.2.1.4.2.1"; my $ClOsCommonModuleIndex_tabular ="1.3.6.1.4.1.232.15.2.1.4.2.1.1"; my $ClOsCommonModuleName_tabular ="1.3.6.1.4.1.232.15.2.1.4.2.1.2"; my $ClOsCommonModuleVersion_tabular ="1.3.6.1.4.1.232.15.2.1.4.2.1.3"; my $ClOsCommonModuleDate_tabular ="1.3.6.1.4.1.232.15.2.1.4.2.1.4"; my $ClOsCommonModulePurpose_tabular ="1.3.6.1.4.1.232.15.2.1.4.2.1.5"; my $ClInfo_group ="1.3.6.1.4.1.232.15.2.2"; my $ClName_scalar ="1.3.6.1.4.1.232.15.2.2.1.0"; my $ClCondition_scalar ="1.3.6.1.4.1.232.15.2.2.2.0"; my $ClIpAddress_scalar ="1.3.6.1.4.1.232.15.2.2.3.0"; my $ClQuorumResource_scalar ="1.3.6.1.4.1.232.15.2.2.4.0"; my $ClMajorVersion_scalar ="1.3.6.1.4.1.232.15.2.2.5.0"; my $ClMinorVersion_scalar ="1.3.6.1.4.1.232.15.2.2.6.0"; my $ClCSDVersion_scalar ="1.3.6.1.4.1.232.15.2.2.7.0"; my $ClVendorId_scalar ="1.3.6.1.4.1.232.15.2.2.8.0"; my $ClResourceAggregateCondition_scalar="1.3.6.1.4.1.232.15.2.2.9.0"; my $ClNetworkAggregateCondition_scalar ="1.3.6.1.4.1.232.15.2.2.10.0"; my $ClNode_group ="1.3.6.1.4.1.232.15.2.3"; my $ClNodeTable ="1.3.6.1.4.1.232.15.2.3.1"; my $ClNodeEntry ="1.3.6.1.4.1.232.15.2.3.1.1"; my $ClNodeIndex_tabular ="1.3.6.1.4.1.232.15.2.3.1.1.1"; my $ClNodeName_tabular ="1.3.6.1.4.1.232.15.2.3.1.1.2"; my $ClNodeStatus_tabular ="1.3.6.1.4.1.232.15.2.3.1.1.3"; my $ClNodeCondition_tabular ="1.3.6.1.4.1.232.15.2.3.1.1.4"; my $ClResource_group ="1.3.6.1.4.1.232.15.2.4"; my $ClResourceTable ="1.3.6.1.4.1.232.15.2.4.1"; my $ClResourceEntry ="1.3.6.1.4.1.232.15.2.4.1.1"; my $ClResourceIndex_tabular ="1.3.6.1.4.1.232.15.2.4.1.1.1"; my $ClResourceName_tabular ="1.3.6.1.4.1.232.15.2.4.1.1.2"; my $ClResourceType_tabular ="1.3.6.1.4.1.232.15.2.4.1.1.3"; my $ClResourceState_tabular ="1.3.6.1.4.1.232.15.2.4.1.1.4"; my $ClResourceOwnerNode_tabular ="1.3.6.1.4.1.232.15.2.4.1.1.5"; my $ClResourcePhysId_tabular ="1.3.6.1.4.1.232.15.2.4.1.1.6"; my $ClResourceCondition_tabular ="1.3.6.1.4.1.232.15.2.4.1.1.7"; my $ClResourceDriveLetter_tabular ="1.3.6.1.4.1.232.15.2.4.1.1.8"; my $ClResourceIpAddress_tabular ="1.3.6.1.4.1.232.15.2.4.1.1.9"; my $ClResourceGroupName_tabular ="1.3.6.1.4.1.232.15.2.4.1.1.10"; my $ClInterconnect_group ="1.3.6.1.4.1.232.15.2.5"; my $ClInterconnectTable ="1.3.6.1.4.1.232.15.2.5.1"; my $ClInterconnectEntry ="1.3.6.1.4.1.232.15.2.5.1.1"; my $ClInterconnectIndex_tabular ="1.3.6.1.4.1.232.15.2.5.1.1.1"; my $ClInterconnectPhysId_tabular ="1.3.6.1.4.1.232.15.2.5.1.1.2"; my $ClInterconnectTransport_tabular ="1.3.6.1.4.1.232.15.2.5.1.1.3"; my $ClInterconnectAddress_tabular ="1.3.6.1.4.1.232.15.2.5.1.1.4"; my $ClInterconnectNetworkName_tabular="1.3.6.1.4.1.232.15.2.5.1.1.5"; my $ClInterconnectNodeName_tabular ="1.3.6.1.4.1.232.15.2.5.1.1.6"; my $ClInterconnectRole_tabular ="1.3.6.1.4.1.232.15.2.5.1.1.7"; my $ClNetwork_group ="1.3.6.1.4.1.232.15.2.6"; my $ClNetworkTable ="1.3.6.1.4.1.232.15.2.6.1"; my $ClNetworkEntry ="1.3.6.1.4.1.232.15.2.6.1.1"; my $ClNetworkIndex_tabular ="1.3.6.1.4.1.232.15.2.6.1.1.1"; my $ClNetworkName_tabular ="1.3.6.1.4.1.232.15.2.6.1.1.2"; my $ClNetworkAddressMask_tabular ="1.3.6.1.4.1.232.15.2.6.1.1.3"; my $ClNetworkDescription_tabular ="1.3.6.1.4.1.232.15.2.6.1.1.4"; my $ClNetworkRole_tabular ="1.3.6.1.4.1.232.15.2.6.1.1.5"; my $ClNetworkState_tabular ="1.3.6.1.4.1.232.15.2.6.1.1.6"; my $ClNetworkCondition_tabular ="1.3.6.1.4.1.232.15.2.6.1.1.7"; # Textual description of the different values my %ClMibCondition_val = ( 1 => "other", 2 => "ok", 3 => "degraded", 4 => "failed", ); my %ClCondition_val = ( 1 => "other", 2 => "ok", 3 => "degraded", 4 => "failed", ); my %ClResourceAggregateCondition_val = ( 1 => "other", 2 => "ok", 3 => "degraded", 4 => "failed", ); my %ClNetworkAggregateCondition_val = ( 1 => "other", 2 => "ok", 3 => "degraded", 4 => "failed", ); my %ClNodeStatus_val = ( 1 => "other", 2 => "nodeUp", 3 => "nodeDown", 4 => "nodePaused", 5 => "nodeJoining", ); my %ClNodeCondition_val = ( 1 => "other", 2 => "ok", 3 => "degraded", 4 => "failed", ); my %ClResourceState_val = ( 1 => "other", 2 => "online", 3 => "offline", 4 => "failed", 5 => "onlinePending", 6 => "offlinePending", ); my %ClResourceCondition_val = ( 1 => "other", 2 => "ok", 3 => "degraded", 4 => "failed", ); my %ClInterconnectRole_val = ( 1 => "none", 2 => "client", 3 => "internal", 4 => "clientAndInternal", ); my %ClNetworkRole_val = ( 1 => "none", 2 => "client", 3 => "internal", 4 => "clientAndInternal", ); my %ClNetworkState_val = ( 1 => "other", 2 => "online", 3 => "offline", 4 => "partitioned", 5 => "unavailable", ); my %ClNetworkCondition_val = ( 1 => "other", 2 => "ok", 3 => "degraded", 4 => "failed", ); $ENV{'PATH'}=''; $ENV{'BASH_ENV'}=''; $ENV{'ENV'}=''; $PROGNAME = "check_mscs_hpma"; $REVISION = "1.8"; # checking commandline arguments my $arg_status = check_args(); if ($arg_status){ print "ERROR: some arguments wrong\n"; exit $ERRORS{"UNKNOWN"}; } if ($opt_snmpdebug) { my $module="Net::SNMP"; printf( "%-20s Version: %s\n", $module, $module->VERSION ); } # set alarmhandler for timeouthandling $SIG{'ALRM'} = sub { print ("ERROR: plugin timed out after $opt_timeout seconds \n"); exit $ERRORS{"UNKNOWN"}; }; alarm($opt_timeout); # build array of hostnames in the cluster my @t_hostnames; push @t_hostnames,$opt_hostname; if (defined $opt_addhosts){ my @t_temphosts=split(/,/,$opt_addhosts); foreach (@t_temphosts) { push @t_hostnames,$_; } } # check the hosts if they want to speak with us, maybe some are down # we take the first who is answering my $s_found=0; foreach my $l_hostname (@t_hostnames) { my ($snmp_session_tmp,$snmp_error_tmp)=open_snmp_session($l_hostname); if ( ! defined ($snmp_session_tmp)) { next; } $snmp_session_tmp->translate(['-endofmibview'=>0,'-nosuchobject'=>0,'-nosuchinstance'=>0]); my @oid_tmp; push @oid_tmp,$ClName_scalar; my $l_snmp_result_tmp=$snmp_session_tmp->get_request( -varbindlist => \@oid_tmp, ); #if ( ! defined ($l_snmp_result_tmp)) { if ($snmp_session_tmp->error_status != 0) { $snmp_session_tmp->close; next; } # this one speaks to us, should normally be the host defined with "-H" $opt_hostname=$l_hostname; $snmp_session_tmp->close; $s_found++; last; } if ($s_found == 0) { print "CLUSTER ERROR: Could not open connection to the host(s), all probably down\n"; exit $ERRORS{'UNKNOWN'}; } # now we have a host who wants to speak with us my ($snmp_session,$snmp_error)=open_snmp_session($opt_hostname); if ( ! defined ($snmp_session)) { print "CLUSTER ERROR: Could not open connection: $snmp_error \n"; exit $ERRORS{'UNKNOWN'}; } $snmp_session->translate(['-endofmibview'=>0,'-nosuchobject'=>0,'-nosuchinstance'=>0]); # get Cluster OS Common Module Table my $p_ClOsCommonModuleTable=get_cluster_info_get_table_request ($ClOsCommonModuleTable); # get Cluster Node Table my $p_ClNodeTable=get_cluster_info_get_table_request ($ClNodeTable); # get Cluster Resource Table my $p_ClResourceTable=get_cluster_info_get_table_request ($ClResourceTable); # get Cluster Interconnect Table my $p_ClInterconnectTable=get_cluster_info_get_table_request ($ClInterconnectTable); # get Cluster Network Table my $p_ClNetworkTable=get_cluster_info_get_table_request ($ClNetworkTable); # Reading necessary OIDs my $oids=build_oid_table(); my $p_ClOids=get_cluster_info_get_request ($oids); $snmp_session->close; # Check if Cluster is installed on server if ( $p_ClOids->{$ClName_scalar} eq "noSuchObject" ) { print "CLUSTER ERROR: Please check Cluster Installation, something wrong!\n"; exit $ERRORS{'UNKNOWN'}; } my $l_quorum_holder=get_quorum_holder($p_ClOids->{$ClQuorumResource_scalar}); if ( $opt_verbose ) { print_Cluster_Info (); print_Cluster_MIB_Revision (); print_Cluster_OS_Common (); print_Cluster_Node (); print_Cluster_Resource (); print_Cluster_Interconnect (); print_Cluster_Network (); } # set standard values for program exit $msg = "CLUSTER OK - No Problems found"; $state = $ERRORS{'OK'}; my $l_tmsg; # checking of condition and status flags for the returncode if ( $ClCondition_val{$p_ClOids->{$ClCondition_scalar}} ne "ok" ) { # the overall cluster condition is not OK # get some status information from the cluster nodes my $l_node_status=get_cluster_node_status(); # get some status information from the cluster resources my $l_resource_status=get_cluster_resource_status(); # get some status information from the cluster network my $l_network_status=get_cluster_network_status(); # build the output message create_msg($l_node_status,\$l_tmsg); create_msg($l_resource_status,\$l_tmsg); create_msg($l_network_status,\$l_tmsg); if ( $ClCondition_val{$p_ClOids->{$ClCondition_scalar}} eq "degraded" ) { $state = $ERRORS{'WARNING'}; } else { $state = $ERRORS{'CRITICAL'}; } } # and now we check if some cluster group failed-over to another node my $l_GroupFailedOver_status=get_GroupFailedOver_status(); if (defined $l_GroupFailedOver_status) { create_msg($l_GroupFailedOver_status,\$l_tmsg); if ($state == $ERRORS{'OK'}){ $state = $ERRORS{'WARNING'}; } } if ($state == $ERRORS{'WARNING'}){ $msg = "CLUSTER WARNING - ".$l_tmsg; }elsif ($state == $ERRORS{'CRITICAL'}){ $msg = "CLUSTER CRITICAL - ".$l_tmsg; } if ( $opt_quorumdisk ) { $msg.=sprintf(" (QuDisk on: %s)",$l_quorum_holder); } # and now "over and out" print "$msg\n"; exit $state; #--------------------------------------------------------------------------# # S U B R O U T I N E S # #--------------------------------------------------------------------------# sub open_snmp_session { my ($l_host)=@_; # open SNMP Session to Server my ($snmp_session,$snmp_error)=Net::SNMP->session( -hostname => $l_host, -community => $opt_community || 'public', -port => $opt_port || 161, -timeout => $opt_snmptimeout, -retries => 3, -debug => $g_snmpdebug, #-maxmsgsize => 16384, -maxmsgsize => 32768, -version => $opt_snmpvers, ); return ($snmp_session,$snmp_error); } sub create_msg { my ($l_txt,$l_msg)=@_; if (! defined $l_txt) {return}; if (defined $$l_msg) { $$l_msg.=", "; } $$l_msg.=$l_txt; } sub build_oid_table { my @l_oids; push @l_oids,$ClMibRevMajor_scalar; push @l_oids,$ClMibRevMinor_scalar; push @l_oids,$ClMibCondition_scalar; push @l_oids,$ClOsCommonPollFreq_scalar; push @l_oids,$ClName_scalar; push @l_oids,$ClCondition_scalar; push @l_oids,$ClIpAddress_scalar; push @l_oids,$ClQuorumResource_scalar; push @l_oids,$ClMajorVersion_scalar; push @l_oids,$ClMinorVersion_scalar; push @l_oids,$ClCSDVersion_scalar; push @l_oids,$ClVendorId_scalar; push @l_oids,$ClResourceAggregateCondition_scalar; push @l_oids,$ClNetworkAggregateCondition_scalar; return \@l_oids; } sub get_cluster_info_get_table_request { my ($l_oid)=@_; my $l_snmp_result=$snmp_session->get_table( -baseoid => $l_oid ); #if ( ! defined ($l_snmp_result)) { if ($snmp_session->error_status != 0) { printf ("ERROR %d: get_table_request: (%s) %s\n",$snmp_session->error_status,$l_oid,$snmp_session->error); $snmp_session->close; exit $ERRORS{'UNKNOWN'}; } return $l_snmp_result; } sub get_cluster_info_get_request { my ($l_oid)=@_; my $l_snmp_result=$snmp_session->get_request( -varbindlist => $l_oid, ); #if ( ! defined ($l_snmp_result)) { if ($snmp_session->error_status != 0) { print "ERROR %d get_request: ",$snmp_session->error_status,$snmp_session->error,"\n"; $snmp_session->close; exit $ERRORS{'UNKNOWN'}; } return $l_snmp_result; } sub check_args { Getopt::Long::Configure('bundling'); GetOptions ("V" => \$opt_version, "version" => \$opt_version, "L" => \$opt_license, "license" => \$opt_license, "v" => \$opt_verbose, "verbose" => \$opt_verbose, "D" => \$opt_snmpdebug, "debug" => \$opt_snmpdebug, "h|?" => \$opt_help, "help" => \$opt_help, "T=i" => \$opt_snmptimeout, "snmptimeout=i" => \$opt_snmptimeout, "t=i" => \$opt_timeout, "timeout=i" => \$opt_timeout, "H=s" => \$opt_hostname, "hostname=s" => \$opt_hostname, "o=s" => \$opt_pgo, "cgowner=s" => \$opt_pgo, "a=s" => \$opt_addhosts, "addnodes=s" => \$opt_addhosts, "C=s" => \$opt_community, "community=s" => \$opt_community, "p=i" => \$opt_port, "port=i" => \$opt_port, "s=s" => \$opt_snmpvers, "snmpvers=s" => \$opt_snmpvers, "Q" => \$opt_quorumdisk, "qudisk" => \$opt_quorumdisk, ); if ($opt_license) { print_gpl($PROGNAME,$REVISION); exit $ERRORS{'OK'}; } if ($opt_version) { print_revision($PROGNAME,$REVISION); exit $ERRORS{'OK'}; } if ($opt_help) { print_help(); exit $ERRORS{'OK'}; } if ( ! defined($opt_hostname)){ print "\nERROR: Hostname not defined\n\n"; print_usage(); exit $ERRORS{'UNKNOWN'}; } unless (defined $opt_snmpvers) { $opt_snmpvers = "snmpv2c"; } if ( ($opt_snmpvers ne "snmpv1") && ($opt_snmpvers ne "snmpv2c") ){ print "\nERROR: SNMP version unknown\n\n"; print_usage(); exit $ERRORS{'UNKNOWN'}; } unless (defined $opt_timeout) { $opt_timeout = $DEFAULT_TIMEOUT; } unless (defined $opt_snmptimeout) { $opt_snmptimeout = $DEFAULT_SNMPTIMEOUT; } unless (defined $opt_port) { $opt_port = 161; } if (defined $opt_pgo) { # Separation of DoubleSlash // my @l_hlp1=split(/\/\//,$opt_pgo); foreach my $l (@l_hlp1){ my ($l_node,$l_others)=split(/:/,$l); my @l_hlp2=split(/,/,$l_others); foreach my $g (@l_hlp2){ my @tmp=($l_node,$g); push @t_pgo,\@tmp; } } } unless (defined $opt_quorumdisk) { $opt_quorumdisk = 0; } if ($opt_snmpdebug) { $g_snmpdebug = DEBUG_ALL; }else{ $g_snmpdebug = DEBUG_NONE; } return $ERRORS{'OK'}; } sub print_usage { print "Usage: $PROGNAME [-h] [-L] [-Q] [-t timeout] [-T snmptimeout] [-v] [-V] [-C community] [-p port] [-s snmpv1|snmpv2c] [-a addhosts] [-o cgroupowner] -H hostname \n"; } sub print_help { print_revision($PROGNAME,$REVISION); print "\n"; print_usage(); print "\n"; print " Check Microsoft Cluster Server via SNMP\n"; print " using HP Managements Agents.\n\n"; print "-t (--timeout) Timeout in seconds (default = $DEFAULT_TIMEOUT)\n"; print "-T (--snmptimeout) SNMP CallTimeout in seconds (default = $DEFAULT_SNMPTIMEOUT)\n"; print "-H (--hostname) Host to monitor\n"; print "-a (--addhosts) additional hosts in clustergroup '-a host1,host2' \n"; print "-o (--cgowner) preferred clustergroup owner e.g: \n"; print " '-o 'node1:group1,group2//node2:group3,group4'\n"; print "-s (--snmpvers) SNMP Version [snmpv1|snmpv2c]\n"; print "-C (--community) SNMP Community\n"; print "-p (--port) SNMP Port\n"; print "-h (--help) Help\n"; print "-Q (--qudisk) Print information in message on which server QDisk is attached\n"; print "-V (--version) Programm version\n"; print "-v (--verbose) Print some useful information\n"; print "-L (--license) Print license information\n"; print "\n\n"; } sub print_Cluster_Info { printhead ("Cluster Info"); print ("============\n"); printscalar ("Cluster Name", $p_ClOids->{$ClName_scalar}); printscalar ("Cluster Condition", $ClCondition_val{$p_ClOids->{$ClCondition_scalar}}); printscalar ("Cluster IpAddress", $p_ClOids->{$ClIpAddress_scalar}); my $l_quorum=get_quorum_resource($p_ClOids->{$ClQuorumResource_scalar}); printscalar ("Cluster QuorumResource", $l_quorum); printscalar ("Cluster SW MajorVersion",$p_ClOids->{$ClMajorVersion_scalar}); printscalar ("Cluster SW MinorVersion",$p_ClOids->{$ClMinorVersion_scalar}); printscalar ("Cluster CSDVersion", $p_ClOids->{$ClCSDVersion_scalar}); printscalar ("Cluster VendorId", $p_ClOids->{$ClVendorId_scalar}); printscalar ("Cluster ResourceAggregateCondition", $ClResourceAggregateCondition_val{$p_ClOids->{$ClResourceAggregateCondition_scalar}}); printscalar ("Cluster NetworkAggregateCondition", $ClNetworkAggregateCondition_val{$p_ClOids->{$ClNetworkAggregateCondition_scalar}}); } sub get_quorum_holder { my ($l_index)=@_; my $l_quorum_holder=""; if ($l_index =~/^\d+$/) { if ($l_index >= 0) { $l_quorum_holder=$p_ClResourceTable->{$ClResourceOwnerNode_tabular.".".$l_index}; } } return ($l_quorum_holder); } sub get_quorum_resource { my ($l_index)=@_; my $l_quorum=""; if ($l_index =~/^\d+$/) { if ($l_index >= 0) { $l_quorum=$p_ClResourceTable->{$ClResourceName_tabular.".".$l_index}; } } return $l_quorum; } sub print_Cluster_MIB_Revision { printhead ("Cluster MIB Revision Group"); print ("==========================\n"); printscalar ("Cluster MibRevMajor", $p_ClOids->{$ClMibRevMajor_scalar}); printscalar ("Cluster MibRevMinor", $p_ClOids->{$ClMibRevMinor_scalar}); printscalar ("Cluster MibCondition", $ClMibCondition_val{$p_ClOids->{$ClMibCondition_scalar}}); } sub print_Cluster_OS_Common { printhead ("Cluster OS Common Group"); print ("=======================\n"); printscalar ("Os Poll Frequency in sec",$p_ClOids->{$ClOsCommonPollFreq_scalar}); printtable ("Cluster OS Common Module Table"); print ("==============================\n"); foreach my $l_key (oid_lex_sort(keys(%$p_ClOsCommonModuleTable))){ if (!(oid_base_match($ClOsCommonModuleIndex_tabular,$l_key))) { next; } my $l_val=$p_ClOsCommonModuleTable->{$l_key}; printtabular("Os Common Module Name", $p_ClOsCommonModuleTable->{$ClOsCommonModuleName_tabular.".".$l_val}); printtabular("Os Common Module Version", $p_ClOsCommonModuleTable->{$ClOsCommonModuleVersion_tabular.".".$l_val}); printtabular("Os Common Module Date", unpackDate($p_ClOsCommonModuleTable->{$ClOsCommonModuleDate_tabular.".".$l_val})); printtabular("Os Common Module Purpose", $p_ClOsCommonModuleTable->{$ClOsCommonModulePurpose_tabular.".".$l_val}); print ("\n"); } } sub print_Cluster_Node { printhead ("Cluster Node Group"); print ("==================\n"); printtable ("Cluster Node Table"); print ("==================\n"); foreach my $l_key (oid_lex_sort(keys(%$p_ClNodeTable))){ if (!(oid_base_match($ClNodeIndex_tabular,$l_key))) { next; } my $l_val=$p_ClNodeTable->{$l_key}; printtabular("Node Name", $p_ClNodeTable->{$ClNodeName_tabular.".".$l_val}); printtabular("Node Status", $ClNodeStatus_val{$p_ClNodeTable->{$ClNodeStatus_tabular.".".$l_val}}); printtabular("Node Condition",$ClNodeCondition_val{$p_ClNodeTable->{$ClNodeCondition_tabular.".".$l_val}}); print ("\n"); } } sub print_Cluster_Resource { printhead ("Cluster Resource Group"); print ("======================\n"); printtable ("Cluster Resource Table"); print ("======================\n"); foreach my $l_key (oid_lex_sort(keys(%$p_ClResourceTable))){ if (!(oid_base_match($ClResourceIndex_tabular,$l_key))) { next; } my $l_val=$p_ClResourceTable->{$l_key}; printtabular("Resource Name", $p_ClResourceTable->{$ClResourceName_tabular.".".$l_val}); printtabular("Resource Type", $p_ClResourceTable->{$ClResourceType_tabular.".".$l_val}); printtabular("Resource State", $ClResourceState_val{$p_ClResourceTable->{$ClResourceState_tabular.".".$l_val}}); printtabular("Resource Owner Node", $p_ClResourceTable->{$ClResourceOwnerNode_tabular.".".$l_val}); printtabular("Resource PhysId", $p_ClResourceTable->{$ClResourcePhysId_tabular.".".$l_val}); printtabular("Resource Condition", $ClResourceCondition_val{$p_ClResourceTable->{$ClResourceCondition_tabular.".".$l_val}}); printtabular("Resource Drive Letter", $p_ClResourceTable->{$ClResourceDriveLetter_tabular.".".$l_val}); printtabular("Resource Ip Address", $p_ClResourceTable->{$ClResourceIpAddress_tabular.".".$l_val}); printtabular("Resource Group Name", $p_ClResourceTable->{$ClResourceGroupName_tabular.".".$l_val}); print ("\n"); } } sub print_Cluster_Interconnect { printhead ("Cluster Interconnect Group"); print ("==========================\n"); printtable ("Cluster Interconnect Table"); print ("==========================\n"); foreach my $l_key (oid_lex_sort(keys(%$p_ClInterconnectTable))){ if (!(oid_base_match($ClInterconnectIndex_tabular,$l_key))) { next; } my $l_val=$p_ClInterconnectTable->{$l_key}; printtabular("Interconnect PhysId", $p_ClInterconnectTable->{$ClInterconnectPhysId_tabular.".".$l_val}); printtabular("Interconnect Transport", $p_ClInterconnectTable->{$ClInterconnectTransport_tabular.".".$l_val}); printtabular("Interconnect Address", $p_ClInterconnectTable->{$ClInterconnectAddress_tabular.".".$l_val}); printtabular("Interconnect Network Name",$p_ClInterconnectTable->{$ClInterconnectNetworkName_tabular.".".$l_val}); printtabular("Interconnect Node Name", $p_ClInterconnectTable->{$ClInterconnectNodeName_tabular.".".$l_val}); printtabular("Interconnect Role", $ClInterconnectRole_val{$p_ClInterconnectTable->{$ClInterconnectRole_tabular.".".$l_val}}); print ("\n"); } } sub print_Cluster_Network { printhead ("Cluster Network Group"); print ("=====================\n"); printtable ("Cluster Network Table"); print ("=====================\n"); foreach my $l_key (oid_lex_sort(keys(%$p_ClNetworkTable))){ if (!(oid_base_match($ClNetworkIndex_tabular,$l_key))) { next; } my $l_val=$p_ClNetworkTable->{$l_key}; printtabular("Network Name", $p_ClNetworkTable->{$ClNetworkName_tabular.".".$l_val}); printtabular("Network Address Mask",$p_ClNetworkTable->{$ClNetworkAddressMask_tabular.".".$l_val}); printtabular("Network Description", $p_ClNetworkTable->{$ClNetworkDescription_tabular.".".$l_val}); printtabular("Network Role", $ClNetworkRole_val{$p_ClNetworkTable->{$ClNetworkRole_tabular.".".$l_val}}); printtabular("Network State", $ClNetworkState_val{$p_ClNetworkTable->{$ClNetworkState_tabular.".".$l_val}}); printtabular("Network Condition", $ClNetworkCondition_val{$p_ClNetworkTable->{$ClNetworkCondition_tabular.".".$l_val}}); print ("\n"); } } sub printhead { my ($l_head)=@_; printf ("\n%-40s\n",$l_head); } sub printtable { my ($l_head)=@_; printf ("%-40s\n",$l_head); } sub printscalar { my ($l_arg,$l_oid)=@_; printf ("%-35s: %-30s\n",$l_arg,$l_oid); } sub printtabular { my ($l_arg,$l_oid)=@_; printf ("%-35s: %-30s\n",$l_arg,$l_oid); } sub unpackDate { my ($l_octet)=@_; # field octets contents range # ===== ====== ======= ===== # 1 1-2 year 0..65536 # 2 3 month 1..12 # 3 4 day 1..31 # 4 5 hour 0..23 # 5 6 minute 0..59 # 6 7 second 0..60 my @l_d=unpack("SCCCCC",$l_octet); if ( $l_d[0] == 0 ) { return ""; } my $l_rdate=sprintf("%04d-%02-%02d %02d:%02d:%02d",$l_d[0],$l_d[1],$l_d[2],$l_d[3],$l_d[4],$l_d[5]); return ($l_rdate); } sub print_gpl { print <. EOD } sub print_revision { my ($l_prog,$l_revision)=@_; print <{$l_key}; if ($ClNodeCondition_val{$p_ClNodeTable->{$ClNodeCondition_tabular.".".$l_val}} ne "ok" ) { if ( defined $l_txt ) { $l_txt.=", "; } $l_txt.=$p_ClNodeTable->{$ClNodeName_tabular.".".$l_val}.": ".$ClNodeStatus_val{$p_ClNodeTable->{$ClNodeStatus_tabular.".".$l_val}}; } } return $l_txt; } sub get_cluster_resource_status { my $l_txt; foreach my $l_key (oid_lex_sort(keys(%$p_ClResourceTable))){ if (!(oid_base_match($ClResourceIndex_tabular,$l_key))) { next; } my $l_val=$p_ClResourceTable->{$l_key}; if ( $ClResourceCondition_val{$p_ClResourceTable->{$ClResourceCondition_tabular.".".$l_val}} ne "ok" ) { if ( defined $l_txt ) { $l_txt.=", "; } $l_txt.=$p_ClResourceTable->{$ClResourceName_tabular.".".$l_val}.": ".$ClResourceState_val{$p_ClResourceTable->{$ClResourceState_tabular.".".$l_val}}; } } return $l_txt; } sub get_cluster_network_status { my $l_txt; foreach my $l_key (oid_lex_sort(keys(%$p_ClNetworkTable))){ if (!(oid_base_match($ClNetworkIndex_tabular,$l_key))) { next; } my $l_val=$p_ClNetworkTable->{$l_key}; if ($ClNetworkCondition_val{$p_ClNetworkTable->{$ClNetworkCondition_tabular.".".$l_val}} ne "ok" ) { if ( defined $l_txt ) { $l_txt.=", "; } $l_txt.=$p_ClNetworkTable->{$ClNetworkName_tabular.".".$l_val}.": ".$ClNetworkState_val{$p_ClNetworkTable->{$ClNetworkState_tabular.".".$l_val}}; } } return $l_txt; } sub get_GroupFailedOver_status { my $l_txt; my %h_pgo; foreach my $l_key (oid_lex_sort(keys(%$p_ClResourceTable))){ if (!(oid_base_match($ClResourceIndex_tabular,$l_key))) { next; } my $l_val=$p_ClResourceTable->{$l_key}; my $l_ro =$p_ClResourceTable->{$ClResourceOwnerNode_tabular.".".$l_val}; my $l_rg =$p_ClResourceTable->{$ClResourceGroupName_tabular.".".$l_val}; $h_pgo{$l_ro}{$l_rg}="dummy"; } foreach my $x (@t_pgo) { #print "$$x[0],$$x[1]\n"; # $$x[0] = owner node # $$x[1] = group name if (defined $h_pgo{$$x[0]}{$$x[1]}){ next; } else { if (defined $l_txt ) { $l_txt.=", "; } if ( ! defined $l_txt ) { $l_txt.="FailedOver: "; } $l_txt.=$$x[1]; } } return $l_txt; } #__END__ =head1 NAME check_mscs_hpma =head1 DESCRIPTION Checking Microsoft Cluster Server via SNMP protocol. HP Managements Agents have to be installed on the Server. Plugin created for Nagios Monitoring. =head1 SYNOPSIS check_mscs_hpma -H To check some additional hosts in the cluster group (in case of a server down of the primary node). check_mscs_hpma -H -a , To check if a cluster group is running on the preferred node, you can enter nodes with the defined groups: check_mscs_hpma -H -o "node1:group1,group2//node2:group3,group4" If group1 is not running on node1 a warning will be given to nagios. for more information call: check_mscs_hpma -h =head1 AUTHOR Herbert Stadler, Austria (hestadler@gmx.at) December 2007 This plugin is my contribution to the nagios community. =head1 REQUIRED SOFTWARE from search.cpan.org Net::SNMP Package e.g: Net-SNMP-5.2.0.tar.gz Used MIB (not necessary for executing the script) CPQCLUS1.MIB easy to find on "www.mibdepot.com" (enterprise compaq) =head1 HOW TO CHECK THE WINDOWS SERVER FUNCTIONALITY snmpwalk 172.29.130.201 -v2c -c public enterprises.232.15 should return a lot of lines like these: SNMPv2-SMI::enterprises.232.15.1.1.0 = INTEGER: 1 SNMPv2-SMI::enterprises.232.15.1.2.0 = INTEGER: 3 SNMPv2-SMI::enterprises.232.15.1.3.0 = INTEGER: 3 SNMPv2-SMI::enterprises.232.15.2.1.4.1.0 = INTEGER: 120 SNMPv2-SMI::enterprises.232.15.2.1.4.2.1.1.0 = INTEGER: 0 SNMPv2-SMI::enterprises.232.15.2.1.4.2.1.1.1 = INTEGER: 1 SNMPv2-SMI::enterprises.232.15.2.1.4.2.1.2.0 = STRING: "CPQCLUS.DLL" SNMPv2-SMI::enterprises.232.15.2.1.4.2.1.2.1 = STRING: "HOSTMIB.DLL" if not, check on windows server if "Clustering Information" is an "Active Agent". how can I check this ? Control Panel HP-Management Agents Clustering Information (in Active Agents) =head1 CONFIGURATION IN NAGIOS Copy this plugin to the nagios plugin installation directory e.g.: /usr/lib(64)/nagios/plugins COMMAND DEFINITION: # "check_mscs_hpma" command definition define command{ command_name check_mscs_hpma command_line $USER1$/check_mscs_hpma -H $HOSTADDRESS$ } # "check_mscs_hpma_a" command definition with additional cluster nodes define command{ command_name check_mscs_hpma_a command_line $USER1$/check_mscs_hpma -H $HOSTADDRESS$ -a $ARG1$ } # "check_mscs_hpma_ao" command definition with additional cluster nodes # and clustergroup checking # Please use apostrophes in case you have clustergroup definitions # with spaces (like "SQL Server Group") for option "-o" define command{ command_name check_mscs_hpma_a command_line $USER1$/check_mscs_hpma -H $HOSTADDRESS$ -a $ARG1$ -o "$ARG2" } =head1 PLUGIN HISTORY Version 1.8 - 2010-03-24 check error_status of snmp call Version 1.7 - 2009-08-31 Checking if Cluster is installed and running Version 1.6 - 2009-02-20 Debugging Parameter -D added Parameter -T added Version 1.5 - 2009-02-17 print OID in case of error function get_cluster_info_get_table_request Version 1.4 - 2008-11-26 show quorum disk holder (node) in message (flag -Q) additional library path added Version 1.3 - 2008-09-26 separation of parameters of -o option changed from ";" to "//" because ";" is start of comment under nagios control Version 1.2 - 2007-12-19 fixed problem with **ePN (Missing right curly or square ...) Version 1.1 - 2007-12-04 small changes in documentation Version 1.0 - 2007-12-01 first release =head1 COPYRIGHT AND DISCLAIMER Copyright (C) 2007 by Herbert Stadler email: hestadler@gmx.at License Information: This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . =cut