#!/opt/vdops/bin/perl # This script queries status variables in BLUEARC-SERVER-MIB and # produces a report identifying salient issues. # V Who When What # --------------------------------------------------------------------------- # 1.1.0 skendric 2010-01-10 Upgrade to perl 5.10.1 # 1.0.6 skendric 2009-04-19 Distinguish between silent and unresponsive # 1.0.5 skendric 2009-03-20 Add @down_for_maintenance # 1.0.4 skendric 2007-12-07 Add owner # 1.0.3 skendric 2007-06-07 Add clusterQuorumDeviceStatus # 1.0.2 skendric 2007-03-21 Stylistic mods # 1.0.1 skendric 2007-02-09 Add logging, separate storage into components # 1.0.0 skendric 2007-01-23 First Version # # Author: Stuart Kendrick, sbk {put at sign here} skendric {put dot here} com # # Source: http://www.skendric.com/device # # This software is available under the GNU GENERAL PUBLIC LICENSE, see # http://www.fsf.org/licenses/gpl.html # # # This script takes the following approach: # -Parses the hosts table for a list of targets (or accepts a command- # line list) # -Queries a bunch of BlueArc-specific variables # -Produces a report # # # Requirements: # -The target(s) must be pingable # # -PERL modules: the FHCRC::Netops collection # # # Assumptions: # # # Tested on: # -perl-5.10.1 # -net-snmp-5.5 # # # Instructions: # -Customize the script for your site: find the 'user-configurable # variables' section and modify as appropriate # -Type "bluearc-alarm" to see the command-line options # -Try it out # # # # Caveats: # # # Known Bugs: # # # To do: # # Begin script # Load modules use strict; use warnings; use feature 'say'; use feature 'switch'; use Carp qw(carp cluck croak confess); use Data::Dumper; use English qw( -no_match_vars ); use Getopt::Std; use List::MoreUtils qw(uniq); use FHCRC::Netops::HostTools 1.0.3; use FHCRC::Netops::NetopsTools 2.0.7; use FHCRC::Netops::NetopsData 1.3.0; use FHCRC::Netops::PingTools 1.1.5; use FHCRC::Netops::SNMPTools 1.3.9; use FHCRC::Netops::Utilities 1.3.9; # Declare global variables my %nic; # ifOperStatus my %temperature; # temperatureSensorStatus my %fan; # fanFittedStatus + fanSpeedStatus my %power; # psuStatus my %clusterQuorum; # clusterQuorumDeviceStatus my %clusterVNode; # clusterVNodeStatus my %sysDrive; # sysDriveStatus my %volume; # volumeStatus my @silent; # Targets which did not answer pings my @unresponsive; # Targets which did not answer SNMP GETs # Define global variables $debug = 0; # 10 = Logging # 9 = Database SELECT operations # 8 = Per IP/MAC/Port processing # 7 = Database INSERT/UPDATE/DELETE # 6 = Dump SNMP var # 5 = Dump snmp_packets # 4 = Grody: print big var # 3 = Verbose: print mid var # 2 = Simple: print small var # 1 = Basic: subroutine trace # 0 = Disable debugging $program_name = 'bluearc-alarm'; $usage = 'Usage: bluearc-alarm -s {yes|no} [-d {integer}] [-r] [-a | -e {expr} | -f {filename} | target1 target2 target3 ...]'; $version = '1.1.0'; # Define user-configurable variables # Binaries $grab_hosts = '/bin/cat /etc/hosts'; # Report stuff $institution = 'Widgets International'; $owner = 'Susan Way'; $owner_backup = 'Rick Bawaan'; $report_file = '/home/netops/rpts/bluearc-alarm.txt'; $report_queries = 'bsmith@widgets.com'; $report_recipients = 'it-server@fhcrc.org'; $report_subject = 'BlueArc Alarm Report'; # Pause parameters $long = 30; $mid = 10; $short = 5; # Ping Stuff $ping_count = 3; $ping_timeout = 1; # SNMP Stuff # Optimize performance by sorting your community strings and SNMP version # list, most frequently used to the left, least frequently used to the right @snmp_read_list = qw/public public/; @snmp_version_list = qw/2/; $snmp_port = 161; $snmp_retries = 3; $snmp_timeout = 2000000; # Syslog stuff $syslog_facility = 'local5'; $syslog_host = 'localhost'; $syslog_port = 514; $syslog_priority = 'info'; $syslog_socket = 'unix'; # Other possibilites include 'udp' and # 'stream'; depending on the flavor of Unix, # I've employed each of these # Target details @down_for_maintenance = qw//; @skip_name = qw/swamp/; @suffixes = qw/-bluearc/; # Grab arguments getopts('ad:e:f:rs:', \%option); @target = @ARGV; # Set mode if ($option{r}) { $mode = 'report' } elsif (-t STDIN) { $mode = 'interactive' } else { $mode = 'batch' } ### Begin Main Program ############################################### { check_args(); # Check arguments # compile_mibs(); # Compile MIB files build_target(); # Populate @target push @silent, target_check(); # Look for errors in @target push @unresponsive, basic_info(); # Gather information sanity_check(); # Check for major errors do_the_work(); # Do the work identify_alarms(); # Count devices with alarms print_report(); # Print report notify_staff(); # Mail report } ##### End Main Program ############################################### ######################################################################## # Do the work ######################################################################## sub do_the_work { my $answer; my $val; # Result of snmpGet/Walk # Debug trace trace_location('begin') if $debug; # Notify operator print_it('Querying targets...'); unless ($dome) { sleep $short; return 1; } # Loop through targets TARGET: for my $target (@target) { # Walk ifOperStatus say 'Walking ifOperStatus' if $debug > 3; $val = snmpWalk( {host => $target, oid => 'ifOperStatus'} ); $answer = 'ok'; for my $varbind (@$val) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; log_it("$target ifOperStatus.$iid = $val"); $answer = 'bad' unless $val eq 'up'; } $alarm_count{$target}++ unless $answer eq 'ok'; $nic{$target} = $answer; # Walk temperatureSensorStatus say 'Walking temperatureSensorStatus' if $debug > 3; $val = snmpWalk( {host => $target, oid => 'temperatureSensorStatus'} ); $answer = 'ok'; for my $varbind (@$val) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; log_it("$target temperatureSensorStatus.$iid = $val"); $answer = 'bad' unless $val eq 'ok'; } $alarm_count{$target}++ if $answer eq 'bad'; $temperature{$target} = $answer; # Walk fanFittedStatus say 'Walking fanFittedStatus' if $debug > 3; $val = snmpWalk( {host => $target, oid => 'fanFittedStatus'} ); $answer = 'ok'; for my $varbind (@$val) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; log_it("$target fanFittedStatus.$iid = $val"); $answer = 'bad' unless $val eq 'ok'; } $alarm_count{$target}++ if $answer eq 'bad'; $fan{$target} = $answer; # Walk fanSpeedStatus unless ($fan{$target} eq 'bad') { say 'Walking fanSpeedStatus' if $debug > 3; $val = snmpWalk( {host => $target, oid => 'fanSpeedStatus'} ); $answer = 'ok'; for my $varbind (@$val) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; log_it("$target fanSpeedStatus.$iid = $val"); $answer = 'bad' unless $val eq 'ok'; } $alarm_count{$target}++ if $answer eq 'bad'; $fan{$target} = $answer; } # Walk psuStatus say 'Walking psuStatus' if $debug > 3; $val = snmpWalk( {host => $target, oid => 'psuStatus'} ); $answer = 'ok'; for my $varbind (@$val) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; log_it("$target psuStatus.$iid = $val"); $answer = 'bad' unless $val eq 'ok'; } $alarm_count{$target}++ if $answer eq 'bad'; $power{$target} = $answer; # Walk clusterVNodeStatus say 'Walking clusterVNodeStatus' if $debug > 3; $val = snmpWalk( {host => $target, oid => 'clusterVNodeStatus'} ); $answer = 'ok'; for my $varbind (@$val) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; log_it("$target clusterVNodeStatus.$iid = $val"); $answer = 'bad' unless $val eq 'onLine'; } $alarm_count{$target}++ if $answer eq 'bad'; $clusterVNode{$target} = $answer; # Get clusterQuorumDeviceStatus say 'Getting clusterQuorumDeviceStatus' if $debug > 3; $val = snmpGet( {host => $target, oid => 'clusterQuorumDeviceStatus.0'} ); given ($val) { when ('owned') { $answer = 'ok' } default { $answer = 'bad' } } $alarm_count{$target}++ unless $answer eq 'ok'; $clusterQuorum{$target} = $answer; # Walk sysDriveStatus say 'Walking sysDriveStatus' if $debug > 3; $val = snmpWalk( {host => $target, oid => 'sysDriveStatus'} ); $answer = 'ok'; for my $varbind (@$val) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; log_it("$target sysDriveStatus.$iid = $val"); $answer = 'bad' unless $val eq 'online'; } $alarm_count{$target}++ if $answer eq 'bad'; $sysDrive{$target} = $answer; # Walk volumeStatus say 'Walking volumeStatus' if $debug > 3; $val = snmpWalk( {host => $target, oid => 'volumeStatus'} ); $answer = 'ok'; for my $varbind (@$val) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; log_it("$target volumeStatus.$iid = $val"); $answer = 'bad' unless $val eq 'mounted'; } $alarm_count{$target}++ if $answer eq 'bad'; $volume{$target} = $answer; # Entertain operator print $BANG if $mode eq 'interactive'; } # Debug info if ($debug > 2) { for my $target (@target) { if ($alarm_count{$target} > 0) { say "alarm_count{$target} = $alarm_count{$target}"; } } } # Make things look pretty say "\n" if $mode eq 'interactive'; # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Tell the operator what I discovered ######################################################################## sub print_report { my $handle; my $total = @target; my $now = get_now(); # If we are running in test mode, skip this routine unless ($dome) { print_it("Running in test mode, cannot print a meaningful report\n"); return 1; } # Debug trace trace_location('begin') if $debug; # Direct output to screen or to file if ($mode eq 'interactive') { $handle = *STDOUT; } else { open $handle, '>', $report_file or die "Cannot open $report_file: $!\n"; } print {$handle} < 0) { @silent = sort @silent; for my $silent (@silent) { printf {$handle} "%-15s Not answering pings\n", $silent; } } # Add unresponsive devices to the report if (@unresponsive > 0) { @unresponsive = sort @unresponsive; for my $unresponsive (@unresponsive) { printf {$handle} "%-15s Not answering SNMP GETs\n", $unresponsive; } } # Clean up unless ($handle =~ /STDOUT/) { close $handle or warn "Cannot close $report_file: $!\n"; } # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Sanity check ######################################################################## sub sanity_check { my @remove; # Debug trace trace_location('begin') if $debug; # Notify operator print_it('Sanity check...'); # Loop through targets, removing non-BlueArc devices SANITY: for my $target (@target) { # Identify manufacturer unless ($manufacturer{$target} eq 'BlueArc') { say "\nManufacturer of $target is not BlueArc, ignoring" if $debug; push @remove, $target; next SANITY; } # Entertain operator print $BANG if $mode eq 'interactive'; } # Remove entries which failed checks prune_basic(@remove); # Make things look pretty say "\n" if $mode eq 'interactive'; # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Output help ######################################################################## sub HELP_MESSAGE { print <