shanepresley
asked on
Problem with (someone else's) Perl code...
Hello,
I am using a monitoring package called BigBrother (written in C I think). Anyway, one of the Open Source add-ons is written in Perl. Basically this perl script uses Net::SNMP to get some stats from Cisco devices, check the results, and return a status to the BigBrother server. Forgetting the BigBrother part, all this script does is check the SNMP values, and execute a command that reports the status.
Status for BigBrother is based on color...
Red = Bad
Yellow = Warning
Green = OK
Clear = No results
As an example, this script will check the fans on a Cisco Router. If all the fans return OK, then the result is green. Another example, it will check the power supplies. If all the power supplies are OK, it returns green.
Here's the problem. The code checks each power supply, then looks for the "worst color". So if one power supply is bad, and three more are green, the overall alert should be red.
Something is wrong with this routine. It's returning green, even when one power supply is red.
This is someone else's code, and I tried to get in touch with them, but have gotten no answers. Could anyone take a look at the code and see if you can find a problem. I'll post the code below...
Thanks!
Shane
I am using a monitoring package called BigBrother (written in C I think). Anyway, one of the Open Source add-ons is written in Perl. Basically this perl script uses Net::SNMP to get some stats from Cisco devices, check the results, and return a status to the BigBrother server. Forgetting the BigBrother part, all this script does is check the SNMP values, and execute a command that reports the status.
Status for BigBrother is based on color...
Red = Bad
Yellow = Warning
Green = OK
Clear = No results
As an example, this script will check the fans on a Cisco Router. If all the fans return OK, then the result is green. Another example, it will check the power supplies. If all the power supplies are OK, it returns green.
Here's the problem. The code checks each power supply, then looks for the "worst color". So if one power supply is bad, and three more are green, the overall alert should be red.
Something is wrong with this routine. It's returning green, even when one power supply is red.
This is someone else's code, and I tried to get in touch with them, but have gotten no answers. Could anyone take a look at the code and see if you can find a problem. I'll post the code below...
Thanks!
Shane
ASKER
Here's the results when I run this script, with one bad power supply. Note the condition is GREEN (rtr.domain.com.power green) but should be RED, since three devices are RED
"
/usr/local/bb/bb/bin/bb-co mbo.sh add "status rtr.domain.com.power green Wed Apr 20 12:46:51 2005
&green Power Supply 1 1, source: ac, state: normal
&red Power Supply 2 2, source: ac, state: critical
&red Power Supply 3 3, source: unknown, state: notPresent
&red Power Supply 4 4, source: unknown, state: notPresent
<!-- Enterprise: cisco , Version: 12.3113 -->
"
/usr/local/bb/bb/bin/bb-co
&green Power Supply 1 1, source: ac, state: normal
&red Power Supply 2 2, source: ac, state: critical
&red Power Supply 3 3, source: unknown, state: notPresent
&red Power Supply 4 4, source: unknown, state: notPresent
<!-- Enterprise: cisco , Version: 12.3113 -->
his line seems to be the problem:
my $worstcolor = ($fancount > 0) ? 'red' : 'green';
Is it supposed to sit inside the netapp enterprise if statement?
As it sits now, it is executed for all enterprises, but is $fancount isn't set in the cisco or foundry sections so $fancount <0 which sets $worstcolor to green.
my $worstcolor = ($fancount > 0) ? 'red' : 'green';
Is it supposed to sit inside the netapp enterprise if statement?
As it sits now, it is executed for all enterprises, but is $fancount isn't set in the cisco or foundry sections so $fancount <0 which sets $worstcolor to green.
ASKER
Hmm, that sounds like it might be on the right track. But the problem of the incorrect $worstcolor affects more than just fans? But I tried commenting that line
out, and it failed with compile errors.
bb-xsnmp.pl Global symbol "$worstcolor" requires explicit package name at /usr/local/bb/bb/ext/bb-xs nmp.pl
So any suggestions what to change that line to? I thought the problem might be in &color_compare, but my Perl knowledge is very limited :)
Thanks
out, and it failed with compile errors.
bb-xsnmp.pl Global symbol "$worstcolor" requires explicit package name at /usr/local/bb/bb/ext/bb-xs
So any suggestions what to change that line to? I thought the problem might be in &color_compare, but my Perl knowledge is very limited :)
Thanks
I was wrong. That worstcolor line *is* within the netapp function only so it's not the problem.
I'll look again at the color_compare routine when I get a chance...
I'll look again at the color_compare routine when I get a chance...
ASKER
I think the problem is somewhere here...
# determine colors
my %powercolors = ();
while (my($index,$state) = each(%statedb)) {
if ($state eq 'normal') {
$powercolors{$index} = 'green';
} elsif ($state eq 'notPresent') {
$powercolors{$index} = 'clear';
} elsif ($state eq 'warning') {
$powercolors{$index} = 'yellow';
} else {
$powercolors{$index} = 'red';
}
} # while (my($index,$state) = each(%statedb))
# find worst color
my $worstcolor = &color_compare(values(%sta tedb));
When I do some debug inside the &color_compare routine, the values getting passed into it are "normal, critical, notPresent". The values should
be "red" or "green" etc.
# determine colors
my %powercolors = ();
while (my($index,$state) = each(%statedb)) {
if ($state eq 'normal') {
$powercolors{$index} = 'green';
} elsif ($state eq 'notPresent') {
$powercolors{$index} = 'clear';
} elsif ($state eq 'warning') {
$powercolors{$index} = 'yellow';
} else {
$powercolors{$index} = 'red';
}
} # while (my($index,$state) = each(%statedb))
# find worst color
my $worstcolor = &color_compare(values(%sta
When I do some debug inside the &color_compare routine, the values getting passed into it are "normal, critical, notPresent". The values should
be "red" or "green" etc.
ASKER
Yea...got it. This line was wrong...
my $worstcolor = &color_compare(values(%sta tedb));
It should have been passing in powercolors. Correct line is
my $worstcolor = &color_compare(values(%pow ercolors)) ;
my $worstcolor = &color_compare(values(%sta
It should have been passing in powercolors. Correct line is
my $worstcolor = &color_compare(values(%pow
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Not all, just power and one other. I just threw in some debug print statements, and saw that inside color_compare,
it was seeing "critical" or "normal" instead of what it was looking for...red, green, etc.
Anyway, thanks for the help. I'll hand over the points since you spent some time. THanks again!
Shane
it was seeing "critical" or "normal" instead of what it was looking for...red, green, etc.
Anyway, thanks for the help. I'll hand over the points since you spent some time. THanks again!
Shane
Thanks! Good luck with this...
ASKER
#!/usr/local/bin/perl
# Monolithic SNMP gatherer for BigBrother.
use strict;
use Carp;
use FileHandle;
use FindBin qw($Bin $Script);
use Net::SNMP qw(:snmp);
use vars qw($VERSION);
( $VERSION ) = '$Revision: 1.77 $' =~ /\$Revision:\s+([^\s]+)/;
my $debug = $ENV{'DEBUG'};
our $is_commandline = 0; # &env_check sets it to true if it looks like
# I was not called by BigBrother.
# In this case, I assume I'm testing and
# print to stdout instead of
# sending to BB.
my $defbbtmp = '/tmp';
my $defbbhome = '/usr/local/bb/bb';
my $defbb = "$defbbhome/bin/bb";
my $defbbdisp = '127.0.0.1';
my $defmachine = 'localhost';
# For SNMP
my $defretries = 3;
my $deftimeout = 5;
my %snmpoids = (
'sysDescr' => '.1.3.6.1.2.1.1.1.0',
'sysObjectID' => '.1.3.6.1.2.1.1.2.0',
'sysUpTime' => '.1.3.6.1.2.1.1.3.0',
'sysName' => '.1.3.6.1.2.1.1.5.0',
'ifDescr' => '.1.3.6.1.2.1.2.2.1.2',
'ifSpeed' => '.1.3.6.1.2.1.2.2.1.5',
'ifOperStatus' => '.1.3.6.1.2.1.2.2.1.8',
'tcp' => '.1.3.6.1.2.1.6',
'tcpCurrEstab' => '.1.3.6.1.2.1.6.9',
'tcpConnRemAddress' => '.1.3.6.1.2.1.6.13.1.4',
'bgpLocalAs' => '.1.3.6.1.2.1.15.2.0',
'bgpPeerState' => '.1.3.6.1.2.1.15.3.1.2',
'bgpPeerAdminStatus' => '.1.3.6.1.2.1.15.3.1.2',
'bgpPeerRemoteAs' => '.1.3.6.1.2.1.15.3.1.9',
'bgpPeerFsmEstablishedTime
# hrStorage used mostly by the UCD/NET daemon
# Memory and disk information are stored in the same tree
# UCD/NET also uses separate dskTable and memory tables
'host' => '.1.3.6.1.2.1.25',
'hrStorage' => '.1.3.6.1.2.1.25.2',
'hrStorageTypes' => '.1.3.6.1.2.1.25.2.1',
'hrStorageOther' => '.1.3.6.1.2.1.25.2.1.1',
'hrStorageRam' => '.1.3.6.1.2.1.25.2.1.2',
'hrStorageVirtualMemory' => '.1.3.6.1.2.1.25.2.1.3',
'hrStorageFixedDisk' => '.1.3.6.1.2.1.25.2.1.4',
'hrStorageRemovableDisk' => '.1.3.6.1.2.1.25.2.1.5',
'hrStorageFloppyDisk' => '.1.3.6.1.2.1.25.2.1.6',
'hrStorageCompactDisc' => '.1.3.6.1.2.1.25.2.1.7',
'hrStorageRamDisk' => '.1.3.6.1.2.1.25.2.1.8',
'hrStorageFlashMemory' => '.1.3.6.1.2.1.25.2.1.9',
'hrStorageNetworkDisk' => '.1.3.6.1.2.1.25.2.1.10',
'hrStorageEntry' => '.1.3.6.1.2.1.25.2.3.1',
'hrStorageType' => '.1.3.6.1.2.1.25.2.3.1.2',
'hrStorageDescr' => '.1.3.6.1.2.1.25.2.3.1.3',
'hrStorageAllocationUnits'
'hrStorageSize' => '.1.3.6.1.2.1.25.2.3.1.5',
'hrStorageUsed' => '.1.3.6.1.2.1.25.2.3.1.6',
'ifXEntry' => '.1.3.6.1.2.1.31.1.1.1',
'ifAlias' => '.1.3.6.1.2.1.31.1.1.1.18'
'enterprises' => '.1.3.6.1.4.1',
'cisco' => '.1.3.6.1.4.1.9',
'busyPer' => '.1.3.6.1.4.1.9.2.1.56.0',
'avgBusy1' => '.1.3.6.1.4.1.9.2.1.57.0',
'avgBusy5' => '.1.3.6.1.4.1.9.2.1.58.0',
'ciscoEnvMonTemperatureSta
'ciscoEnvMonTemperatureSta
'ciscoEnvMonTemperatureSta
'ciscoEnvMonTemperatureSta
'ciscoEnvMonTemperatureThr
'ciscoEnvMonTemperatureLas
'ciscoEnvMonTemperatureSta
'ciscoEnvMonFanStatusDescr
'ciscoEnvMonFanState' => '.1.3.6.1.4.1.9.9.13.1.4.1
'ciscoEnvMonSupplyStatusDe
'ciscoEnvMonSupplyState' => '.1.3.6.1.4.1.9.9.13.1.5.1
'ciscoEnvMonSupplySource' => '.1.3.6.1.4.1.9.9.13.1.5.1
'ciscoMemoryPoolMIB' => '.1.3.6.1.4.1.9.9.48',
'ciscoMemoryPoolObjects' => '.1.3.6.1.4.1.9.9.48.1',
'ciscoMemoryPoolTable' => '.1.3.6.1.4.1.9.9.48.1.1',
'ciscoMemoryPoolEntry' => '.1.3.6.1.4.1.9.9.48.1.1.1
'ciscoMemoryPoolType' => '.1.3.6.1.4.1.9.9.48.1.1.1
'ciscoMemoryPoolName' => '.1.3.6.1.4.1.9.9.48.1.1.1
'ciscoMemoryPoolAlternate'
'ciscoMemoryPoolValid' => '.1.3.6.1.4.1.9.9.48.1.1.1
'ciscoMemoryPoolUsed' => '.1.3.6.1.4.1.9.9.48.1.1.1
'ciscoMemoryPoolFree' => '.1.3.6.1.4.1.9.9.48.1.1.1
'ciscoMemoryPoolLargestFre
'c2900PortIfIndex' => '.1.3.6.1.4.1.9.9.87.1.4.1
'c2900PortDuplexState' => '.1.3.6.1.4.1.9.9.87.1.4.1
'c2900PortDuplexStatus' => '.1.3.6.1.4.1.9.9.87.1.4.1
'c2900PortAdminSpeed' => '.1.3.6.1.4.1.9.9.87.1.4.1
'ciscoProcessMIB' => '.1.3.6.1.4.1.9.9.109',
'cpmCPUTotal5sec' => '.1.3.6.1.4.1.9.9.109.1.1.
'cpmCPUTotal1min' => '.1.3.6.1.4.1.9.9.109.1.1.
'cpmCPUTotal5min' => '.1.3.6.1.4.1.9.9.109.1.1.
'cpmProcess' => '.1.3.6.1.4.1.9.9.109.1.2'
'cpmProcessEntry' => '.1.3.6.1.4.1.9.9.109.1.2.
'cpmProcessName' => '.1.3.6.1.4.1.9.9.109.1.2.
'cpmProcessuSecs' => '.1.3.6.1.4.1.9.9.109.1.2.
'cpmProcessAverageUSecs' => '.1.3.6.1.4.1.9.9.109.1.2.
'cpmProcessExtEntry' => '.1.3.6.1.4.1.9.9.109.1.2.
'cpmProcExtPriority' => '.1.3.6.1.4.1.9.9.109.1.2.
'cpmProcessExtRevEntry' => '.1.3.6.1.4.1.9.9.109.1.2.
'cpmProcExtPriorityRev' => '.1.3.6.1.4.1.9.9.109.1.2.
'ciscoFirewallMIB' => '.1.3.6.1.4.1.9.9.147',
'cfwHardwareStatusValue' => '.1.3.6.1.4.1.9.9.147.1.2.
'cfwHardwareStatusDetail' => '.1.3.6.1.4.1.9.9.147.1.2.
'cfwBufferStatValue' => '.1.3.6.1.4.1.9.9.147.1.2.
'cfwConnectionStatValue' => '.1.3.6.1.4.1.9.9.147.1.2.
# Original extension by Craig Cook uses things like cpqHoCpuUtilMin.0
# even though CPU items are in a table and table entries usually don't
# get a zero stuck at the end. I don't have a Compaq to test so I must
# be careful, prepare for both possibilities with Compaq items.
'compaq' => '.1.3.6.1.4.1.232',
'cpqHeCorrMemLogStatus' => '.1.3.6.1.4.1.232.6.2.3.1.
'cpqHeCorrMemTotalErrs' => '.1.3.6.1.4.1.232.6.2.3.3.
'cpqHeCorrMemErrorCntThres
'cpqHeThermalCondition' => '.1.3.6.1.4.1.232.6.2.6.1.
'cpqHeThermalTempStatus' => '.1.3.6.1.4.1.232.6.2.6.3.
'cpqHeThermalSystemFanStat
'cpqHeThermalCpuFanStatus'
'cpqHeTemperatureIndex' => '.1.3.6.1.4.1.232.6.2.6.8.
'cpqHeTemperatureLocale' => '.1.3.6.1.4.1.232.6.2.6.8.
'cpqHeTemperatureCelsius' => '.1.3.6.1.4.1.232.6.2.6.8.
'cpqHeTemperatureThreshold
'cpqHeTemperatureCondition
'cpqHeEventLogSupported' => '.1.3.6.1.4.1.232.6.2.11.1
'cpqHeEventLogCondition' => '.1.3.6.1.4.1.232.6.2.11.2
'cpqHeEventLogEntry' => '.1.3.6.1.4.1.232.6.2.11.3
'cpqHeEventLogEntryNumber'
'cpqHeEventLogEntrySeverit
'cpqHeEventLogEntryCount' => '.1.3.6.1.4.1.232.6.2.11.3
'cpqHeEventLogInitialTime'
'cpqHeEventLogUpdateTime' => '.1.3.6.1.4.1.232.6.2.11.3
'cpqHeEventLogErrorDesc' => '.1.3.6.1.4.1.232.6.2.11.3
'cpqHeEventLogFreeFormData
'cpqHostOs' => '.1.3.6.1.4.1.232.11',
'cpqHoCpuUtilEntry' => '.1.3.6.1.4.1.232.11.2.3.1
'cpqHoCpuUtilMin' => '.1.3.6.1.4.1.232.11.2.3.1
'cpqHoCpuUtilFiveMin' => '.1.3.6.1.4.1.232.11.2.3.1
'cpqHoCpuUtilThirtyMin' => '.1.3.6.1.4.1.232.11.2.3.1
'cpqHoCpuUtilHour' => '.1.3.6.1.4.1.232.11.2.3.1
'cpqHoFileSysEntry' => '.1.3.6.1.4.1.232.11.2.4.1
'cpqHoFileSysIndex' => '.1.3.6.1.4.1.232.11.2.4.1
'cpqHoFileSysDesc' => '.1.3.6.1.4.1.232.11.2.4.1
'cpqHoFileSysSpaceTotal' => '.1.3.6.1.4.1.232.11.2.4.1
'cpqHoFileSysSpaceUsed' => '.1.3.6.1.4.1.232.11.2.4.1
'cpqHoFileSysPercentSpaceU
'cpqHoFileSysAllocUnitsTot
'cpqHoFileSysAllocUnitsUse
'cpqHoPhysicalMemorySize' => '.1.3.6.1.4.1.232.11.2.13.
'cpqHoPhysicalMemoryFree' => '.1.3.6.1.4.1.232.11.2.13.
'cpqHoPagingMemorySize' => '.1.3.6.1.4.1.232.11.2.13.
'cpqHoPagingMemoryFree' => '.1.3.6.1.4.1.232.11.2.13.
'upsBasicIdentModel' => '.1.3.6.1.4.1.318.1.1.1.1.
'upsBasicBatteryStatus' => '.1.3.6.1.4.1.318.1.1.1.2.
'upsBasicBatteryTimeOnBatt
'upsAdvBatteryCapacity' => '.1.3.6.1.4.1.318.1.1.1.2.
'upsAdvBatteryTemperature'
'upsAdvBatteryRunTimeRemai
'upsAdvBatteryReplaceIndic
'upsAdvInputLineVoltage' => '.1.3.6.1.4.1.318.1.1.1.3.
'upsAdvInputLineFailCause'
'upsBasicOutputStatus' => '.1.3.6.1.4.1.318.1.1.1.4.
'upsAdvOutputVoltage' => '.1.3.6.1.4.1.318.1.1.1.4.
'upsAdvOutputLoad' => '.1.3.6.1.4.1.318.1.1.1.4.
'upsBasicBatteryLastReplac
'netapp' => '.1.3.6.1.4.1.789',
'miscNfsOps' => '.1.3.6.1.4.1.789.1.2.2.1.
'miscNetRcvdKB' => '.1.3.6.1.4.1.789.1.2.2.2.
'miscNetSentKB' => '.1.3.6.1.4.1.789.1.2.2.3.
'miscGlobalStatus' => '.1.3.6.1.4.1.789.1.2.2.4.
'miscHighNfsOps' => '.1.3.6.1.4.1.789.1.2.2.5.
'miscLowNfsOps' => '.1.3.6.1.4.1.789.1.2.2.6.
'miscHighNetRcvdBytes' => '.1.3.6.1.4.1.789.1.2.2.11
'miscLowNetRcvdBytes' => '.1.3.6.1.4.1.789.1.2.2.12
'miscHighNetSentBytes' => '.1.3.6.1.4.1.789.1.2.2.13
'miscLowNetSentBytes' => '.1.3.6.1.4.1.789.1.2.2.14
'envOverTemperature' => '.1.3.6.1.4.1.789.1.2.4.1.
'envFailedFanCount' => '.1.3.6.1.4.1.789.1.2.4.2.
'envFailedFanMessage' => '.1.3.6.1.4.1.789.1.2.4.3.
'envFailedPowerSupplyCount
'envFailedPowerSupplyMessa
'cpuBusyTime' => '.1.3.6.1.4.1.789.1.2.1.2.
'cpuBusyTimePerCent' => '.1.3.6.1.4.1.789.1.2.1.3.
'cpuIdleTimePerCent' => '.1.3.6.1.4.1.789.1.2.1.5.
'qrEntry' => '.1.3.6.1.4.1.789.1.4.3.1'
'qrIndex' => '.1.3.6.1.4.1.789.1.4.3.1.
'qrType' => '.1.3.6.1.4.1.789.1.4.3.1.
'qrId' => '.1.3.6.1.4.1.789.1.4.3.1.
'qrKBytesUsed' => '.1.3.6.1.4.1.789.1.4.3.1.
'qrKBytesLimit' => '.1.3.6.1.4.1.789.1.4.3.1.
'qrFilesUsed' => '.1.3.6.1.4.1.789.1.4.3.1.
'qrFileLimit' => '.1.3.6.1.4.1.789.1.4.3.1.
'qrPathName' => '.1.3.6.1.4.1.789.1.4.3.1.
'dfEntry' => '.1.3.6.1.4.1.789.1.5.4.1'
'dfIndex' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfFileSys' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfKBytesTotal' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfKBytesUsed' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfKBytesAvail' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfPerCentKBytesCapacity' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfInodesUsed' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfInodesFree' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfPerCentInodeCapacity' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfMountedOn' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfMaxFilesAvail' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfMaxFilesUsed' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfMaxFilesPossible' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfHighTotalKBytes' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfLowTotalKBytes' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfHighUsedKBytes' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfLowUsedKBytes' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfHighAvailKBytes' => '.1.3.6.1.4.1.789.1.5.4.1.
'dfLowAvailKBytes' => '.1.3.6.1.4.1.789.1.5.4.1.
'foundry' => '.1.3.6.1.4.1.1991',
'snChasActualTemperature' => '.1.3.6.1.4.1.1991.1.1.1.1
'snChasWarningTemperature'
'snChasShutdownTemperature
'snChasPwrSupplyDescriptio
'snChasPwrSupplyOperStatus
'snChasFanDescription' => '.1.3.6.1.4.1.1991.1.1.1.3
'snChasFanOperStatus' => '.1.3.6.1.4.1.1991.1.1.1.3
'snAgGblCpuUtilData' => '.1.3.6.1.4.1.1991.1.1.2.1
'snAgGblCpuUtil1SecAvg' => '.1.3.6.1.4.1.1991.1.1.2.1
'snAgGblCpuUtil5SecAvg' => '.1.3.6.1.4.1.1991.1.1.2.1
'snAgGblCpuUtil1MinAvg' => '.1.3.6.1.4.1.1991.1.1.2.1
'snAgGblDynMemUtil' => '.1.3.6.1.4.1.1991.1.1.2.1
'snAgGblDynMemTotal' => '.1.3.6.1.4.1.1991.1.1.2.1
'snAgGblDynMemFree' => '.1.3.6.1.4.1.1991.1.1.2.1
'snSwPortInfoChnMode' => '.1.3.6.1.4.1.1991.1.1.3.3
'snSwPortInfoSpeed' => '.1.3.6.1.4.1.1991.1.1.3.3
'snSwPortName' => '.1.3.6.1.4.1.1991.1.1.3.3
'snSwPortIfIndex' => '.1.3.6.1.4.1.1991.1.1.3.3
'snL4VirtualServerIndex' => '.1.3.6.1.4.1.1991.1.1.4.2
'snL4VirtualServerName' => '.1.3.6.1.4.1.1991.1.1.4.2
'snL4VirtualServerVirtualI
'snL4VirtualServerAdminSta
'snL4RealServerIndex' => '.1.3.6.1.4.1.1991.1.1.4.3
'snL4RealServerName' => '.1.3.6.1.4.1.1991.1.1.4.3
'snL4RealServerIP' => '.1.3.6.1.4.1.1991.1.1.4.3
'snL4RealServerAdminStatus
'snL4VirtualServerPortInde
'snL4VirtualServerPortServ
'snL4VirtualServerPortPort
'snL4VirtualServerPortAdmi
'snL4RealServerPortIndex' => '.1.3.6.1.4.1.1991.1.1.4.5
'snL4RealServerPortServerN
'snL4RealServerPortPort' => '.1.3.6.1.4.1.1991.1.1.4.5
'snL4RealServerPortAdminSt
'snL4RealServerStatusIndex
'snL4RealServerStatusName'
'snL4RealServerStatusState
'snL4RealServerPortStatusI
'snL4RealServerPortStatusP
'snL4RealServerPortStatusS
'snL4RealServerPortStatusS
'snL4BindIndex' => '.1.3.6.1.4.1.1991.1.1.4.6
'snL4BindVirtualServerName
'snL4BindVirtualPortNumber
'snL4BindRealServerName' => '.1.3.6.1.4.1.1991.1.1.4.6
'snL4BindRealPortNumber' => '.1.3.6.1.4.1.1991.1.1.4.6
'snBgp4GenLocalAs' => '.1.3.6.1.4.1.1991.1.2.11.
'snBgp4NeighGenCfgNeighIp'
'snBgp4NeighGenCfgRemoteAs
'snBgp4NeighGenCfgShutdown
'snBgp4NeighGenCfgDesc' => '.1.3.6.1.4.1.1991.1.2.11.
'snBgp4NeighOperStatusInde
'snBgp4NeighOperStatusIp' => '.1.3.6.1.4.1.1991.1.2.11.
'snBgp4NeighOperStatusRemo
'snBgp4NeighOperStatusBgpT
'snBgp4NeighOperStatusStat
'snBgp4NeighborSummaryInde
'snBgp4NeighborSummaryIp' => '.1.3.6.1.4.1.1991.1.2.11.
'snBgp4NeighborSummaryStat
'snBgp4NeighborSummaryStat
'snSI' => '.1.3.6.1.4.1.1991.1.3.3.1
'snSIXL' => '.1.3.6.1.4.1.1991.1.3.3.2
# The UCD/NET-SNMP daemon uses many items in the mib-2.host branch
'ucdavis' => '.1.3.6.1.4.1.2021',
'dskEntry' => '.1.3.6.1.4.1.2021.9.1',
'dskPath' => '.1.3.6.1.4.1.2021.9.1.2',
'dskDevice' => '.1.3.6.1.4.1.2021.9.1.3',
'dskTotal' => '.1.3.6.1.4.1.2021.9.1.6',
'dskAvail' => '.1.3.6.1.4.1.2021.9.1.7',
'dskUsed' => '.1.3.6.1.4.1.2021.9.1.8',
'dskPercent' => '.1.3.6.1.4.1.2021.9.1.9',
'dskPercentInode' => '.1.3.6.1.4.1.2021.9.1.10'
'laLoadFloat' => '.1.3.6.1.4.1.2021.10.1.6'
'laLoadFloat.1' => '.1.3.6.1.4.1.2021.10.1.6.
'laLoadFloat.2' => '.1.3.6.1.4.1.2021.10.1.6.
'laLoadFloat.3' => '.1.3.6.1.4.1.2021.10.1.6.
'ssCpuUser' => '.1.3.6.1.4.1.2021.11.9.0'
'ssCpuSystem' => '.1.3.6.1.4.1.2021.11.10.0
'ssCpuIdle' => '.1.3.6.1.4.1.2021.11.11.0
'ucdVersionTag' => '.1.3.6.1.4.1.2021.100.2.0
'netscreen' => '.1.3.6.1.4.1.3224',
'nsSetGenSwVer' => '.1.3.6.1.4.1.3224.7.1.5.0
'nsResCpuLast1Min' => '.1.3.6.1.4.1.3224.16.1.2.
'nsResCpuLast5Min' => '.1.3.6.1.4.1.3224.16.1.3.
'nsResCpuLast15Min' => '.1.3.6.1.4.1.3224.16.1.4.
);
my %enterprisenumbers = (
9 => 'cisco',
232 => 'compaq',
318 => 'apc',
529 => 'ascend',
789 => 'netapp',
1991 => 'foundry',
2021 => 'ucdavis',
3224 => 'netscreen',
);
my %snmpsyntaxdb = (
# .1.3.6.1.2.1.2.2.1.8
'ifOperStatus' => {
'1' => 'up',
'2' => 'down',
'3' => 'testing',
'4' => 'unknown',
'5' => 'dormant',
'6' => 'notPresent',
'7' => 'lowerLayerDown',
},
# .1.3.6.1.2.1.15.3.1.2
'bgpPeerState' => {
'0' => 'nostate',
'1' => 'idle',
'2' => 'connect',
'3' => 'active',
'4' => 'opensent',
'5' => 'openconfirm',
'6' => 'established',
},
# .1.3.6.1.2.1.15.3.1.3
'bgpPeerAdminStatus' => {
'1' => 'stop',
'2' => 'start',
},
# .1.3.6.1.4.1.9.9.13.1.3.1.
'ciscoEnvMonTemperatureSta
'1' => 'normal',
'2' => 'warning',
'3' => 'critical',
'4' => 'shutdown',
'5' => 'notPresent',
'6' => 'notFunctioning',
},
# .1.3.6.1.4.1.9.9.13.1.4.1.
'ciscoEnvMonFanState' => {
'1' => 'normal',
'2' => 'warning',
'3' => 'critical',
'4' => 'shutdown',
'5' => 'notPresent',
'6' => 'notFunctioning'
},
# .1.3.6.1.4.1.9.9.13.1.5.1.
'ciscoEnvMonSupplyState' => {
'1' => 'normal',
'2' => 'warning',
'3' => 'critical',
'4' => 'shutdown',
'5' => 'notPresent',
'6' => 'notFunctioning',
},
# .1.3.6.1.4.1.9.9.13.1.5.1.
'ciscoEnvMonSupplySource' => {
'1' => 'unknown',
'2' => 'ac',
'3' => 'dc',
'4' => 'externalPowerSupply',
'5' => 'internalRedundant',
},
# .1.3.6.1.4.1.9.9.87.1.4.1.
'c2900PortDuplexState' => {
'1' => 'full',
'2' => 'half',
'3' => 'auto',
},
# .1.3.6.1.4.1.9.9.87.1.4.1.
'c2900PortDuplexStatus' => {
'1' => 'full',
'2' => 'half',
},
# .1.3.6.1.4.1.9.9.87.1.4.1.
'c2900PortAdminSpeed' => {
'1' => 'auto',
'10000000' => '10000000',
'100000000' => '100000000',
'155520000' => '155520000',
},
# .1.3.6.1.4.1.9.9.109.1.2.2
'cpmProcExtPriority' => {
'1' => 'critical',
'2' => 'high',
'3' => 'normal',
'4' => 'low',
'5' => 'notAssigned',
},
# .1.3.6.1.4.1.9.9.109.1.2.3
'cpmProcExtPriorityRev' => {
'1' => 'critical',
'2' => 'high',
'3' => 'normal',
'4' => 'low',
'5' => 'notAssigned',
},
# .1.3.6.1.4.1.9.9.147.1.2.1
'cfwHardwareStatusValue' => {
'1' => 'other',
'2' => 'up',
'3' => 'down',
'4' => 'error',
'5' => 'overTemp',
'6' => 'busy',
'7' => 'noMedia',
'8' => 'backup',
'9' => 'active',
'10' => 'standby',
},
# .1.3.6.1.4.1.232.6.2.6.1.0
'cpqHeThermalCondition' => {
'1' => 'other',
'2' => 'ok',
'3' => 'degraded',
'4' => 'failed',
},
# .1.3.6.1.4.1.232.6.2.6.3.0
'cpqHeThermalTempStatus' => {
'1' => 'other',
'2' => 'ok',
'3' => 'degraded',
'4' => 'failed',
},
# .1.3.6.1.4.1.232.6.2.6.4.0
'cpqHeThermalSystemFanStat
'1' => 'other',
'2' => 'ok',
'3' => 'degraded',
'4' => 'failed',
},
# .1.3.6.1.4.1.232.6.2.6.5.0
'cpqHeThermalCpuFanStatus'
'1' => 'other',
'2' => 'ok',
'4' => 'failed',
},
# 1.3.6.1.4.1.232.6.2.6.8.1.
'cpqHeTemperatureLocale' => {
'1' => 'other',
'2' => 'unknown',
'3' => 'system',
'4' => 'systemBoard',
'5' => 'ioBoard',
'6' => 'cpu',
'7' => 'memory',
'8' => 'storage',
'9' => 'removableMedia',
'10' => 'powerSupply',
'11' => 'ambient',
'12' => 'chassis',
'13' => 'bridgeCard',
},
# 1.3.6.1.4.1.232.6.2.6.8.1.
'cpqHeTemperatureCondition
'1' => 'other',
'2' => 'ok',
'3' => 'degraded',
'4' => 'failed',
},
# .1.3.6.1.4.1.232.6.2.11.1
'cpqHeEventLogSupported' => {
'1' => 'other',
'2' => 'notSupported',
'3' => 'supported',
},
# .1.3.6.1.4.1.232.6.2.11.2
'cpqHeEventLogCondition' => {
'1' => 'other',
'2' => 'ok',
'3' => 'degraded',
'4' => 'failed',
},
# .1.3.6.1.4.1.232.6.2.11.3.
'cpqHeEventLogEntrySeverit
'2' => 'informational',
'3' => 'infoWithAlert',
'6' => 'repaired',
'9' => 'caution',
'15' => 'critical',
},
# .1.3.6.1.4.1.318.1.1.1.2.1
'upsBasicBatteryStatus' => {
'1' => 'unknown',
'2' => 'batteryNormal',
'3' => 'batteryLow',
},
# .1.3.6.1.4.1.318.1.1.1.4.1
'upsBasicOutputStatus' => {
'1' => 'unknown',
'2' => 'onLine',
'3' => 'onBattery',
'4' => 'onSmartBoost',
'5' => 'timedSleeping',
'6' => 'softwareBypass',
'7' => 'off',
'8' => 'rebooting',
'9' => 'switchedBypass',
'10' => 'hardwareFailureBypass',
'11' => 'sleepingUntilPowerReturn'
'12' => 'onSmartTrim',
},
# .1.3.6.1.4.1.318.1.1.1.2.2
'upsAdvBatteryReplaceIndic
'1' => 'noBatteryNeedsReplacing',
'2' => 'batteryNeedsReplacing',
},
# .1.3.6.1.4.1.318.1.1.1.3.2
'upsAdvInputLineFailCause'
'1' => 'noTransfer',
'2' => 'highLineVoltage',
'3' => 'brownout',
'4' => 'blackout',
'5' => 'smallMomentarySag',
'6' => 'deepMomentarySag',
'7' => 'smallMomentarySpike',
'8' => 'largeMomentarySpike',
'9' => 'selfTest',
# In the MIB file itself the following is spelled as rateOfVoltageChnage
'10' => 'rateOfVoltageChange',
},
# .1.3.6.1.4.1.789.1.2.2.4.0
'miscGlobalStatus' => {
'1' => 'other',
'2' => 'unknown',
'3' => 'ok',
'4' => 'nonCritical',
'5' => 'critical',
'6' => 'nonRecoverable',
},
# .1.3.6.1.4.1.789.1.2.4.1.0
'envOverTemperature' => {
'1' => 'no',
'2' => 'yes',
},
# .1.3.6.1.4.1.1991.1.1.1.2.
'snChasPwrSupplyOperStatus
'1' => 'other',
'2' => 'normal',
'3' => 'failure',
},
# .1.3.6.1.4.1.1991.1.1.1.3.
'snChasFanOperStatus' => {
'1' => 'other',
'2' => 'normal',
'3' => 'failure',
},
# .1.3.6.1.4.1.1991.1.1.3.3.
'snSwPortInfoChnMode' => {
'0' => 'none',
'1' => 'half',
'2' => 'full',
},
# .1.3.6.1.4.1.1991.1.1.3.3.
'snSwPortInfoSpeed' => {
'0' => 'none',
'1' => 'auto',
'2' => '10000000',
'3' => '100000000',
'4' => '1000000000',
'5' => '45000000',
'6' => '155000000',
'7' => '10000000000',
},
# .1.3.6.1.4.1.1991.1.1.4.2.
'snL4VirtualServerAdminSta
'0' => 'disabled',
'1' => 'enabled',
},
# .1.3.6.1.4.1.1991.1.1.4.3.
'snL4RealServerAdminStatus
'0' => 'disabled',
'1' => 'enabled',
},
# .1.3.6.1.4.1.1991.1.1.4.4.
'snL4VirtualServerPortAdmi
'0' => 'disabled',
'1' => 'enabled',
},
# .1.3.6.1.4.1.1991.1.1.4.5.
'snL4RealServerPortAdminSt
'0' => 'disabled',
'1' => 'enabled',
},
# .1.3.6.1.4.1.1991.1.1.4.8.
'snL4RealServerStatusState
'0' => 'serverdisabled',
'1' => 'serverenabled',
'2' => 'serverfailed',
'3' => 'servertesting',
'4' => 'serversuspect',
'5' => 'servershutdown',
'6' => 'serveractive',
},
# .1.3.6.1.4.1.1991.1.1.4.10
'snL4RealServerPortStatusS
'0' => 'disabled',
'1' => 'enabled',
'2' => 'failed',
'3' => 'testing',
'4' => 'suspect',
'5' => 'shutdown',
'6' => 'active',
'7' => 'unbound',
'8' => 'awaitUnbind',
'9' => 'awaitDelete',
},
# .1.3.6.1.4.1.1991.1.2.11.6
'snBgp4NeighGenCfgShutdown
'0' => 'disabled',
'1' => 'enabled',
},
# .1.3.6.1.4.1.1991.1.2.11.1
'snBgp4NeighOperStatusBgpT
'0' => 'ebgp',
'1' => 'ibgp',
},
# .1.3.6.1.4.1.1991.1.2.11.1
'snBgp4NeighOperStatusStat
'0' => 'noState',
'1' => 'idle',
'2' => 'connect',
'3' => 'active',
'4' => 'openSent',
'5' => 'openConfirm',
'6' => 'established',
},
# .1.3.6.1.4.1.1991.1.2.11.1
'snBgp4NeighborSummaryStat
'0' => 'noState',
'1' => 'idle',
'2' => 'connect',
'3' => 'active',
'4' => 'openSent',
'5' => 'openConfirm',
'6' => 'established',
},
);
my $z = 0;
my %cpustatusorder = (
'cpu' => $z++,
'cpu1sec' => $z++,
'cpu5sec' => $z++,
'cpu1min' => $z++,
'cpu5min' => $z++,
'cpu15min' => $z++,
'la1min' => $z++,
'la5min' => $z++,
'la15min' => $z++,
'cpuuser' => $z++,
'cpusystem' => $z++,
'cpubusy' => $z++,
'cpuidle' => $z++,
);
my %cpustatusnames = (
'cpu' => 'CPU Usage',
'cpu1sec' => 'CPU Usage, 1 Second Average',
'cpu5sec' => 'CPU Usage, 5 Second Average',
'cpu1min' => 'CPU Usage, 1 Minute Average',
'cpu5min' => 'CPU Usage, 5 Minute Average',
'cpu15min' => 'CPU Usage, 15 Minute Average',
'la1min' => 'Load Average, 1 Minute Average',
'la5min' => 'Load Average, 5 Minute Average',
'la15min' => 'Load Average, 15 Minute Average',
'cpuuser' => 'CPU Time in User Mode',
'cpusystem' => 'CPU Time in System Mode',
'cpubusy' => 'CPU Time in Busy Mode',
'cpuidle' => 'CPU Time in Idle Mode',
);
my $cputhreshdb_ref = undef;
my $cpu_defyellow = 80; # percent
my $cpu_defred = 90; # percent
my $la_defyellow = exists($ENV{'CPUWARN'}) ? $ENV{'CPUWARN'} : 150; # Load average x 100
$la_defyellow = sprintf("0.2%f",$la_defyel
my $la_defred = exists($ENV{'CPUPANIC'}) ? $ENV{'CPUPANIC'} : 300; # Load average x 100
$la_defred = sprintf("0.2%f",$la_defred
my $show_cisco_top = 0; # Show similated Cisco top in CPU output
# For Compaq temperature checks
my $compaq_pct_temp_warn = 80;
my $compaq_pct_temp_panic = 90;
# For disk checks
my $diskthreshdb_ref = undef;
my $disk_defyellow = exists($ENV{'DFWARN'}) ? $ENV{'DFWARN'} : 90;
my $disk_defred = exists($ENV{'DFWARN'}) ? $ENV{'DFWARN'} : 90;
# Turn on or off depending on whether or not you have more servers defined
# than BB can display in one page. TODO: Automate this decision.
# bindtree is the minimum necessary.
my $l4_show_realservers = 0;
my $l4_show_virtservers = 0;
my $l4_show_bindtree = 1;
my $l4_bbhosts_ref = undef; # Database of bb-hosts contents for L4 switch monitor-by-proxy.
# Uses the L4 real server states as test results for tests that
# BigBrother is not already performing itself.
&main();
exit;
#--------------------
# Prevent stupid typos with cruel autoload!
#--------------------
sub AUTOLOAD {
use vars qw($AUTOLOAD);
warn("package ".(caller(1))[0].", file ".(caller(1))[1].", line ".(caller(1))[2]);
warn(", subname ".(caller(1))[3].", called the following function which doesn't exist: $AUTOLOAD\n");
exit;
}
sub main {
if ($ARGV[0] eq '-v') {
die("$Bin/$Script: $VERSION\n");
}
print("Starting...\n") if $debug;
print("Environment checking\n") if $debug;
unless (&env_check()) {
print(localtime().": ".(caller(0))[3].": Environment check failed\n");
exit 1;
}
# Read in bb-xsnmptab
print("Reading bb-xsnmptab\n") if $debug;
my $commdb_ref = undef;
my $testdb_ref = undef;
unless (($commdb_ref,$testdb_ref)
print(localtime().": ".(caller(0))[3].": Unable to get community and test list.\n");
exit 1;
}
# Read in bb-cputab.
print("Reading bb-cputab\n") if $debug;
$cputhreshdb_ref = &read_cpu_tab(keys(%$commd
unless (defined($cputhreshdb_ref)
print(localtime().": ".(caller(0))[3].": Unable to read bb-cputab.\n");
exit 1;
}
# Read in bb-dftab
print("Reading bb-dftab\n") if $debug;
$diskthreshdb_ref = &read_df_tab(keys(%$commdb
unless (defined($diskthreshdb_ref
print(localtime().": ".(caller(0))[3].": Unable to read bb-dftab.\n");
exit 1;
}
# Read bb-hosts for L4 switch monitor-by-proxy
print("Reading bb-hosts\n") if $debug;
unless ($l4_bbhosts_ref = &l4_read_bbhosts()) {
print(localtime().": ".(caller(0))[3].": Unable to read bb-hosts.\n");
exit 1;
}
# Initialize bb-combo message
$ENV{'BBCOMBOID'} = $$;
if ($is_commandline) {
print("$ENV{'BBHOME'}/bin/
} else {
system("$ENV{'BBHOME'}/bin
}
while (my($host,$community) = each(%$commdb_ref)) {
# Make only one session
my($snmpsession,$snmperror
-hostname => $host,
-community => $community,
-debug => $debug,
-retries => $defretries,
-timeout => $deftimeout,
-translate => [ -timeticks => 0x0 ],
); # Net::SNMP->session
if (! defined($snmpsession)) {
print((caller(0))[3].": SNMP session failed for '$host': $snmperror\n");
next;
}
# Determine properties used in all tests
# Send a query to determine what brand the machine is.
print(" Checking enterprise and uptime for $host\n") if $debug;
my $objectid = undef;
my $enterprise = undef;
my $uptime = undef;
if (my $result = $snmpsession->get_request(
[$snmpoids{'sysObjectID'},
$uptime = $result->{$snmpoids{'sysUp
$objectid = $result->{$snmpoids{'sysOb
(my $brandnum = substr($objectid,length($s
if (exists($enterprisenumbers
$enterprise = $enterprisenumbers{$brandn
} else {
print("Unknown enterprise number '$brandnum' in ObjectID '$objectid'\n");
next;
}
} else {
print((caller(0))[3].": SNMP get request failed for '$host': ".$snmpsession->error()."\
return;
}
# Determine what OS version the machine is.
my $version = undef;
unless ($version = &detect_version($host,$snm
print("Unable to detect version for host '$host' enterprise '$enterprise'\n");
next;
}
print(" version $version\n") if $debug;
# Run individual tests
while (my($test) = each(%{$testdb_ref->{$host
# Harmless skips
if ($test eq 'l4') {
next unless &is_l4switch($host,$snmpse
}
my $message = '';
# Run the appropriate test/determine colors
unless ($message = &create_message($host,$snm
print("Unable to create message for host '$host' enterprise '$enterprise' version '$version' test '$test'");
next;
}
$message .= "\n<!-- Enterprise: $enterprise , Version: $version -->\n";
# Add version credit
$message .= "$Script Version: $VERSION\n";
# Add to combo message
if ($is_commandline) {
print("$ENV{'BBHOME'}/bin/
} else {
system("$ENV{'BBHOME'}/bin
}
} # while (my($test) = each(%{$testdb_ref->{$host
} # while (my($host,$community) = each(%$commdb_ref))
# Send combo message
if ($is_commandline) {
print("$ENV{'BBHOME'}/bin/
# Print time elapsed since the start of this extension
printf("%d seconds elapsed\n",time() - $^T);
} else {
system("$ENV{'BBHOME'}/bin
}
return 1;
} # sub main
##### TESTS #####
#----
# $message = &create_message($host,$snm
#
# Create a message for transmission to BigBrother
#----
sub create_message {
my($host,$snmpsession,$tes
if ($test eq 'bgp') {
return &bgp_message($host,$snmpse
} elsif ($test eq 'cpu') {
return &cpu_message($host,$snmpse
} elsif ($test eq 'disk') {
return &disk_message($host,$snmps
} elsif ($test eq 'fans') {
return &fans_message($host,$snmps
} elsif ($test eq 'l4') {
return &l4_message($host,$snmpses
} elsif ($test eq 'memory') {
return &memory_message($host,$snm
} elsif ($test eq 'ports') {
return &ports_message($host,$snmp
} elsif ($test eq 'power') {
return &power_message($host,$snmp
} elsif ($test eq 'temperature') {
return &temperature_message($host
} elsif ($test eq 'uptime') {
return &uptime_message($host,$snm
} else {
print("Unknown test '$test'\n");
return;
}
return;
} # sub create_message
##### BGP #####
#----
# &bgp_message($host,$snmpse
#
# Create a BigBrother message about the BGP state of a host
#----
sub bgp_message {
my($host,$snmpsession,$ent
(my $commahost = $host) =~ s/\./\,/g;
my $test = 'bgp';
my $message = '';
# Cisco uses generic mib-2 BGP MIB but Foundry does not.
# Should be able to check whether or not I can use the standard MIB.
my $is_standard = 0;
my $localas = undef;
unless (($enterprise eq 'cisco') || ($enterprise eq 'foundry')) {
# See whether or not I have the standard MIB-2 bits
if (my $result = $snmpsession->get_request(
if (exists($result->{$snmpoid
$is_standard = 1;
$localas = $result->{$snmpoids{'bgpLo
}
}
} # unless (($enterprise eq 'cisco') || ($enterprise eq 'foundry'))
my %asdb = ();
my %statedb = ();
my %timedb = ();
my %shutdowndb = (); # Only used by Cisco for now
my %descrdb = (); # Only used by Foundry for now
if (($enterprise eq 'cisco') || ($is_standard)) {
unless (defined($localas)) {
if (my $result = $snmpsession->get_request(
$localas = $result->{$snmpoids{'bgpLo
} else {
print(localtime().": ".(caller(0))[3].": Unable to get local AS for $host: ".$snmpsession->error()."\
return;
}
}
if (my $result = $snmpsession->get_table(-b
while (my($oid,$asnum) = each(%$result)) {
$asdb{substr($oid,1+length
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get remote ASs for $host: ".$snmpsession->error()."\
return;
}
if (my $result = $snmpsession->get_table(-b
while (my($oid,$statenum) = each(%$result)) {
$statedb{substr($oid,1+len
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get peer states for $host: ".$snmpsession->error()."\
return;
}
if (my $result = $snmpsession->get_table(-b
while (my($oidnum,$statenum) = each(%$result)) {
$shutdowndb{substr($oidnum
$snmpsyntaxdb{'bgpPeerAdmi
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get peer admin statuses for $host: ".$snmpsession->error()."\
return;
}
if (my $result = $snmpsession->get_table(-b
$snmpoids{'bgpPeerFsmEstab
while (my($oid,$seconds) = each(%$result)) {
$timedb{substr($oid,1+leng
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get peer established times for $host: ".$snmpsession->error()."\
return;
}
} elsif ($enterprise eq 'foundry') {
unless (defined($localas)) {
# "Useless use of private variable in void context at bb-xsnmp.pl line 904."
# Unless I use 'my' here.
if (my $result => $snmpsession->get_request(
[$snmpoids{'snBgp4GenLocal
$localas = $result->{$snmpoids{'snBgp
} else {
print(localtime().": ".(caller(0))[3].": Unable to get local AS for $host: ".$snmpsession->error()."\
return;
}
}
# Shutdown state, IP works as index.
# This doesn't mean what I thought it did though. Disabling for Foundry.
# Doesn't seem to be a way to get BGP peer admin state for Foundry.
# if (my $result = $snmpsession->get_table(-b
# while (my($oidnum,$statenum) = each(%$result)) {
# $shutdowndb{substr($oidnum
# $snmpsyntaxdb{'snBgp4Neigh
# }
# } else {
# print(localtime().": ".(caller(0))[3].": Unable to get shutdown states for $host: ".$snmpsession->error()."\
# return;
# }
# Neighbor description
if (my $result = $snmpsession->get_table(-b
while (my($oidnum,$descr) = each(%$result)) {
$descrdb{substr($oidnum,1+
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get neighbor descriptions for $host: ".$snmpsession->error()."\
return;
}
# Remote AS
if (my $result = $snmpsession->get_table(-b
while (my($oidnum,$remoteas) = each(%$result)) {
$asdb{substr($oidnum,1+len
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get neighbor remote ASs for $host: ".$snmpsession->error()."\
return;
}
# Need index -> remote ip, state, and time
my %index2ip = ();
if (my $result = $snmpsession->get_table(-b
$snmpoids{'snBgp4NeighborS
while (my($oidnum,$ipaddr) = each(%$result)) {
(my $index = $oidnum) =~ s/^.*\.//;
$index2ip{$index} = $ipaddr;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get neighbor IP index for $host: ".$snmpsession->error()."\
return;
}
# Remote IP
if (my $result = $snmpsession->get_table(-b
$snmpoids{'snBgp4NeighborS
while (my($oidnum,$ipaddr) = each(%$result)) {
(my $index = $oidnum) =~ s/^.*\.//;
$index2ip{$index} = $ipaddr;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get neighbor IP index for $host: ".$snmpsession->error()."\
return;
}
# Remote State
if (my $result = $snmpsession->get_table(-b
$snmpoids{'snBgp4NeighborS
while (my($oidnum,$statenum) = each(%$result)) {
(my $index = $oidnum) =~ s/^.*\.//;
my $ipaddr = $index2ip{$index};
my $state = $snmpsyntaxdb{'snBgp4Neigh
$statedb{$ipaddr} = $state;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get neighbor states for $host: ".$snmpsession->error()."\
return;
}
# Time since last change
if (my $result = $snmpsession->get_table(-b
$snmpoids{'snBgp4NeighborS
while (my($oidnum,$timeup) = each(%$result)) {
(my $index = $oidnum) =~ s/^.*\.//;
my $ipaddr = $index2ip{$index};
$timedb{$ipaddr} = $timeup;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get neighbor state change times for $host: ".$snmpsession->error()."\
return;
}
} else {
print(localtime().": ".(caller(0))[3].": Unknown enterprise '$enterprise' for host '$host'\n");
return;
}
# Look through states and find a color for each peer and an overall color.
# Include description and shutdown if they exist.
# 'One line' IP address sort! Woohoo!
my @peerlist = sort {
unless ((split(/\./,$a))[0] <=> (split(/\./,$b))[0]) {
unless (((split(/\./,$a))[1] <=> (split(/\./,$b))[1])) {
unless (((split(/\./,$a))[2] <=> (split(/\./,$b))[2])) {
(split(/\./,$a))[3] <=> (split(/\./,$b))[3]
}
}
}
} keys(%statedb);
my $routercolor = 'green';
# Turn $routercolor red if all external peers are down.
# Turn $routercolor yellow if any internal peers are down
# or if any external peers are down for longer than fifteen minutes.
my %colordb = ();
my $has_externalup = 0; # Set to 1 if any external BGP peers are up.
foreach my $ipaddr (@peerlist) {
my $state = $statedb{$ipaddr};
my $remoteas = $asdb{$ipaddr};
my $statetime = $timedb{$ipaddr};
my $descr = exists($descrdb{$ipaddr}) ? $descrdb{$ipaddr} : undef;
my $shutdown = exists($shutdowndb{$ipaddr
if ($state eq 'established') {
$colordb{$ipaddr} = 'green';
$has_externalup = 1;
} elsif ((defined($shutdown)) && ($shutdown eq 'stop')) {
$colordb{$ipaddr} = 'clear';
# } elsif (($state eq 'active') && ($statetime == 0)) {
} elsif ($statetime == 0) {
# Means it's never been up
$colordb{$ipaddr} = 'clear';
} elsif ($remoteas eq $localas) {
# Bad news if an IBGP session is down
$colordb{$ipaddr} = 'red';
$routercolor = 'red';
} elsif ($statetime < 900) {
# Allow 15 minutes of downtime
$colordb{$ipaddr} = 'yellow';
} else {
# More than that, something is wrong
$colordb{$ipaddr} = 'red';
$routercolor = ($routercolor eq 'green') ? 'yellow' : $routercolor;
}
if (! $has_externalup) {
$routercolor = 'red';
}
$message .= '&'.$colordb{$ipaddr}.' '.$ipaddr.' AS '.$remoteas;
if ((defined($descr)) && (length($descr) > 0)) {
$message .= " '$descr'";
}
$message .= ' '.$state;
my $secs = $statetime;
my $weeks = int($secs / 604800);
$secs = $secs - $weeks * 604800;
my $days = int($secs / 86400);
$secs = $secs - $days * 86400;
my $hours = int($secs / 3600);
$secs = $secs - $hours * 3600;
my $minutes = int($secs / 60);
$secs = $secs - $minutes * 60;
my $timestr = '';
if ($weeks >= 2) {
$timestr .= "$weeks weeks, ";
} elsif ($weeks == 1) {
$timestr .= "1 week, ";
}
if ($days >= 2) {
$timestr .= "$days days, ";
} elsif ($days == 1) {
$timestr .= "1 day, ";
}
$timestr .= sprintf("%02d:%02d:%02d",$
$message .= ' '.$timestr;
$message .= "\n";
}
$message = "status $commahost.$test $routercolor ".scalar(localtime)."\n\n$
return $message;
} # sub bgp_message
##### CPU #####
#----
# &cpu_message($host,$snmpse
#
# Check CPU status and compose into a message
#----
sub cpu_message {
my($host,$snmpsession,$ent
print(localtime().": ".(caller(0))[3].": Checking host '$host'\n") if $debug;
if (! defined($uptime)) {
print(localtime().": ".(caller(0))[3].": Uptme for '$host' is undefined\n");
return;
}
if ($uptime == 0) {
print(localtime().": ".(caller(0))[3].": Uptme for '$host' is zero\n");
return;
}
# Find one or more of the following:
# cpu - All Foundry devices have this. Newer ones have the time-based
# averages that should be used instead.
# This has been deprecated in new Foundries and should be ignored when
# the others are available. Docs for 07.6.04 say reading it resets all
# the CPU counters.
# cpuNsec - Foundry routers
# cpu1min - Many routers
# cpu5min - Many routers
# cpu15min - Many routers
# la1min - UCD
# la5min - UCD
# la10min - UCD-SNMP mib files say this. Not used.
# la15min - UCD-SNMP config files and snmpwalk say this. Using this.
# UCD-SNMP also has the following which are also available through vmstat:
# cpuuser
# cpusystem
# cpuidle
my $cpudb_ref = undef;
unless ($cpudb_ref = &get_cpu_status($host,$snm
print(localtime().": ".(caller(0))[3].": Unable to get CPU status for host '$host' enterprise '$enterprise' version $version\n");
next;
}
# Check uptime, hundredths of seconds
my $uptimecolor = 'green';
if ((($uptime / 100) / 60) < $ENV{'WARNMINSONREBOOT'}) {
$uptimecolor = $ENV{'WARNCOLORONREBOOT'};
}
# Determine colors
my $colordb_ref = &check_cpu_colorstatus($ho
unless (defined($colordb_ref)) {
print("Unable to determine colors for host '$host' enterprise '$enterprise' version '$version'\n");
next;
}
# Find worst color
my @colorlist = ($uptimecolor);
if (exists($colordb_ref->{'cp
push(@colorlist,$colordb_r
} elsif (exists($colordb_ref->{'cp
push(@colorlist,$colordb_r
} elsif (exists($colordb_ref->{'cp
push(@colorlist,$colordb_r
} elsif (exists($colordb_ref->{'la
push(@colorlist,$colordb_r
} elsif (exists($colordb_ref->{'cp
push(@colorlist,$colordb_r
}
my $worstcolor = &color_compare(@colorlist)
# Create message
my $message = '';
my $test = 'cpu';
(my $commahost = $host) =~ s/\./\,/g;
my $upword = '';
if (($uptime / 100) < 120) {
$upword = sprintf("%3.2f seconds",$uptime / 100);
} elsif ((($uptime / 100) / 60) < 120) {
$upword = sprintf("%3.2f minutes",(($uptime / 100) / 60));
} elsif (((($uptime / 100) / 60 ) / 60) < 48) {
$upword = sprintf("%3.2f hours",((($uptime / 100) / 60) / 60));
} else {
$upword = sprintf("%3.2f days",(((($uptime / 100) / 60) / 60) / 24));
}
$message = "status $commahost.$test $worstcolor ".scalar(localtime)." up: $upword";
if (exists($cpudb_ref->{'la5m
$message .= sprintf(", load=%0.2f",$cpudb_ref->{'
} elsif (exists($cpudb_ref->{'cpu5
$message .= sprintf(", CPU Usage=%3.0f\%",$cpudb_ref-
} elsif (exists($cpudb_ref->{'cpub
$message .= sprintf(", CPU Usage=%3.0f\%",$cpudb_ref-
} elsif (exists($cpudb_ref->{'cpu'
$message .= sprintf(", CPU Usage=%3.0f\%",$cpudb_ref-
}
$message .= "\n\n";
if ((($uptime / 100) / 60) < $ENV{'WARNMINSONREBOOT'}) {
$message .= "Warning: Machine recently rebooted\n\n";
}
my @cpuparams = sort { $cpustatusorder{$a} <=> $cpustatusorder{$b} } keys(%$cpudb_ref);
my $has_la = 0;
my $has_cpu = 0;
foreach my $cpu (@cpuparams) {
$message .= '&'.$colordb_ref->{$cpu};
$message .= ' ';
$message .= "$cpustatusnames{$cpu}: ";
if ($cpu =~ /^la/) {
# Assume load average
$has_la = 1;
$message .= sprintf("%0.2f",$cpudb_ref
} elsif ($cpu =~ /^cpu/) {
# Assume percentage
$has_cpu = 1;
$message .= sprintf("%3.0f\%",$cpudb_r
} else {
print("Unknown parameter for host '$host': $cpu\n");
}
$message .= "\n";
} # foreach my $cpu (@cpuparams)
$message .= "\n";
if ($has_cpu) {
$message .= "&yellow CPU Usage Threshold: ".$cputhreshdb_ref->{$host
$message .= "&red CPU Usage Threshold: ".$cputhreshdb_ref->{$host
}
if ($has_la) {
$message .= sprintf("&yellow Load Average Threshold: %0.2f\n",$cputhreshdb_ref-
$message .= sprintf("&red Load Average Threshold: %0.2f\n",$cputhreshdb_ref-
}
if (($enterprise eq 'cisco') && ($show_cisco_top)) {
# Try to build a top-like listing of active processes,
# much like the origial SNMP2BB extension.
# Walk cpmProcessEntry
# Skip peacefully if anything vital is missing. Old ciscos don't even have cpmProcessEntry.
my %procpridb = ();
my %procusecdb = ();
my %procavgusecdb = ();
my %procnamedb = ();
if ((my $result = $snmpsession->get_table(-b
(my $priresult = $snmpsession->get_table(-b
$message .= "</pre>\n";
my $qprocname = quotemeta($snmpoids{'cpmPr
my $qprocusec = quotemeta($snmpoids{'cpmPr
my $qprocavgusec = quotemeta($snmpoids{'cpmPr
my $qprocpri = quotemeta($snmpoids{'cpmPr
while (my($key,$value) = each(%$result)) {
if ($key =~ /^$qprocname\.1\.(\d+)/) {
my $pid = $1;
$procnamedb{$pid} = $value;
} elsif ($key =~ /^$qprocusec\.1\.(\d+)/) {
my $pid = $1;
$procusecdb{$pid} = $value;
} elsif ($key =~ /^$qprocavgusec\.1\.(\d+)/
my $pid = $1;
$procavgusecdb{$pid} = $value;
} # if ($key =~ /^$qprocname\.1\.(\d+)/)
} # while (my($key,$value) = each(%$result))
while (my($key,$value) = each(%$priresult)) {
if ($key =~ /^$qprocpri\.1\.(\d+)/) {
my $pid = $1;
unless (exists($snmpsyntaxdb{'cpm
print("Cisco Host $host Value $value corresponds to no known cpmProcExtPriority\n");
return;
}
unless (defined($snmpsyntaxdb{'cp
print("Cisco Host $host Value $value corresponds to no defined cpmProcExtPriority\n");
return;
}
$procpridb{$pid} = $snmpsyntaxdb{'cpmProcExtP
}
} # while (my($key,$value) = each(%$priresults))
# Filter out the inactive processes.
# use cpmProcessuSecs if needed, cpmProcessAverageUSecs not always present
while (my($pid,$pname) = each(%procnamedb)) {
if (exists($procavgusecdb{$pi
if ($procavgusecdb{$pid} == 0) {
delete($procnamedb{$pid});
}
} elsif (exists($procusecdb{$pid})
if ($procusecdb{$pid} == 0) {
delete($procnamedb{$pid});
} # if ($procusecdb{$pid} == 0)
} # if (exists($procavgusecdb{$pi
} # while (my($pid,$pname) = each(%procnamedb))
# Sort by cpmProcessAverageUSecs/cpm
my @pidlist = ();
if (scalar(keys(%procavgusecd
@pidlist = sort { $procusecdb{$b} <=> $procusecdb{$a} } keys(%procnamedb);
} else {
@pidlist = sort { ($procavgusecdb{$b} <=> $procavgusecdb{$a}) || ($procusecdb{$b} <=> $procusecdb{$a}) } keys(%procnamedb);
}
# Print table in the following form:
# PID PRI Time Name
$message .= "<!-- Priority keys: ".(scalar(keys(%procpridb)
$message .= "<!-- Priority key results: ".(scalar(keys(%$priresult
my($samplekey,$samplevalue
$message .= "<!-- Sample key results: ".$samplekey." : ".$samplevalue." -->";
$message .= "<table border=1>\n";
$message .= "<tr><th>PID</th><th>PRI</
foreach my $pid (@pidlist) {
my $pname = $procnamedb{$pid};
my $ppri = (exists($procpridb{$pid}))
my $ptime = (exists($procavgusecdb{$pi
$message .= "<tr><td>$pid</td><td>$ppr
}
$message .= "</table>\n";
$message .= "<pre>\n";
} else {
# The cisco in question is too old to present the requested MIB
# print("Unable to get process names for Cisco $host: ".$snmpsession->error()."\
# return;
}
} # if ($enterprise eq 'cisco') and if I really want to print a top-like table
return $message;
} # sub cpu_message
#----
# &read_cpu_tab(@hostlist)
#
# Read in the bb-cputab.
# Require a list of wanted hosts.
# Ignore the 'localhost' option in bb-cputab since I'm
# looking at someone else's CPU.
# $cputhreshdb_ref->{$host}{
# $cputhreshdb_ref->{$host}{
#----
sub read_cpu_tab {
my(@hostlist) = @_;
my %hostdb = map { $_ => 1 } @hostlist;
my %threshdb = ();
unless (-f "$ENV{'BBHOME'}/etc/bb-cpu
# bb-cputab doesn't exist, which is the default installation and not
# necessarily an error
return \%threshdb;
}
my $infh = new FileHandle;
if ($infh->open("< $ENV{'BBHOME'}/etc/bb-cput
while (my $line = $infh->getline()) {
chomp($line);
$line =~ s/\#.*$//g;
$line =~ s/\s+$//g;
next if $line =~ /^\s*\#/;
next if $line !~ /\S/;
if ($line =~ /^\s*(\S+)\s*\:[^\:]*\:\s*
my($host,$yellowlimits,$re
unless (exists($hostdb{$host})) {
next;
} # unless (exists($hostdb{$host}))
my @yellows = split(' ',$yellowlimits);
my @reds = split(' ',$redlimits);
foreach my $yellow (@yellows) {
if ($yellow =~ /^([\d\.]+)\%$/) {
# assume cpu percentage
$threshdb{$host}{'cpu'}{'y
} elsif ($yellow =~ /^(\d+\.\d\d)$/) {
# assume dotted load average
$threshdb{$host}{'la'}{'ye
} elsif ($yellow =~ /^(\d+)$/) {
# assume load average x 100
$threshdb{$host}{'la'}{'ye
} else {
# unknown
print("Odd yellow threshold for host '$host' in bb-cputab:'$yellow'\n");
} # if ($yellow =~ /^([\d\.]+)\%$/)
} # foreach my $yellow (@yellows)
foreach my $red (@reds) {
if ($red =~ /^([\d\.]+)\%$/) {
# assume cpu percentage
$threshdb{$host}{'cpu'}{'r
} elsif ($red =~ /^(\d+\.\d\d)$/) {
# assume dotted load average
$threshdb{$host}{'la'}{'re
} elsif ($red =~ /^(\d+)$/) {
# assume load average x 100
$threshdb{$host}{'la'}{'re
} else {
# unknown
print("Odd red threshold for host '$host' in bb-cputab:'$red'\n");
} # if ($red =~ /^([\d\.]+)\%$/)
} # foreach my $yellow (@yellows)
} else {
print("Odd line in bb-cputab:'$line'\n");
} # if ($line =~ /^\s*(\S+)\s*\:[^\:]*\:\s*
} # while (my $line = $infh->getline())
$infh->close;
} else {
print("Unable to open bb-cputab: $!\n");
return;
}
# Fill in the blanks
foreach my $host (@hostlist) {
unless (exists($threshdb{$host}{'
$threshdb{$host}{'la'}{'ye
}
unless (exists($threshdb{$host}{'
$threshdb{$host}{'la'}{'re
}
unless (exists($threshdb{$host}{'
$threshdb{$host}{'cpu'}{'y
}
unless (exists($threshdb{$host}{'
$threshdb{$host}{'cpu'}{'r
}
}
# Return results
return \%threshdb;
} # sub read_cpu_tab
#----
# &read_df_tab(@hostlist)
#
# Read in the bb-dftab.
# Require a list of wanted hosts.
# $diskthreshdb_ref->{$host}
# $diskthreshdb_ref->{$host}
# 'localhost' and unspecified hosts ignored.
# Spaces eliminated during processing.
#----
sub read_df_tab {
my(@hostlist) = @_;
my %hostdb = map { $_ => 1 } @hostlist;
my %threshdb = ();
unless (-f "$ENV{'BBHOME'}/etc/bb-dft
# bb-dftab doesn't exist, which is the default installation and not
# necessarily an error
return \%threshdb;
}
my $infh = new FileHandle;
if ($infh->open("< $ENV{'BBHOME'}/etc/bb-dfta
while (my $line = $infh->getline()) {
chomp($line);
$line =~ s/\#.*$//g;
$line =~ s/\s+$//g;
next if $line =~ /^\s*\#/;
next if $line !~ /\S/;
$line =~ s/\s//g;
# Look for specific hosts:
# host:partition:warn%:panic
if ($line =~ /^([^:]+):([^:]+):(\d+):(\
my($hostname,$partition,$w
next unless exists($hostdb{$hostname})
$threshdb{$hostname}{$part
$threshdb{$hostname}{$part
} # if ($line =~ /^([^:]+):([^:]+):(\d+):(\
} # while (my $line = $infh->getline())
} else { # if ($infh->open("< $ENV{'BBHOME'}/etc/bb-dfta
print("Unable to open bb-dftab: $!\n");
return;
}
return \%threshdb;
} # sub read_df_tab
#----
# &get_cpu_status($host,$snm
#
# Get all kinds of status possible via SNMP
#----
sub get_cpu_status {
my($host,$snmpsession,$ent
my %cpudb = ();
my %oiddb = ();
if ($enterprise eq 'cisco') {
$oiddb{'cpu5sec'} = $snmpoids{'busyPer'};
$oiddb{'cpu1min'} = $snmpoids{'avgBusy1'};
$oiddb{'cpu5min'} = $snmpoids{'avgBusy5'};
} elsif ($enterprise eq 'foundry') {
if ($version >= 7.1) {
$oiddb{'cpu1sec'} = $snmpoids{'snAgGblCpuUtil1
$oiddb{'cpu5sec'} = $snmpoids{'snAgGblCpuUtil5
$oiddb{'cpu1min'} = $snmpoids{'snAgGblCpuUtil1
} else {
$oiddb{'cpu'} = $snmpoids{'snAgGblCpuUtilD
}
} elsif ($enterprise eq 'netapp') {
$oiddb{'cpubusy'} = $snmpoids{'cpuBusyTimePerC
$oiddb{'cpuidle'} = $snmpoids{'cpuIdleTimePerC
} elsif ($enterprise eq 'netscreen') {
$oiddb{'cpu1min'} = $snmpoids{'nsResCpuLast1Mi
$oiddb{'cpu5min'} = $snmpoids{'nsResCpuLast5Mi
$oiddb{'cpu15min'} = $snmpoids{'nsResCpuLast15M
} elsif ($enterprise eq 'ucdavis') {
$oiddb{'cpuuser'} = $snmpoids{'ssCpuUser'};
$oiddb{'cpusystem'} = $snmpoids{'ssCpuSystem'};
$oiddb{'cpuidle'} = $snmpoids{'ssCpuIdle'};
# Get the float versions, easiet to handle as numbers
$oiddb{'la1min'} = $snmpoids{'laLoadFloat.1'}
$oiddb{'la5min'} = $snmpoids{'laLoadFloat.2'}
$oiddb{'la15min'} = $snmpoids{'laLoadFloat.3'}
} else {
print(localtime().": ".(caller(0))[3].": Unknown enterprise '$enterprise' for host '$host'\n");
return;
}
# Get all the requested data
if (my $result = $snmpsession->get_request(
while (my($oidname,$oidnumber) = each(%oiddb)) {
$cpudb{$oidname} = $result->{$oidnumber};
}
} else {
print("Unable to get anything for host $host enterprise $enterprise version $version: ".$snmpsession->error()."\
return;
}
return \%cpudb;
} # sub get_cpu_status
#----
# $colordb_ref = &check_cpu_colorstatus($ho
# $cpudb_ref,$threshdb_ref->
#
# Determine colors for each of the CPU parameters given and possible.
#----
sub check_cpu_colorstatus {
my($host,$enterprise,$vers
my %colordb = ();
while (my($param,$value) = each(%$cpudb_ref)) {
if ($param =~ /^la/) {
# Load average
if ($value > $thresh_ref->{'la'}{'red'}
$colordb{$param} = 'red';
} elsif ($value > $thresh_ref->{'la'}{'yello
$colordb{$param} = 'yellow';
} else {
$colordb{$param} = 'green';
}
} elsif ($param eq 'cpuidle') {
if (100 - $value > $thresh_ref->{'cpu'}{'red'
$colordb{$param} = 'red';
} elsif (100 - $value > $thresh_ref->{'cpu'}{'yell
$colordb{$param} = 'yellow';
} else {
$colordb{$param} = 'green';
}
} elsif ($param =~ /^cpu/) {
if ($value > $thresh_ref->{'cpu'}{'red'
$colordb{$param} = 'red';
} elsif ($value > $thresh_ref->{'cpu'}{'yell
$colordb{$param} = 'yellow';
} else {
$colordb{$param} = 'green';
}
} else {
# Unknown
print("Unknown paramater '$param' for host '$host'");
}
} # while (my($param,$value) = each(%$cpudb_ref))
while (my($cpu,$value) = each(%$cpudb_ref)) {
unless (exists($colordb{$cpu})) {
$colordb{$cpu} = 'clear';
}
}
return \%colordb;
} # sub check_cpu_colorstatus
##### FANS #####
#----
# &fans_message($host,$commu
#
# Check fan status and compose a message accordingly
#----
sub fans_message {
my($host,$snmpsession,$ent
(my $commahost = $host) =~ s/\./\,/g;
my $message = '';
my $test = 'fans';
if ($enterprise eq 'cisco') {
# walk ciscoEnvMonFanStatusDescr/
my %descrdb = ();
if (my $result = $snmpsession->get_table(-b
$snmpoids{'ciscoEnvMonFanS
while (my($key,$value) = each(%$result)) {
$descrdb{substr($key,lengt
}
} else {
print("Unable to get fan names for Cisco $host: ".$snmpsession->error()."\
return;
}
# walk ciscoEnvMonFanState/.1.3.6
my %statedb = ();
if (my $result = $snmpsession->get_table(-b
$snmpoids{'ciscoEnvMonFanS
while (my($key,$value) = each(%$result)) {
$statedb{substr($key,lengt
$snmpsyntaxdb{'ciscoEnvMon
}
} else {
print("Unable to get fan statuses for Cisco $host: ".$snmpsession->error()."\
return;
}
# determine colors for each fan
my %fancolors = ();
while (my($index,$state) = each(%statedb)) {
if ($state eq 'normal') {
$fancolors{$index} = 'green';
} elsif ($state eq 'notPresent') {
$fancolors{$index} = 'clear';
} elsif ($state eq 'warning') {
$fancolors{$index} = 'yellow';
} else {
$fancolors{$index} = 'red';
}
} # while (my($index,$state) = each(%statedb))
# find worst color
my $worstcolor = &color_compare(values(%fan
# compose message
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
my @indices = sort { $a <=> $b } keys(%statedb);
foreach my $index (@indices) {
$message .= '&'.$fancolors{$index}.' '.$descrdb{$index}.': '.$statedb{$index}."\n";
}
} elsif ($enterprise eq 'foundry') {
# walk snChasFanDescription/.1.3.
my %descrdb = ();
if (my $result = $snmpsession->get_table(-b
$snmpoids{'snChasFanDescri
while (my($key,$value) = each(%$result)) {
$descrdb{substr($key,lengt
}
} else {
print("Unable to get fan names for Foundry $host: ".$snmpsession->error()."\
return;
}
# walk snChasFanOperStatus/.1.3.6
my %statedb = ();
if (my $result = $snmpsession->get_table(-b
$snmpoids{'snChasFanOperSt
while (my($key,$value) = each(%$result)) {
$statedb{substr($key,lengt
$snmpsyntaxdb{'snChasFanOp
}
} else {
print("Unable to get fan statuses for Foundry $host: ".$snmpsession->error()."\
return;
}
# Determine colors for each fan
my %fancolors = ();
while (my($index,$state) = each(%statedb)) {
if ($state eq 'normal') {
$fancolors{$index} = 'green';
} else {
$fancolors{$index} = 'red';
}
} # while (my($index,$state) = each(%statedb))
# Determine worst color
my $worstcolor = &color_compare(values(%fan
# Compose message
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
my @indices = sort { $a <=> $b } keys(%statedb);
foreach my $index (@indices) {
$message .= '&'.$fancolors{$index}.' '.$descrdb{$index}.': '.$statedb{$index}."\n";
}
} elsif ($enterprise eq 'netapp') {
# get envFailedFanCount/.1.3.6.1
# get envFailedFanMessage/.1.3.6
my $fancount = '';
my $fanmessage = '';
if (my $result = $snmpsession->get_request(
[$snmpoids{'envFailedFanCo
$snmpoids{'envFailedFanMes
$fancount = $result->{$snmpoids{'envFa
$fanmessage = $result->{$snmpoids{'envFa
} else {
print("Unable to get count of failed fans and message for netapp $host: ".$snmpsession->error()."\
return;
}
# Determine color
my $worstcolor = ($fancount > 0) ? 'red' : 'green';
# Compose message
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
$message .= "$fanmessage\n";
} else {
print(localtime().": ".(caller(0))[3].": Unknown enterprise '$enterprise' for host '$host'\n");
return;
} # if ($enterprise eq 'cisco')
return $message;
} # sub fans_message
##### L4, CURRENTLY ONLY FOUNDRY SERVERIRONS SUPPORTED #####
#----
# &l4_message($host,$snmpses
#
# Compose a message for a layer 4 load balancing device.
# Currently only Foundry ServerIrons supported.
#----
sub l4_message {
my($host,$snmpsession,$ent
my $test = 'l4';
# SNMPL4 CHECK - GATHER ALL DATA HERE
my %snmpl4db = ();
my %oiddb = ();
if ($enterprise eq 'foundry') {
while (my($oidtext,$oidnum) = each(%snmpoids)) {
next unless $oidtext =~ /^snL4/;
$oiddb{$oidtext} = $oidnum;
}
} else {
print(localtime().": ".(caller(0))[3].": Unknown enterprise '$enterprise'\n");
return;
}
while (my($oidtext,$oidnum) = each(%oiddb)) {
if (my $result = $snmpsession->get_table(-b
my $qoidnum = quotemeta($oidnum);
while (my($fulloid,$value) = each(%$result)) {
(my $shortoid = $fulloid) =~ s/^$qoidnum\.//;
$snmpl4db{$oidtext}{$short
}
} else {
print(localtime().": ".(caller(0))[3].": Failed to get tree for $oidtext from $host: ".$snmpsession->error()."\
return;
}
} # while (my($oidtext,$oidnum) = each(%oiddb))
# VIRTUAL SERVERS
my %vn2ip = ();
my %vip2n = ();
my %vn2as = ();
while (my($indexoid,$index) = each(%{$snmpl4db{'snL4Virt
my $virtname = $snmpl4db{'snL4VirtualServ
my $ipaddr = $snmpl4db{'snL4VirtualServ
my $adminstatus = $snmpsyntaxdb{'snL4Virtual
$vn2ip{$virtname} = $ipaddr;
$vip2n{$ipaddr} = $virtname;
$vn2as{$virtname} = $adminstatus;
} # while (my($indexoid,$index) = each(%{$snmpl4db{'snL4Virt
my %vspas = ();
while (my($indexoid,$index) = each(%{$snmpl4db{'snL4Virt
my $servername = $snmpl4db{'snL4VirtualServ
my $port = $snmpl4db{'snL4VirtualServ
if ($port eq '65535') { $port = 'default' }
my $adminstatus = $snmpsyntaxdb{'snL4Virtual
$vspas{$servername}{$port}
} # while (my($indexoid,$index) = each(%{$snmpl4db{'snL4Virt
# REAL SERVERS
my %rn2ip = (); # Name to IP
my %rip2n = (); # IP to Name
my %rsas = (); # Real server admin status
while (my($absoid,$index) = each(%{$snmpl4db{'snL4Real
my $realname = $snmpl4db{'snL4RealServerN
my $realip = $snmpl4db{'snL4RealServerI
my $adminstatus = $snmpsyntaxdb{'snL4RealSer
$rn2ip{$realname} = $realip;
$rip2n{$realip} = $realname;
$rsas{$realname} = $adminstatus;
} # while (my($absoid,$index) = each(%{$snmpl4db{'snL4Real
my %rsss = (); # Real server status state
while (my($indexoid,$index) = each(%{$snmpl4db{'snL4Real
my $realname = $snmpl4db{'snL4RealServerS
my $statusstate = $snmpsyntaxdb{'snL4RealSer
$rsss{$realname} = $statusstate;
} # while (my($indexoid,$index) = each(%{$snmpl4db{'snL4Real
my %rspas = (); # Real server port admin status
while (my($indexoid,$index) = each(%{$snmpl4db{'snL4Real
my $realname = $snmpl4db{'snL4RealServerP
my $realport = $snmpl4db{'snL4RealServerP
if ($realport eq '65535') { $realport = 'default' }
my $adminstatus = $snmpsyntaxdb{'snL4RealSer
$rspas{$realname}{$realpor
}
my %rspss = (); # Real server port status state
while (my($indexoid,$index) = each(%{$snmpl4db{'snL4Real
my $realname = $snmpl4db{'snL4RealServerP
my $realport = $snmpl4db{'snL4RealServerP
if ($realport eq '65535') { $realport = 'default' }
my $statusstate = $snmpsyntaxdb{'snL4RealSer
$rspss{$realname}{$realpor
}
# check-as-proxy: look for real servers which are listed by name in bb-hosts
# but don't have the check enabled for which they're offering services
# via the L4 load balancer.
my @realhostlist = sort(keys(%rsas));
foreach my $hostname (@realhostlist) {
if (exists($l4_bbhosts_ref->{
(my $commahost = $hostname) =~ s/\./\,/g;
foreach my $realport (keys(%{$rspas{$hostname}}
next if $realport eq 'default';
my $portname = scalar(getservbyport($real
unless (defined($portname)) {
print(localtime().": ".(caller(0))[3].": Port number $realport has no defined service.\n");
next;
}
if (exists($l4_bbhosts_ref->{
next; # BigBrother is already monitoring it.
}
# If I get this far, I have a service that needs to be reported.
my $color = 'green';
my $message = "Port $realport service $portname is funtioning normally";
if ($rspas{$hostname}{$realpo
$color = 'clear';
$message = "Port $realport service $portname has been disabled on the ServerIron";
} elsif ($rspss{$hostname}{$realpo
$color = 'clear';
$message = "Port $realport service $portname has been disabled on the ServerIron";
} elsif ($rspss{$hostname}{$realpo
$color = 'yellow';
$message = "Port $realport service $portname is in state: '".$rspss{$hostname}{$real
}
$message .= " according to $host";
$message = "status $commahost.$portname $color ".scalar(localtime)."\n$me
$message .= "$Script Version: $VERSION\n";
if ($is_commandline) {
print("$ENV{'BBHOME'}/bin/
} else {
system("$ENV{'BBHOME'}/bin
}
} # foreach my $realport (keys(%{$rspas{$realname}}
# If $ENV{'CONNTEST'} is true and 'noconn' is defined as a service,
# then the snL4RealServerAdminStatus and snL4RealServerStatusState
# are used to determine the 'conn' status.
if ((exists($ENV{'CONNTEST'})
($ENV{'CONNTEST'} eq 'TRUE') &&
(exists($l4_bbhosts_ref->{
my $color = 'green';
my $message = "Server $hostname is responding to layer 3 health checks";
if ($rsas{$hostname} eq 'disabled') {
$color = 'clear';
$message = "Server $hostname has been disabled on the ServerIron";
} elsif ($rsss{$hostname} eq 'serverdisabled') {
$color = 'clear';
$message = "Server $hostname has been disabled on the ServerIron";
} elsif ($rsss{$hostname} ne 'serveractive') {
$color = 'yellow';
$message = "Server $hostname is in state: '".$rsss{$hostname}."'";
}
$message .= " according to $host";
$message = "status $commahost.conn $color ".scalar(localtime)."\n$me
$message .= "$Script Version: $VERSION\n";
if ($is_commandline) {
print("$ENV{'BBHOME'}/bin/
} else {
system("$ENV{'BBHOME'}/bin
}
} # If i want to determine the 'conn' status
} # if (exists($bbhosts_ref->{$ho
} # foreach my $hostname
# BINDS
# Need to be able to build tree from Virtual Server ports
# down to real server ports
# BIND TREE
# Shopping list:
# 'snL4BindIndex' => '1.3.6.1.4.1.1991.1.1.4.6.
# 'snL4BindVirtualServerName
# 'snL4BindVirtualPortNumber
# 'snL4BindRealServerName' => '1.3.6.1.4.1.1991.1.1.4.6.
# 'snL4BindRealPortNumber' => '1.3.6.1.4.1.1991.1.1.4.6.
my %binddb = ();
while (my($oidtext,$oidnum) = each(%snmpoids)) {
next unless $oidtext =~ /^snL4Bind/;
if (my $result = $snmpsession->get_table(-b
my $qoidnum = quotemeta($oidnum);
while (my($fulloid,$value) = each(%$result)) {
(my $shortoid = $fulloid) =~ s/^$qoidnum\.//;
$binddb{$oidtext}{$shortoi
}
} else {
print(localtime().": ".(caller(0))[3].": Failed to get tree for $oidtext from $host: ".$snmpsession->error()."\
return;
} # if (my(%subdb) = &simpletree
} # while (my($oidtext,$oidnum) = each(%oiddb))
my %bindtree = ();
while (my($indexoid,$index) = each(%{$binddb{'snL4BindIn
my $virtualname = $binddb{'snL4BindVirtualSe
my $virtualport = $binddb{'snL4BindVirtualPo
if ($virtualport eq '65535') { $virtualport = 'default' }
my $realname = $binddb{'snL4BindRealServe
my $realport = $binddb{'snL4BindRealPortN
if ($realport eq '65535') { $realport = 'default' }
$bindtree{$virtualname}{$v
}
# COMPOSE PAGE
# Tables done in plain text for now to avoid HTML table tags for message
# size limit considerations, but HTML might be more efficient than manually spacing
# items.
my $message = '';
my $worstcolor = 'green';
my @collen;
@collen = (); # Maximum lengths of items in each column
my @virtservs = sort { $a cmp $b } keys(%vn2as);
if ($l4_show_virtservers) {
# VIRTUAL SERVER SECTION - Green or clear
$collen[0] = 5;
$collen[1] = length('Name');
$collen[2] = length('IP Address');
$collen[3] = length('Port');
$collen[4] = length('Admin Status');
$message .= "<B>VIRTUAL SERVERS</B>\n";
# Make alphebetized list of virtual servers
foreach my $virtname (@virtservs) {
my $adminstatus = $vn2as{$virtname};
my $virtip = $vn2ip{$virtname};
$collen[1] = ($collen[1] > length($virtname)) ? $collen[1] : length($virtname);
$collen[2] = ($collen[2] > length($virtip)) ? $collen[2] : length($virtip);
$collen[4] = ($collen[4] > length($adminstatus)) ? $collen[4] : length($adminstatus);
while (my($port) = each(%{$vspas{$virtname}})
my $adminstatus = $vspas{$virtname}{$port};
$collen[3] = ($collen[3] > length($port)) ? $collen[3] : length($port);
$collen[4] = ($collen[4] > length($adminstatus)) ? $collen[4] : length($adminstatus);
}
}
$message .= sprintf(" %".($collen[0])."s %".($collen[1]+1)."s %".($collen[2]+1)."s %".($collen[3]+1)."s %".($collen[4]+1)."s\n", 'Color', 'Name', 'IP Address', 'Port', 'Admin Status');
foreach my $virtname (@virtservs) {
my $adminstatus = $vn2as{$virtname};
my $virtip = $vn2ip{$virtname};
my $color = ($adminstatus eq 'enabled') ? 'green' : 'clear';
# $message .= " &$color $virtname / $virtip - $adminstatus\n";
$message .= sprintf(" &%".($collen[0])."s %".($collen[1]+1)."s %".($collen[2]+1)."s %".($collen[3]+1)."s %".($collen[4]+1)."s\n", $color, $virtname, $virtip, '',$adminstatus);
while (my($port) = each(%{$vspas{$virtname}})
my $adminstatus = $vspas{$virtname}{$port};
my $color = ($adminstatus eq 'enabled') ? 'green' : 'clear';
$message .= sprintf(" &%".($collen[0])."s %".($collen[1]+1)."s %".($collen[2]+1)."s %".($collen[3]+1)."s %".($collen[4]+1)."s\n", $color,'','',$port,$admins
}
} # foreach my $virtname (@virtservs)
} # if ($show_virtservers)
if ($l4_show_realservers) {
# REAL SERVER SECTION
$message .= "\n<B>REAL SERVERS</B>\n";
my @realservs = sort { $a cmp $b } keys(%rsas);
my %realcolors = ();
@collen = ();
$collen[0] = length("Color");
$collen[1] = length("Name");
$collen[2] = length("IP Address");
$collen[3] = length("Port");
$collen[4] = length("Admin Status");
$collen[5] = length("State");
foreach my $realserv (@realservs) {
my $servadminstatus = $rsas{$realserv};
my $servstatusstate = $rsss{$realserv};
my $ipaddr = $rn2ip{$realserv};
$collen[1] = ($collen[1] > length($realserv)) ? $collen[1] : length($realserv);
$collen[2] = ($collen[2] > length($ipaddr)) ? $collen[2] : length($ipaddr);
$collen[4] = ($collen[4] > length($servadminstatus)) ? $collen[4] : length($servadminstatus);
$collen[5] = ($collen[5] > length($servstatusstate)) ? $collen[5] : length($servstatusstate);
while (my($realport) = each(%{$rspas{$realserv}})
my $adminstatus = $rspas{$realserv}{$realpor
my $statusstate = $rspss{$realserv}{$realpor
$collen[3] = ($collen[3] > length($realport)) ? $collen[3] : length($realport);
$collen[4] = ($collen[4] > length($adminstatus)) ? $collen[4] : length($adminstatus);
$collen[5] = ($collen[5] > length($statusstate)) ? $collen[5] : length($statusstate);
} # foreach my $realport (@portlist)
} # foreach my $realserv (@realservs)
$message .= sprintf(" %".($collen[0])."s %".($collen[1] + 1)."s %".($collen[2] + 1)."s %".($collen[3] + 1)."s %".($collen[4] + 1)."s %".($collen[5] + 1)."s\n", 'Color', 'Name', 'IP Address', 'Port', 'Admin Status', 'State');
foreach my $realserv (@realservs) {
# Color is determined by admin status and statuses of
# subsidiary ports
my $servercolor = 'green';
my %portcolors = ();
my $servadminstatus = $rsas{$realserv};
my $servstatusstate = $rsss{$realserv};
my $ipaddr = $rn2ip{$realserv};
while (my($port,$portstate) = each(%{$rspss{$realserv}})
if ($portstate eq 'active') {
$portcolors{$port} = 'green';
} elsif ($portstate eq 'unbound') {
$portcolors{$port} = 'clear';
} elsif ($portstate eq 'disabled') {
$portcolors{$port} = 'clear';
} elsif ($portstate eq 'enabled') {
$portcolors{$port} = 'clear';
} else {
if ($port eq 'default') {
$portcolors{$port} = 'clear';
} elsif ($servstatusstate eq 'serverenabled') {
$portcolors{$port} = 'clear';
} elsif ($servadminstatus ne 'enabled') {
$portcolors{$port} = 'clear';
} else {
$portcolors{$port} = 'yellow';
$worstcolor = 'yellow';
}
}
}
while (my($port,$portstatus) = each(%{$rspas{$realserv}})
if ($portstatus eq 'enabled') {
if ($portcolors{$port} eq 'yellow') {
$servercolor = 'yellow';
$worstcolor = 'yellow';
}
} else {
$portcolors{$port} = 'clear';
}
}
# I really do not like this logic. Should be cleaner.
if ($servstatusstate eq 'serveractive') {
# Do nothing
} elsif ($servstatusstate eq 'serverenabled') {
$servercolor = 'clear';
foreach my $port (keys(%portcolors)) { $portcolors{$port} = 'clear' }
} else {
$servercolor = 'yellow';
$worstcolor = 'yellow';
}
unless ($servadminstatus eq 'enabled') {
$servercolor = 'clear';
foreach my $port (keys(%portcolors)) { $portcolors{$port} = 'clear' }
}
$message .= sprintf(" &%".($collen[0])."s %".($collen[1] + 1)."s %".($collen[2] + 1)."s %".($collen[3] + 1)."s %".($collen[4] + 1)."s %".($collen[5] + 1)."s\n", $servercolor, $realserv, $ipaddr, '', $servadminstatus, $servstatusstate);
my @portlist = sort { $a <=> $b } keys(%portcolors);
foreach my $realport (@portlist) {
my $portcolor = $portcolors{$realport};
my $adminstatus = $rspas{$realserv}{$realpor
my $statusstate = $rspss{$realserv}{$realpor
# $message .= " &$portcolor $realport - $adminstatus / $statusstate\n";
$message .= sprintf(" &%".($collen[0])."s %".($collen[1] + 1)."s %".($collen[2] + 1)."s %".($collen[3] + 1)."s %".($collen[4] + 1)."s %".($collen[5] + 1)."s\n", $portcolor, '', '', $realport, $adminstatus, $statusstate);
}
$realcolors{$realserv} = $servercolor;
} # foreach my $realserv (@realservs)
} # if ($show_realservers)
if ($l4_show_bindtree) {
# BINDTREE DISPLAYED
$message .= "\n<B>BINDS</B>\n";
# $bindtree{$virtname}{$virt
# First, colors.
my %realportcolors = ();
my %realservcolors = ();
my %virtportcolors = ();
my %virtservcolors = ();
foreach my $virtname (@virtservs) {
$virtservcolors{$virtname}
my @virtports = sort(keys(%{$bindtree{$vir
if ($vn2as{$virtname} eq 'disabled') {
$virtservcolors{$virtname}
foreach my $virtport (@virtports) {
$virtportcolors{$virtname}
my @realnames = sort { $a cmp $b } keys(%{$bindtree{$virtname
foreach my $realname (@realnames) {
$realservcolors{$virtname}
my @realports = sort(keys(%{$bindtree{$vir
foreach my $realport (@realports) {
$realportcolors{$virtname}
}
} # foreach my $realname (@realnames)
} # foreach my $virtport (@virtports)
} else {
foreach my $virtport (@virtports) {
# Decide the color of each virtual port
my @realnames = sort { $a cmp $b } keys(%{$bindtree{$virtname
if ($vspas{$virtname}{$virtpo
$virtportcolors{$virtname}
foreach my $realname (@realnames) {
$realservcolors{$virtname}
my @realports = sort(keys(%{$bindtree{$vir
foreach my $realport (@realports) {
$realportcolors{$virtname}
}
}
} else {
foreach my $realname (@realnames) {
$realservcolors{$virtname}
# Decide the color of each real server
my @realports = sort(keys(%{$bindtree{$vir
# if (($rsas_ref->{$realname} eq 'disabled') || ($rsss_ref->{$realname} eq 'serverenabled'))
# down servers can be serverenabled
if ($rsas{$realname} eq 'disabled') {
$realservcolors{$virtname}
foreach my $realport (@realports) {
$realportcolors{$virtname}
} # foreach my $realport (@realports)
} else {
foreach my $realport (@realports) {
$realportcolors{$virtname}
# Decide the color of each port
# WARNING: snL4RealServerPortStatusSt
if (($rspas{$realname}{$realp
($rspss{$realname}{$realpo
$realportcolors{$virtname}
} else {
if (($realport eq 'default') &&
($rspss{$realname}{$realpo
$realportcolors{$virtname}
} elsif ($rspss{$realname}{$realpo
$realportcolors{$virtname}
}
}
} # foreach my $realport (@realports)
# Look at the color of each port.
# If any are yellow set the server yellow.
# Don't want to turn red here.
$realservcolors{$virtname}
} # if ($rsas_ref->{$realname} eq 'disabled')
} # foreach my $realname (@realservs)
# Look at the color of each real server.
# If any are yellow set the virtual port yellow.
# If all are yellow set the virtual port red.
$virtportcolors{$virtname}
} # if ($vspas_ref->{$virtname}{$
} # foreach my $virtport (@virtports)
# Look at the color of each virtual port.
# If any are yellow set the virt server yellow.
# If any are red set the virtual server red.
$virtservcolors{$virtname}
} # if ($vsas_ref->{$virtname} eq 'disabled')
} # foreach my $virtname (@virtservs)
# Then, show tree
foreach my $virtname (@virtservs) {
$message .= " &".$virtservcolors{$virtna
if ($virtservcolors{$virtname
$worstcolor = 'red';
} elsif (($virtservcolors{$virtnam
$worstcolor = 'yellow';
}
my @virtports = sort(keys(%{$bindtree{$vir
foreach my $virtport (@virtports) {
$message .= " &".$virtportcolors{$virtna
my @realnames = sort { $a cmp $b } keys(%{$bindtree{$virtname
foreach my $realname (@realnames) {
$message .= " &".$realservcolors{$virtna
my @realports = sort(keys(%{$bindtree{$vir
foreach my $realport (@realports) {
$message .= " &".$realportcolors{$virtna
}
} # foreach my $realserv (@realservs)
} # foreach my $virtport (@virtports)
$message .= "\n";
} # foreach my $virtname (@virtservs)
} # if ($show_bindtree)
# HEADER GENERATED
(my $commaname = $host) =~ s/\./\,/g;
$message = "status $commaname.$test $worstcolor ".scalar(localtime)."\n\n$
return $message;
} # sub l4_message
#----
# &l4_read_bbhosts()
#
# Read bb-hosts specifically for the benefit of comparing with L4 monitoring.
# Specific URLs don't matter as much as the fact that http or https is offered.
# Although many folks use dig with BB to check DNS, this extension creates
# the column as dns if neither dig nor dns already exist for a given host.
# If a service is mentioned with ? or ! in front, it's an indication that
# BigBrother is taking care of the checking. Same if there's a :s, :q, or :Q
# at the end.
#----
sub l4_read_bbhosts {
my $infh = new FileHandle;
unless ($infh->open("< $ENV{'BBHOME'}/etc/bb-host
print("Unable to open $ENV{'BBHOME'}/etc/bb-host
return;
}
my %bbhostsdb = ();
while (my $line = $infh->getline()) {
$line =~ s/^\s*#.*$//g;
next unless $line =~ /\S/;
if ($line =~ /^(\d{1,3}.\d{1,3}.\d{1,3}
my($ipaddr,$hostname,$serv
$services = '' unless defined($services);
$services =~ s/^\s+//g;
$services =~ s/\s+$//g;
$services =~ s/^#\s*//;
my @svclist = split(' ',$services);
foreach my $service (@svclist) {
# Don't worry about http with a funny port.
$service =~ s|^http://.*$|http|;
$service =~ s|^https://.*$|https|;
next if $service =~ /^BBRELAY/;
$service =~ s/:[sqQ]$//;
$service =~ s/^[\?\!]//;
# Custom TCP ports by name... yes I can do this.
# Trick is it means I do not need bb-xsnmpl4's help with this port.
my($servname,$servport);
if ($service =~ /^(\w+):(\d+)$/) {
($servname,$servport) = ($1,$2);
} elsif ($service =~ /^(\w+)$/) {
$servname = $1;
$servport = scalar(getservbyname($serv
$servport = 1 unless defined($servport); # Need a placeholder
} else {
# Quietly ignore
# die("OOPS no patterns matched");
}# if ($service =~ /^(\w+):(\d+)$/)
$bbhostsdb{$hostname}{$ser
} # foreach my $service (@svclist)
} # If the line contains an IP address at the beginning
} # while (my $line = $infh->getline())
return \%bbhostsdb;
} # sub l4_read_bbhosts
#----
# &is_l4switch($host,$snmpse
#
# Check whether or not this is in fact an L4 switch
# for which I can gather data.
#----
sub is_l4switch {
my($host,$snmpsession) = @_;
if (my $result = $snmpsession->get_request(
my $objectoid = $result->{$snmpoids{'sysOb
# Is it a Foundry ServerIron?
if (($objectoid eq $snmpoids{'snSI'}) ||
($objectoid eq $snmpoids{'snSIXL'}) ||
($objectoid eq '.1.3.6.1.4.1.1991.1.1')) { # Very old BigServerIrons
# Does it have anything I can monitor?
if (my $result = $snmpsession->get_table(-b
if (scalar(keys(%$result))) {
return 1;
}
}
}
} else {
print(localtime().": ".(caller(0))[3].": Failed to get sysObjectID from $host: ".$snmpsession->error()."\
return;
}
return 0;
} # sub is_l4switch
##### PORTS #####
#----
# &ports_message($host,$snmp
#
# Check port speed and duplex.
# Look for ports on auto that have chosen 100half
#----
sub ports_message {
my($host,$snmpsession,$ent
(my $commahost = $host) =~ s/\./\,/g;
my $message = '';
my $test = 'ports';
my %ifidx2desc = (); # 1.3.6.1.2.1.2.2.1.2
my %ifidx2speed = (); # 1.3.6.1.2.1.2.2.1.5
my %ifidx2operstat = (); # 1.3.6.1.2.1.2.2.1.8
my %ifidx2alias = (); # 1.3.6.1.2.1.31.1.1.1.18
# Not present in older Foundry stackables
if (my $result = $snmpsession->get_table(-b
while (my($oid,$statuscode) = each(%$result)) {
(my $index = $oid) =~ s/^.*\.//g;
$ifidx2operstat{$index} = $snmpsyntaxdb{'ifOperStatu
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get ifOperStatus for $host: ".$snmpsession->error()."\
return;
}
# Build a list of ifDescr OIDs I want to get
# Some oddballs like ServerIrons have ifDescrs that show up in walk and get-next but not get
if (my $result = $snmpsession->get_table(-b
foreach my $index (keys(%ifidx2operstat)) {
if (exists($result->{"$snmpoi
my $descr = $result->{"$snmpoids{'ifDe
if ($descr =~ /^null|^vlan|^lb|^loopback
delete($ifidx2operstat{$in
} else {
$ifidx2desc{$index} = $descr;
}
}
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get ifDescr for host $host: ".$snmpsession->error()."\
}
# my @descroidlist = keys(%ifidx2operstat);
# foreach my $index (@descroidlist) {
# if (my $result = $snmpsession->get_request(
# my $descr = $result->{"$snmpoids{'ifDe
# if ($descr =~ /^null|^vlan|^lb|^loopback
# delete($ifidx2operstat{$in
# } else {
# $ifidx2desc{$index} = $descr;
# }
# } else {
# print(localtime().": ".(caller(0))[3].": Unable to get ifDescr for host $host index $index: ".$snmpsession->error()."\
# } # if (my $result = $snmpsession->get_request(
# } # foreach my $index (@descroidlist)
# Try to build a list of ifAlias OIDs
# Best not to try them all in case ifAlias isn't supported
my @indexlist = keys(%ifidx2desc);
my $has_ifalias = 0;
foreach my $index (@indexlist) {
if (my $result = $snmpsession->get_request(
$ifidx2alias{$index} = $result->{"$snmpoids{'ifAl
} else {
$has_ifalias = 0;
last;
}
}
# Find actual speeds of interfaces that are up
my @upindexlist = grep { $ifidx2operstat{$_} eq 'up' } keys(%ifidx2operstat);
foreach my $index (@upindexlist) {
if (my $result = $snmpsession->get_request(
$ifidx2speed{$index} = $result->{"$snmpoids{'ifSp
} else {
print(localtime().": ".(caller(0))[3].": Unable to get ifSpeed for $host index $index: ".$snmpsession->error()."\
return;
}
} # foreach my $index (@upindexlist)
# No one seems to support dot3StatsDuplexStatus, but it doesn't cover auto anyways.
# Operational speed and status can always be determined from ifSpeed and ifOperStatus
my %ifidx2confspeed = ();
my %ifidx2confduplx = ();
my %ifidx2duplx = ();
if ($enterprise eq 'cisco') {
# c2900PortDuplexState determines configuration for full, half, or auto
# 1.3.6.1.4.1.9.9.87.1.4.1.1
# c2900PortDuplexStatus determines actual status for full or half.
# 1.3.6.1.4.1.9.9.87.1.4.1.1
# (No point in checking for ports set to full or half.)
# c2900PortAdminSpeed
# Speed settings for a port: auto, 10M,100M,155M
# 1.3.6.1.4.1.9.9.87.1.4.1.1
my %port2ifindex = ();
my %ifindex2port = ();
if (my $result = $snmpsession->get_table(-b
while (my($oidnum,$ifindex) = each(%$result)) {
(my $portnum = $oidnum) =~ s/.*\.//g;
$port2ifindex{$portnum} = $ifindex;
$ifindex2port{$ifindex} = $portnum;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get c2900PortIfIndex for cisco $host: ".$snmpsession->error()."\
return;
}
while (my($index,$status) = each(%ifidx2operstat)) {
next unless $status eq 'up';
my $port = $ifindex2port{$index};
if (my $result = $snmpsession->get_request(
$ifidx2confspeed{$index} = $snmpsyntaxdb{'c2900PortAd
} else {
print(localtime().": ".(caller(0))[3].": Unable to get c2900PortAdminSpeed for $host index $index port $port: ".$snmpsession->error()."\
}
if (my $result = $snmpsession->get_request(
$ifidx2confduplx{$index} = $snmpsyntaxdb{'c2900PortDu
} else {
print(localtime().": ".(caller(0))[3].": Unable to get c2900PortDuplexState for $host index $index port $port: ".$snmpsession->error()."\
}
if ($ifidx2confduplx{$index} eq 'auto') {
if (my $result = $snmpsession->get_request(
$ifidx2duplx{$index} = $snmpsyntaxdb{'c2900PortDu
} else {
print(localtime().": ".(caller(0))[3].": Unable to get c2900PortDuplexStatus for $host index $index port $port.\n");
}
} else { # if ($confduplex eq 'auto')
$ifidx2duplx{$index} = $ifidx2confduplx{$index};
}
} # while (my($index,$status) = each(%ifidx2operstat))
} elsif ($enterprise eq 'foundry') {
# snSwPortInfoChnMode (duplex)
# 1.3.6.1.4.1.1991.1.1.3.3.1
# snSwPortInfoSpeed (conf speed&auto)
# 1.3.6.1.4.1.1991.1.1.3.3.1
# snSwPortIfIndex translates port number to interface number,
# 1.3.6.1.4.1.1991.1.1.3.3.1
# snSwPortName, same as ifAlias, use only if %ifidx2alias is empty
# 1.3.6.1.4.1.1991.1.1.3.3.1
# my $snSwPortInfoChnMode = '.1.3.6.1.4.1.1991.1.1.3.3
# my $snSwPortInfoSpeed = '.1.3.6.1.4.1.1991.1.1.3.3
# my $snSwPortIfIndex = '.1.3.6.1.4.1.1991.1.1.3.3
# my $snSwPortName = '.1.3.6.1.4.1.1991.1.1.3.3
my %port2ifindex = ();
my %ifindex2port = ();
if (my $result = $snmpsession->get_table(-b
while (my($oidnum,$ifindex) = each(%$result)) {
(my $portnum = $oidnum) =~ s/.*\.//g;
$port2ifindex{$portnum} = $ifindex;
$ifindex2port{$ifindex} = $portnum;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get snSwPortIfIndex for foundry $host: ".$snmpsession->error()."\
return;
}
while (my($index,$status) = each(%ifidx2operstat)) {
unless (exists($ifindex2port{$ind
print(localtime().": ".(caller(0))[3].": No port number exists for index '$index' host '$host'\n");
next;
}
unless (defined($ifindex2port{$in
print(localtime().": ".(caller(0))[3].": No port number defined for index '$index' host '$host'\n");
next;
}
if (length($ifindex2port{$ind
print(localtime().": ".(caller(0))[3].": Port number defined for index '$index' host '$host' has zero length.\n");
next;
}
my $portnum = $ifindex2port{$index};
unless (exists($ifidx2alias{$inde
if (my $result = $snmpsession->get_request(
$ifidx2alias{$index} = $result->{"$snmpoids{'snSw
} else {
print(localtime().": ".(caller(0))[3].": Unable to get for snSwPortName foundry $host: ".$snmpsession->error()."\
}
}
next unless $status eq 'up';
# Get adminspeed and duplex in one go
if (my $result = $snmpsession->get_request(
["$snmpoids{'snSwPortInfoS
"$snmpoids{'snSwPortInfoCh
my $adminspeed = $snmpsyntaxdb{'snSwPortInf
$ifidx2confspeed{$index} = $adminspeed;
if ($adminspeed eq 'auto') {
$ifidx2confduplx{$index} = 'auto';
}
my $duplex = $snmpsyntaxdb{'snSwPortInf
$ifidx2duplx{$index} = $duplex;
unless ($adminspeed eq 'auto') {
$ifidx2confduplx{$index} = $duplex;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get for snSwPortInfoSpeed and snSwPortInfoChnMode foundry $host port number '$portnum': ".$snmpsession->error()."\
next;
}
} # while (my($index,$status) = each(%ifidx2operstat))
} else {
print(localtime().": ".(caller(0))[3]." Unknown enterprise $enterprise");
return;
}
my %ifcolordb = ();
my $worstcolor = 'green';
$message = "</pre>";
$message .= "<table>";
$message .= "<tr><td>Color</td><td>Int
@indexlist = sort { $a <=> $b } keys(%ifidx2operstat);
foreach my $index (@indexlist) {
my $status = $ifidx2operstat{$index};
if ($status eq 'up') {
if (($ifidx2confduplx{$index}
($ifidx2duplx{$index} eq 'half') &&
($ifidx2speed{$index} == 100000000)) {
$ifcolordb{$index} = 'yellow';
$worstcolor = 'yellow';
} else {
$ifcolordb{$index} = 'green';
}
} else {
$ifcolordb{$index} = 'clear';
}
$message .= "<tr>";
$message .= "<td>";
$message .= '&'."$ifcolordb{$index}</t
if ($status eq 'up') {
my $confspeed = $ifidx2confspeed{$index};
unless ($confspeed eq 'auto') { $confspeed = sprintf("%dMbps",($confspe
my $truespeed = $ifidx2speed{$index};
unless ($truespeed eq 'auto') { $truespeed = sprintf("%dMbps",($truespe
my $confduplex = $ifidx2confduplx{$index};
my $trueduplex = $ifidx2duplx{$index};
$message .= "<td>$confspeed</td><td>$c
}
$message .= "</tr>";
$message .= "\n";
}
$message .= "</table>\n<pre>\n";
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n$me
return $message;
} # sub ports_message
##### POWER #####
#----
# &power_message($host,$snmp
#
# Gather information on power supply statuses, determine color, and create a message.
#----
sub power_message {
my($host,$snmpsession,$ent
(my $commahost = $host) =~ s/\./\,/g;
my $message = '';
my $test = 'power';
if ($enterprise eq 'apc') {
# List of OIDs to collect:
# upsBasicIdentModel
# upsBasicBatteryStatus
# upsBasicOutputStatus
# upsAdvBatteryCapacity
# upsAdvBatteryTemperature
# upsAdvBatteryRunTimeRemain
# upsAdvBatteryReplaceIndica
# upsAdvInputLineVoltage
# upsAdvOutputLoad
# upsAdvOutputVoltage
# upsBasicBatteryLastReplace
my $result = undef;
unless ($result = $snmpsession->get_request(
$snmpoids{'upsBasicIdentMo
$snmpoids{'upsBasicBattery
$snmpoids{'upsBasicOutputS
$snmpoids{'upsAdvBatteryCa
$snmpoids{'upsAdvBatteryRu
$snmpoids{'upsAdvBatteryRe
$snmpoids{'upsAdvInputLine
$snmpoids{'upsAdvOutputLoa
$snmpoids{'upsAdvOutputVol
$snmpoids{'upsBasicBattery
])) {
print(localtime().": ".(caller(0))[3].": Unable to check UPS status for APC $host: ".$snmpsession->error()."\
return;
}
# Digest results
my $model = $result->{'upsBasicIdentMo
my $battstatus = $snmpsyntaxdb{'upsBasicBat
my $outstatus = $snmpsyntaxdb{'upsBasicOut
my $capacity = $result->{'upsAdvBatteryCa
my $remain = $result->{'upsAdvBatteryRu
my $replace = $snmpsyntaxdb{'upsAdvBatte
my $inputvoltage = $result->{'upsAdvInputLine
my $outputload = $result->{'upsAdvOutputLoa
my $outputvoltage = $result->{'upsAdvOutputVol
my $replacedate = $result->{'upsBasicBattery
# Determine state
my $worstcolor = 'green';
if ($battstatus eq 'batteryLow') {
$worstcolor = 'red';
$message .= "Battery time remaining low.\n";
}
if ($replace eq 'batteryNeedsReplacing') {
$worstcolor = 'red';
$message .= "Battery needs replacing.\n";
}
# upsAdvOutputLoad, say yellow for 90 and red for 95.
if ($outputload > 95) {
$worstcolor = 'red';
$message .= "Output load above 95 percent.\n";
} elsif ($outputload > 90) {
$worstcolor = ($worstcolor eq 'green') ? 'yellow' : $worstcolor;
$message .= "Output load above 90 percent.\n";
}
# Collect the following if currently on battery power.
# upsAdvInputLineFailCause
# upsBasicBatteryTimeOnBatte
if ($outstatus eq 'onBattery') {
$result = undef;
unless ($result = $snmpsession->get_request(
$snmpoids{'upsAdvInputLine
$snmpoids{'upsBasicBattery
])) {
print(localtime().": ".(caller(0))[3].": Unable to check line fail cause for APC $host: ".$snmpsession->error()."\
return;
}
my $failcause = $snmpsyntaxdb{'upsAdvInput
my $timeonbatt = $result->{'upsBasicBattery
$message .= "Reason for input line failure: $failcause\n";
$message .= "Time elapsed since switching to battery: $timeonbatt seconds\n";
}
# Compose remainder of message.
$message .= "Vendor: $enterprise\n";
$message .= "Model: $model\n";
$message .= "Battery Status: $battstatus\n";
$message .= "Current State of the UPS: $outstatus\n";
$message .= "Remaining Battery Capacity: $capacity\n";
$message .= "Time Remaining Before Battery Exhaustion: $remain seconds\n";
$message .= "Battery Replacement Indicator: $replace\n";
$message .= "Input Voltage: $replace\n";
$message .= "UPS Load: $outputload %\n";
$message .= "Output Voltage: $outputvoltage %\n";
$message .= "Date Batteries Last Replaced: $replacedate\n";
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n$
} elsif ($enterprise eq 'cisco') {
# walk ciscoEnvMonSupplyStatusDes
my %descrdb = ();
if (my $result = $snmpsession->get_table(-b
$snmpoids{'ciscoEnvMonSupp
while (my($key,$value) = each(%$result)) {
$key = substr($key,length($snmpoi
$descrdb{$key} = $value;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get power supply names for Cisco $host: ".$snmpsession->error()."\
return;
}
# walk ciscoEnvMonSupplyState/.1.
my %statedb = ();
if (my $result = $snmpsession->get_table(-b
while (my($key,$value) = each(%$result)) {
$key = substr($key,length($snmpoi
$statedb{$key} = $snmpsyntaxdb{'ciscoEnvMon
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get power supply states for Cisco $host: ".$snmpsession->error()."\
return;
}
# walk ciscoEnvMonSupplySource/.1
my %sourcedb = ();
if (my $result = $snmpsession->get_table(-b
while (my($key,$value) = each(%$result)) {
$key = substr($key,length($snmpoi
$sourcedb{$key} = $snmpsyntaxdb{'ciscoEnvMon
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get power supply sources for Cisco $host: ".$snmpsession->error()."\
return;
}
# determine colors
my %powercolors = ();
while (my($index,$state) = each(%statedb)) {
if ($state eq 'normal') {
$powercolors{$index} = 'green';
} elsif ($state eq 'warning') {
$powercolors{$index} = 'yellow';
} else {
$powercolors{$index} = 'red';
}
} # while (my($index,$state) = each(%statedb))
# find worst color
my $worstcolor = &color_compare(values(%sta
# compose message
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
my @indices = sort { $a <=> $b } keys(%statedb);
foreach my $index (@indices) {
$message .= '&'.$powercolors{$index}.'
if (exists($sourcedb{$index})
$message .= ", source: ".$sourcedb{$index}
}
$message .= ", state: ".$statedb{$index}."\n";
} # foreach my $index (@indices)
} elsif ($enterprise eq 'foundry') {
# walk snChasPwrSupplyDescription
# my $snChasPwrSupplyDescriptio
my %descrdb = ();
if (my $result = $snmpsession->get_table(-b
while (my($key,$value) = each(%$result)) {
$key = substr($key,length($snmpoi
$descrdb{$key} = $value;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get power supply names for Foundry $host: ".$snmpsession->error()."\
return;
}
# walk snChasPwrSupplyOperStatus/
# my %statenames = ('1' => 'other', '2' => 'normal', '3' => 'failure');
# my $snChasPwrSupplyOperStatus
my %statedb = ();
if (my $result = $snmpsession->get_table(-b
while (my($key,$value) = each(%$result)) {
$key = substr($key,length($snmpoi
$statedb{$key} = $snmpsyntaxdb{'snChasPwrSu
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get power supply statuses for Foundry $host: ".$snmpsession->error()."\
return;
}
# determine colors
my %powercolors = ();
while (my($index,$state) = each(%statedb)) {
if ($state eq 'normal') {
$powercolors{$index} = 'green';
} else {
$powercolors{$index} = 'red';
}
} # while (my($index,$state) = each(%statedb))
# find worst color
my $worstcolor = &color_compare(values(%pow
# compose message
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
my @indices = sort { $a <=> $b } keys(%statedb);
foreach my $index (@indices) {
$message .= '&'.$powercolors{$index}.'
}
} elsif ($enterprise eq 'netapp') {
# get envFailedPowerSupplyCount/
# get envFailedPowerSupplyMessag
my $powercount = 0;
my $powermessage = '';
if (my $result = $snmpsession->get_request(
[$snmpoids{'envFailedPower
$snmpoids{'envFailedPowerS
$powercount = $result->{$snmpoids{'envFa
$powermessage = $result->{$snmpoids{'envFa
} else {
print("Unable to get count of failed power supplies and failed power message for netapp $host: ".$snmpsession->error()."\
return;
}
# determine color
my $worstcolor = ($powercount > 0) ? 'red' : 'green';
# Compose message
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
$message .= "$powermessage\n";
} else {
print(localtime().": ".(caller(0))[3].": Unknown enterprise '$enterprise' for host '$host'\n");
return;
} # # if ($enterprise eq 'cisco')
return $message;
} # sub power_message
##### TEMPERATURE #####
#----
# &temperature_message($host
#
# Gather information on temperature statuses, determine color, and create a message.
#----
sub temperature_message {
my($host,$snmpsession,$ent
(my $commahost = $host) =~ s/\./\,/g;
my $message = '';
my $test = 'temperature';
if ($enterprise eq 'apc') {
# For now, output enough temperature data to graph it.
# Don't worry about status for now.
my $result = undef;
unless ($result = $snmpsession->get_request(
$snmpoids{'upsAdvBatteryTe
print(localtime().": ".(caller(0))[3].": Unable to check temperature for APC $host: ".$snmpsession->error()."\
return;
}
my $temperature = $result->{'upsAdvBatteryTe
my $worstcolor = 'green';
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
$message .= '&'.$worstcolor." UPS Temperature: $temperature ° C\n";
} elsif ($enterprise eq 'cisco') {
my $srdescr = quotemeta($snmpoids{'cisco
my $srvalue = quotemeta($snmpoids{'cisco
my $srthresh = quotemeta($snmpoids{'cisco
my $srstate = quotemeta($snmpoids{'cisco
# Walk the tree from ciscoEnvMonTemperatureStat
# get everything at once.
my %descrdb = ();
my %valuedb = ();
my %threshdb = ();
my %statedb = ();
if (my $result = $snmpsession->get_table(-b
while (my($key,$value) = each(%$result)) {
if ($key =~ /^$srdescr\.(\d+)$/) {
my $index = $1;
$descrdb{$index} = $value;
} elsif ($key =~ /^$srvalue\.(\d+)$/) {
my $index = $1;
$valuedb{$index} = $value;
} elsif ($key =~ /^$srthresh\.(\d+)$/) {
my $index = $1;
$threshdb{$index} = $value;
} elsif ($key =~ /^$srstate\.(\d+)$/) {
my $index = $1;
$statedb{$index} = $snmpsyntaxdb{'ciscoEnvMon
}
} # while (my($key,$value) = each(%$result))
} else {
print(localtime().": ".(caller(0))[3].": Unable to get temperature information for Cisco $host: ".$snmpsession->error()."\
return;
}
# Determine colors
my %colordb = ();
while (my($index,$state) = each(%statedb)) {
if ($threshdb{$index} == 0) {
$colordb{$index} = 'clear';
} elsif ($state eq 'normal') {
$colordb{$index} = 'green';
} elsif ($state eq 'warning') {
$colordb{$index} = 'yellow';
} else {
$colordb{$index} = 'red';
}
} # while (my($index,$state) = each(%statedb))
# find worst color
my $worstcolor = &color_compare(values(%col
# compose message
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
my @indices = sort { $a <=> $b } keys(%statedb);
foreach my $index (@indices) {
$message .= '&'.$colordb{$index}." $descrdb{$index}: $valuedb{$index} ° C, Threshold: $threshdb{$index} ° C, State: ".$statedb{$index}."\n";
} # foreach my $index (@indices)
} elsif ($enterprise eq 'compaq') {
# Use the following OIDs to grab temperature data and status
# in a way that can be graphed by Butter and Larrd if possible
# cpqHeThermalCondition
# cpqHeThermalTempStatus
# cpqHeTemperatureIndex
# cpqHeTemperatureLocale
# cpqHeTemperatureCelsius
# cpqHeTemperatureThreshold
# cpqHeTemperatureCondition
my $thermcond = '';
my $thermtempstat = '';
if (my $result = $snmpsession->get_request(
$snmpoids{'cpqHeThermalCon
$snmpoids{'cpqHeThermalTem
$thermcond = $result->{$snmpoids{'cpqHe
$thermcond = $snmpsyntaxdb{'cpqHeTherma
$thermtempstat = $result->{$snmpoids{'cpqHe
$thermtempstat = $snmpsyntaxdb{'cpqHeTherma
} else {
print(localtime().": ".(caller(0))[3].": Unable to get Thermal info for Compaq $host: ".$snmpsession->error()."\
return;
}
my $thermcondcolor = ($thermcond eq 'ok') ? 'green' : 'red';
my $thermtempstatcolor = ($thermtempstat eq 'failed') ? 'red' :
($thermtempstat eq 'degraded') ? 'yellow' : 'green';
my %locdb = ();
my %celsdb = ();
my %threshdb = ();
my %conddb = ();
my %tempcolordb = ();
my %threshcoldb = ();
if (my $result = $snmpsession->get_table(-b
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/.*\.//g;
$locdb{$index} = $snmpsyntaxdb{'cpqHeTemper
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get Temperature Locale for Compaq $host: ".$snmpsession->error()."\
return;
}
if (scalar(keys(%locdb)) > 0) { # Don't bother with the others if I didn't get anything for locale
if (my $result = $snmpsession->get_table(-b
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/.*\.//g;
$celsdb{$index} = $value;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get Temperature in Celsius for Compaq $host: ".$snmpsession->error()."\
return;
}
if (my $result = $snmpsession->get_table(-b
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/.*\.//g;
$threshdb{$index} = $value;
my $pct = ( $celsdb{$index} / $threshdb{$index} ) * 100;
if ($pct > $compaq_pct_temp_panic) {
$threshcoldb{$index} = 'red';
} elsif ($pct > $compaq_pct_temp_warn) {
$threshcoldb{$index} = 'yellow';
} else {
$threshcoldb{$index} = 'green';
}
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get cpqHeTemperatureThreshold for Compaq $host: ".$snmpsession->error()."\
return;
}
if (my $result = $snmpsession->get_table(-b
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/.*\.//g;
$conddb{$index} = $snmpsyntaxdb{'cpqHeTemper
if ($conddb{$index} eq 'ok') {
$tempcolordb{$index} = 'green';
} elsif ($conddb{$index} eq 'degraded') {
$tempcolordb{$index} = 'yellow';
} else {
$tempcolordb{$index} = 'red';
}
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get cpqHeTemperatureCondition for Compaq $host: ".$snmpsession->error()."\
return;
}
} # if (scalar(keys(%locdb)) > 0)
my $worstcolor = &color_compare($thermcondc
# compose message
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
# General Status: cpqHeThermalCondition and cpqHeThermalTempStatus
$message .= '&'."$thermcondcolor Status of the system's thermal environment: $thermcond\n";
$message .= '&'."$thermcondcolor Status of the system's temperature sensors: $thermtempstat\n";
# Specific statuses, formatted so they can be graphed
# Use the colors determined by threshold but also show the Condition colors
my @indices = sort { $a <=> $b } keys(%locdb);
foreach my $index (@indices) {
$message .= '&'.$threshcoldb{$index}."
}
} elsif ($enterprise eq 'foundry') {
# Warning: some versions report in 0.5 degrees units, some in 1.0 degrees
# Borderline seems to be 7.2: Those and above use 1.0
# snChasActualTemperature/.1
# snChasWarningTemperature/.
# snChasShutdownTemperature/
my $actual = 0;
my $warning = 0;
my $shutdown = 0;
if (my $result = $snmpsession->get_request(
$snmpoids{'snChasWarningTe
$snmpoids{'snChasShutdownT
$actual = $result->{$snmpoids{'snCha
$warning = $result->{$snmpoids{'snCha
$shutdown = $result->{$snmpoids{'snCha
} else {
print(localtime().": ".(caller(0))[3].": Unable to get temperature info for Foundry $host: ".$snmpsession->error()."\
return;
}
# Determine color
my $worstcolor = 'green';
if ($actual >= $shutdown) {
$worstcolor = 'red';
} elsif ($actual >= $warning) {
$worstcolor = 'yellow';
}
# Determine whether I'm dealing with units of 0.5 or 1.0 degrees.
if ($version < 7.2) {
# if ($warning > 62) # another way to do it
$actual = $actual / 2;
$warning = $warning / 2;
$shutdown = $shutdown / 2;
}
# compose message
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
$message .= '&'.$worstcolor." Actual Temperature: $actual ° C\n";
$message .= "&yellow Warning Temperature: $warning ° C\n";
$message .= "&red Shutdown Temperature: $shutdown ° C\n";
} elsif ($enterprise eq 'netapp') {
# Only a simple yes/no check
# envOverTemperature/.1.3.6.
# my $envOverTemperature = '.1.3.6.1.4.1.789.1.2.4.1.
# no(1)
# yes(2)
my $amihotornot = undef;
if (my $result = $snmpsession->get_request(
$amihotornot = $snmpsyntaxdb{'envOverTemp
} else {
print(localtime().": ".(caller(0))[3].": Unable to check temperature for netapp $host: ".$snmpsession->error()."\
return;
}
my $worstcolor = ($amihotornot eq 'yes') ? 'red' : 'green';
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n\n"
if ($amihotornot == 2) {
$message .= "The Network Appliance is currently operating\n";
$message .= "above its maximum operating temperature.\n";
} else {
$message .= "The Network Appliance is not currently operating\n";
$message .= "above its maximum operating temperature.\n";
}
} else {
print(localtime().": ".(caller(0))[3].": Unknown enterprise '$enterprise' for host '$host'\n");
return;
}
return $message;
} # sub temperature_message
##### UPTIME #####
#----
# &uptime_message($host,$snm
#
# Check uptime and compose into a message.
# Simplified version of uptime_message for machines whose CPU isn't monitored.
#----
sub uptime_message {
my($host,$snmpsession,$ent
print(localtime().": ".(caller(0))[3].": Checking host '$host'\n") if $debug;
if (! defined($uptime)) {
print(localtime().": ".(caller(0))[3].": Uptme for '$host' is undefined\n");
return;
}
if ($uptime == 0) {
print(localtime().": ".(caller(0))[3].": Uptme for '$host' is zero\n");
return;
}
# Check uptime, hundredths of seconds
my $uptimecolor = 'green';
if ((($uptime / 100) / 60) < $ENV{'WARNMINSONREBOOT'}) {
$uptimecolor = $ENV{'WARNCOLORONREBOOT'};
}
# Create message
my $message = '';
my $test = 'uptime';
(my $commahost = $host) =~ s/\./\,/g;
my $upword = '';
if (($uptime / 100) < 120) {
$upword = sprintf("%3.2f seconds",$uptime / 100);
} elsif ((($uptime / 100) / 60) < 120) {
$upword = sprintf("%3.2f minutes",(($uptime / 100) / 60));
} elsif (((($uptime / 100) / 60 ) / 60) < 48) {
$upword = sprintf("%3.2f hours",((($uptime / 100) / 60) / 60));
} else {
$upword = sprintf("%3.2f days",(((($uptime / 100) / 60) / 60) / 24));
}
$message = "status $commahost.$test $uptimecolor ".scalar(localtime)." up: $upword";
$message .= "\n\n";
if ((($uptime / 100) / 60) < $ENV{'WARNMINSONREBOOT'}) {
$message .= "Warning: Machine recently rebooted\n\n";
} else {
$message .= "Machine not recently rebooted\n\n";
}
return $message;
} # sub uptime_message
##### DISK #####
#----
# &disk_message($host,$snmps
#
# Check disk usage and create a text output table as close to the
# original bb-disk.sh as possible.
# TODO: Sneak in inode checks too where possible.
# It would be a shame to gather disk names twice.
#----
sub disk_message {
my($host,$snmpsession,$ent
(my $commahost = $host) =~ s/\./\,/g;
my $test = 'disk';
print(localtime().": ".(caller(0))[3].": Checking host '$host'\n") if $debug;
my $message = '';
my %disknamedb = ();
my %disktotaldb = ();
my %diskuseddb = ();
my %diskfreedb = ();
my %diskpctdb = ();
my %diskmntdb = ();
# Sneak in inode checks where possible
my $is_inodecapable = 0;
my %inodetotaldb = ();
my %inodeuseddb = ();
my %inodefreedb = ();
my %inodepctdb = ();
# Regardless of the system, I need:
# Filesystem 1k-blocks(Total) Used Available Use% Mounted on
# Mounted On can be same as FileSystem if Mounted On is not available
if ($enterprise eq 'netapp') {
$is_inodecapable = 1;
# Get disk names, skip over "snapshots"
# Skip trailing slashes to make it more like Unix
if (my $result = $snmpsession->get_table(-b
while (my($key,$value) = each(%$result)) {
next if $value =~ /\.snapshot$/;
(my $index = $key) =~ s/^.*\.//;
$value =~ s/\/$//;
$disknamedb{$index} = $value;
} # while (($key,$value) = each(%$result))
} else {
print(localtime().": ".(caller(0))[3].": Unable to get dfFileSys for Netapp $host: ".$snmpsession->error()."\
return;
}
# Get totals
my @varbindlist = map { $_ = $snmpoids{'dfKBytesTotal'}
if (my $result = $snmpsession->get_request(
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//;
$disktotaldb{$index} = $value;
} # while (($key,$value) = each(%$result))
} else {
print(localtime().": ".(caller(0))[3].": Unable to get dfKBytesTotal for Netapp $host: ".$snmpsession->error()."\
return;
}
# Get used
@varbindlist = map { $_ = $snmpoids{'dfKBytesUsed'}.
if (my $result = $snmpsession->get_request(
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//;
$diskuseddb{$index} = $value;
} # while (($key,$value) = each(%$result))
} else {
print(localtime().": ".(caller(0))[3].": Unable to get dfKBytesUsed for Netapp $host: ".$snmpsession->error()."\
return;
}
# Get free
@varbindlist = map { $_ = $snmpoids{'dfKBytesAvail'}
if (my $result = $snmpsession->get_request(
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//;
$diskfreedb{$index} = $value;
} # while (($key,$value) = each(%$result))
} else {
print(localtime().": ".(caller(0))[3].": Unable to get dfKBytesAvail for Netapp $host: ".$snmpsession->error()."\
return;
}
# Get MountedOn, same as the Name on the systems we have but you never know
@varbindlist = map { $_ = $snmpoids{'dfMountedOn'}.'
if (my $result = $snmpsession->get_request(
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//;
$value =~ s/\/$//;
$diskmntdb{$index} = $value;
} # while (($key,$value) = each(%$result))
} else {
print(localtime().": ".(caller(0))[3].": Unable to get dfMountedOn for Netapp $host: ".$snmpsession->error()."\
return;
}
# Get pct
@varbindlist = map { $_ = $snmpoids{'dfPerCentKBytes
if (my $result = $snmpsession->get_request(
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//;
$diskpctdb{$index} = $value;
} # while (($key,$value) = each(%$result))
} else {
print(localtime().": ".(caller(0))[3].": Unable to get dfPerCentKBytesCapacity for Netapp $host: ".$snmpsession->error()."\
return;
}
# Get Inodes used
@varbindlist = map { $_ = $snmpoids{'dfInodesUsed'}.
if (my $result = $snmpsession->get_request(
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//;
$inodeuseddb{$index} = $value;
} # while (($key,$value) = each(%$result))
} else {
print(localtime().": ".(caller(0))[3].": Unable to get dfInodesUsed for Netapp $host: ".$snmpsession->error()."\
return;
}
# Get Inodes free
@varbindlist = map { $_ = $snmpoids{'dfInodesFree'}.
if (my $result = $snmpsession->get_request(
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//;
$inodefreedb{$index} = $value;
} # while (($key,$value) = each(%$result))
} else {
print(localtime().": ".(caller(0))[3].": Unable to get dfInodesFree for Netapp $host: ".$snmpsession->error()."\
return;
}
# Calculate Inode totals
while (my($index,$used) = each(%inodeuseddb)) {
my $free = $inodefreedb{$index};
my $total = $used + $free;
$inodetotaldb{$index} = $total;
} # while
# Get Inodes percentage
@varbindlist = map { $_ = $snmpoids{'dfPerCentInodeC
if (my $result = $snmpsession->get_request(
while (my($key,$value) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//;
$inodepctdb{$index} = $value;
} # while (($key,$value) = each(%$result))
} else {
print(localtime().": ".(caller(0))[3].": Unable to get dfPerCentInodeCapacity for Netapp $host: ".$snmpsession->error()."\
return;
}
} else {
print(localtime().": ".(caller(0))[3].": Unknown enterprise '$enterprise' for host '$host'\n");
return;
}
my $worstcolor = 'green';
# This is where I insert any messages about specific partitions going over their limits
my @indices = sort { $a <=> $b } keys(%disknamedb);
foreach my $index (@indices) {
my $yellowlimit = $ENV{'DFWARN'};
my $redlimit = $ENV{'DFPANIC'};
if ((exists($diskthreshdb_ref
(defined($diskthreshdb_ref
(exists($diskthreshdb_ref-
(defined($diskthreshdb_ref
$redlimit = $diskthreshdb_ref->{$host}
$yellowlimit = $diskthreshdb_ref->{$host}
}
if ($diskpctdb{$index} >= $redlimit) {
$message .= "&red $diskmntdb{$index} ($diskpctdb{$index}%) has reached the defined PANIC level ($redlimit%)\n\n";
$worstcolor = 'red';
} elsif ($diskpctdb{$index} >= $yellowlimit) {
$message .= "&yellow $diskmntdb{$index} ($diskpctdb{$index}) has reached the defined WARNING level ($yellowlimit%)\n\n";
$worstcolor = 'yellow' unless $worstcolor eq 'red';
}
}
my @colheaders = ('Filesystem','1k-blocks',
# How to get the length of the longest value in a hash?
# length((sort { $b <=> $a } values())[0]);
# my %disknamedb = ();
# my %disktotaldb = ();
# my %diskuseddb = ();
# my %diskfreedb = ();
# my %diskpctdb = ();
# my %diskmntdb = ();
my @colwidths = (
length((sort { length($b) <=> length($a) } (values(%disknamedb),$colh
length((sort { length($b) <=> length($a) } (values(%disktotaldb),$col
length((sort { length($b) <=> length($a) } (values(%diskuseddb),$colh
length((sort { length($b) <=> length($a) } (values(%diskfreedb),$colh
length((sort { length($b) <=> length($a) } (values(%diskpctdb),$colhe
);
my $pad = '';
for (my $n = 0; $n <= 4; $n++) {
$pad = ' ' x (($colwidths[$n] - length($colheaders[$n])) + 1);
if ($n == 0) {
$message .= $colheaders[$n].$pad;
} else {
$message .= $pad.$colheaders[$n];
}
}
$message .= ' '.$colheaders[5]."\n";
foreach my $index (keys(%disknamedb)) {
$pad = ' ' x (($colwidths[0] - length($disknamedb{$index}
$message .= $disknamedb{$index}.$pad;
$pad = ' ' x (($colwidths[1] - length($disktotaldb{$index
$message .= $pad.$disktotaldb{$index};
$pad = ' ' x (($colwidths[2] - length($diskuseddb{$index}
$message .= $pad.$diskuseddb{$index};
$pad = ' ' x (($colwidths[3] - length($diskfreedb{$index}
$message .= $pad.$diskfreedb{$index};
$pad = ' ' x ($colwidths[4] - length($diskpctdb{$index})
$message .= $pad.$diskpctdb{$index}.'%
$message .= ' '.$diskmntdb{$index};
$message .= "\n";
}
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n$me
if ($is_inodecapable) {
# Sneak in an inode message.
# And why aren't I just adding the message here instead of passing it
# back up anyways?
my $message = ''; # Different namespace
my $test = 'inode';
my $worstcolor = 'green';
# This is where I insert any messages about specific partitions going over their limits
my @indices = sort { $a <=> $b } keys(%disknamedb);
foreach my $index (@indices) {
my $yellowlimit = $ENV{'DFWARN'};
my $redlimit = $ENV{'DFPANIC'};
if ((exists($diskthreshdb_ref
(defined($diskthreshdb_ref
(exists($diskthreshdb_ref-
(defined($diskthreshdb_ref
$redlimit = $diskthreshdb_ref->{$host}
$yellowlimit = $diskthreshdb_ref->{$host}
}
if ($inodepctdb{$index} >= $redlimit) {
$message .= "&red $diskmntdb{$index} ($inodepctdb{$index}%) has reached the defined PANIC level ($redlimit%)\n\n";
$worstcolor = 'red';
} elsif ($inodepctdb{$index} >= $yellowlimit) {
$message .= "&yellow $diskmntdb{$index} ($inodepctdb{$index}) has reached the defined WARNING level ($yellowlimit%)\n\n";
$worstcolor = 'yellow' unless $worstcolor eq 'red';
}
} # foreach my $index (@indices)
my @colheaders = ('Filesystem','Inodes','IU
my @colwidths = (
length((sort { length($b) <=> length($a) } (values(%disknamedb),$colh
length((sort { length($b) <=> length($a) } (values(%inodetotaldb),$co
length((sort { length($b) <=> length($a) } (values(%inodeuseddb),$col
length((sort { length($b) <=> length($a) } (values(%inodefreedb),$col
length((sort { length($b) <=> length($a) } (values(%inodepctdb),$colh
);
my $pad = '';
for (my $n = 0; $n <= 4; $n++) {
$pad = ' ' x (($colwidths[$n] - length($colheaders[$n])) + 1);
if ($n == 0) {
$message .= $colheaders[$n].$pad;
} else {
$message .= $pad.$colheaders[$n];
}
}
$message .= ' '.$colheaders[5]."\n";
foreach my $index (keys(%disknamedb)) {
$pad = ' ' x (($colwidths[0] - length($disknamedb{$index}
$message .= $disknamedb{$index}.$pad;
$pad = ' ' x (($colwidths[1] - length($inodetotaldb{$inde
$message .= $pad.$inodetotaldb{$index}
$pad = ' ' x (($colwidths[2] - length($inodeuseddb{$index
$message .= $pad.$inodeuseddb{$index};
$pad = ' ' x (($colwidths[3] - length($inodefreedb{$index
$message .= $pad.$inodefreedb{$index};
$pad = ' ' x ($colwidths[4] - length($inodepctdb{$index}
$message .= $pad.$inodepctdb{$index}.'
$message .= ' '.$diskmntdb{$index};
$message .= "\n";
}
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n$me
$message .= "\n<!-- Enterprise: $enterprise , Version: $version -->\n";
# Add version credit
$message .= (caller(0))[3].", $Script Version: $VERSION\n";
# Add to combo message
if ($is_commandline) {
print("$ENV{'BBHOME'}/bin/
} else {
system("$ENV{'BBHOME'}/bin
}
} # if ($is_inodecapable)
return $message;
} # sub disk_message
##### MEMORY #####
#----
# &memory_message($host,$snm
#
# Check memory usage and create a text output table as close to the
# original bb-memory.sh as possible.
# Need to be more versatile with names of different types of memory
# and with graphing, make it more like disk checks in its logs and graphing.
#----
sub memory_message {
my($host,$snmpsession,$ent
(my $commahost = $host) =~ s/\./\,/g;
my $test = 'memory';
print(localtime().": ".(caller(0))[3].": Checking host '$host'\n") if $debug;
my $message = '';
# Some of these will be calculated as necessary
# Keys are ostensibly index numbers but you can get away with names.
# Numbers given in KB.
my %memorynamedb = ();
my %memorytotaldb = ();
my %memoryuseddb = ();
my %memoryfreedb = ();
my %memorypctdb = ();
my %memorycolordb = (); # All green for now
if ($enterprise eq 'cisco') {
# Walk the names
if (my $result = $snmpsession->get_table(-b
while (my($key,$name) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//; # Remove all but the last number
$memorynamedb{$index} = $name;
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get ciscoMemoryPoolName for $enterprise $host: ".$snmpsession->error()."\
return;
}
# Walk the used numbers
if (my $result = $snmpsession->get_table(-b
while (my($key,$used) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//; # Remove all but the last number
# $memoryuseddb{$index} = int($used/1024); # Cisco returns bytes
$memoryuseddb{$index} = $used; # Cisco returns bytes, but so does Foundry
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get ciscoMemoryPoolUsed for $enterprise $host: ".$snmpsession->error()."\
return;
}
# Walk the free numbers
if (my $result = $snmpsession->get_table(-b
while (my($key,$free) = each(%$result)) {
(my $index = $key) =~ s/^.*\.//; # Remove all but the last number
# $memoryfreedb{$index} = int($free/1024); # Cisco returns bytes
$memoryfreedb{$index} = $free; # Cisco returns bytes, but so does Foundry
}
} else {
print(localtime().": ".(caller(0))[3].": Unable to get ciscoMemoryPoolFree for $enterprise $host: ".$snmpsession->error()."\
return;
}
# Calculate totals and percentages
while (my($index,$used) = each(%memoryuseddb)) {
my $free = $memoryfreedb{$index};
my $total = $used + $free;
my $percent = sprintf("%.2f",100*($used/
$memorytotaldb{$index} = $total;
$memorypctdb{$index} = $percent;
$memorycolordb{$index} = 'green';
}
} elsif ($enterprise eq 'foundry') {
# All memory named as 'System'
# Get snAgGblDynMemUtil
# Get snAgGblDynMemTotal
# Get snAgGblDynMemFree
if (my $result = $snmpsession->get_request(
$snmpoids{'snAgGblDynMemTo
$snmpoids{'snAgGblDynMemFr
my $free = $result->{$snmpoids{'snAgG
my $total = $result->{$snmpoids{'snAgG
# my $percent = $result->{$snmpoids{'snAgG
my $percent = sprintf("%.2f",100*(($tota
my $used = $total - $free;
$memorynamedb{1} = 'System';
$memorytotaldb{1} = $total;
$memoryuseddb{1} = $used;
$memoryfreedb{1} = $free;
$memorypctdb{1} = $percent;
$memorycolordb{1} = 'green';
} else {
print(localtime().": ".(caller(0))[3].": Unable to get memory for $enterprise $host: ".$snmpsession->error()."\
return;
}
} else {
print(localtime().": ".(caller(0))[3].": Unknown enterprise '$enterprise' for host '$host'\n");
return;
} # if ($enterprise eq ...)
my @colheaders = ('Memory','Used','Total','
my $worstcolor = 'green';
# And will stay green until I figure out how to configure thresholds
my @colwidths = (
2 + length((sort { length($b) <=> length($a) } (values(%memorynamedb),$co
2 + length((sort { length($b) <=> length($a) } (values(%memoryuseddb),$co
2 + length((sort { length($b) <=> length($a) } (values(%memorytotaldb),$c
2 + length((sort { length($b) <=> length($a) } (values(%memorypctdb),$col
);
$message .= sprintf(" %$colwidths[0]s %$colwidths[1]s %$colwidths[2]s %$colwidths[3]s\n",@colhea
my @indlist = sort(keys(%memorynamedb));
foreach my $index (@indlist) {
$message .= sprintf("&%s %$colwidths[0]s %$colwidths[1]s %$colwidths[2]s %$colwidths[3]s\n",$memory
}
# Add a header
$message = "status $commahost.$test $worstcolor ".scalar(localtime)."\n$me
return $message;
} # memory_message
##### COMMON UTILITIES #####
#----
# &env_check()
#
# Check the environment
#----
sub env_check {
unless ((exists($ENV{'BBTMP'})) && (defined($ENV{'BBTMP'}))) {
$is_commandline = 1;
$ENV{'BBTMP'} = $defbbtmp;
}
unless (-d $ENV{'BBTMP'}) {
print(localtime().": ".(caller(0))[3].": BBTMP directory $ENV{'BBTMP'} doesn't exist\n");
return;
}
unless (-w $ENV{'BBTMP'}) {
print(localtime().": ".(caller(0))[3].": BBTMP directory $ENV{'BBTMP'} isn't writable\n");
return;
}
unless ((exists($ENV{'BBHOME'})) && (defined($ENV{'BBHOME'})))
$is_commandline = 1;
$ENV{'BBHOME'} = $defbbhome;
}
unless (-d $ENV{'BBHOME'}) {
print(localtime().": ".(caller(0))[3].": BBHOME directory $ENV{'BBHOME'} doesn't exist\n");
return;
}
unless ((exists($ENV{'BB'})) && (defined($ENV{'BB'}))) {
$is_commandline = 1;
$ENV{'BB'} = $defbb;
}
unless (-x $ENV{'BB'}) {
print(localtime().": ".(caller(0))[3].": BB command $ENV{'BB'} isn't executable\n");
return;
}
unless ((exists($ENV{'BBDISP'})) && (defined($ENV{'BBDISP'})))
$is_commandline = 1;
$ENV{'BBDISP'} = $defbbdisp;
$ENV{'MACHIP'} = $defbbdisp;
$ENV{'MACHINE'} = $defmachine;
$ENV{'MACHINEDOTS'} = $defmachine;
}
if ($is_commandline) {
$ENV{'BBDISPLAY'} = 'TRUE';
$ENV{'BBNET'} = 'TRUE';
}
return 1;
}
#----
# &color_compare(@colors);
#
# Look at a list of colors and compile them into one:
# If any are red, return red.
# If all are clear, return clear.
# If any are yellow, return yellow.
# Else, return green.
#----
sub color_compare {
my(@colors) = @_;
# If any are red, return red.
foreach my $color (@colors) {
if ($color eq 'red') { return 'red' }
}
# If all are clear, return clear.
my $all_clear = 1;
foreach my $color (@colors) {
if ($color ne 'clear') {
$all_clear = 0;
last;
}
}
if ($all_clear) {
return 'clear';
}
# If any are yellow, return yellow.
foreach my $color (@colors) {
if ($color eq 'yellow') {
return 'yellow';
}
}
# Else, return green.
return 'green';
} # sub color_compare_nice
#----
# &color_compare_strict(@col
#
# Look at a list of colors and compile them into one:
# If any are red, return red.
# If all are clear, return clear.
# If all are yellow, return red.
# If any are yellow, return yellow.
# Else, return green.
#----
sub color_compare_strict {
my(@colors) = @_;
# If any are red, return red.
foreach my $color (@colors) {
if ($color eq 'red') { return 'red' }
}
# If all are clear, return clear.
my $all_clear = 1;
foreach my $color (@colors) {
if ($color ne 'clear') {
$all_clear = 0;
last;
}
}
if ($all_clear) {
return 'clear';
}
# If all are yellow, return red.
my $all_yellow = 1;
foreach my $color (@colors) {
if ($color ne 'yellow') {
$all_yellow = 0;
last;
}
}
if ($all_yellow) {
return 'red';
}
# If any are yellow, return yellow.
foreach my $color (@colors) {
if ($color eq 'yellow') {
return 'yellow';
}
}
# Else, return green.
return 'green';
} # sub color_compare_strict
#----
# &read_xsnmptab()
#
# Read the appropriate parts of bb-xsnmptab.
# Return a reference to a hash of hosts to tests and communities.
#----
sub read_xsnmptab {
print("Reading $ENV{'BBHOME'}/etc/bb-xsnm
my $infh = new FileHandle;
if ($infh->open("< $ENV{'BBHOME'}/etc/bb-xsnm
my %commhash = ();
my %testhash = ();
while (my $line = $infh->getline()) {
chomp($line);
next if $line =~ /^\s*\#/;
next if $line !~ /\S/;
if ($line =~ /^\s*(\S+)\s*\:\s*(\S+)\s*
my($host,$community,$tests
my @testhostlist = split(/[\s\,\;]+/,$testhos
my %testhostdb = map { $_ => 1 } @testhostlist;
next unless exists($testhostdb{$ENV{'M
$commhash{$host} = $community;
my @testlist = split(/[\s\,\;]+/,$tests);
foreach my $test (@testlist) {
$testhash{$host}{$test} = 1;
}
print("Found host '$host'\n") if $debug;
} elsif ($line =~ /^\s*(\S+)\s*\:\s*(\S+)\s*
my($host,$community,$tests
next unless $ENV{'BBNET'}; # If I am a BBNET machine
$commhash{$host} = $community;
my @testlist = split(/[\s\,\;]+/,$tests);
foreach my $test (@testlist) {
$testhash{$host}{$test} = 1;
}
print("Found host '$host'\n") if $debug;
} # if ($line =~ /^\s*(\S+)\s*\:\s*(\S+)\s*
} # while (my $line = $infh->getline())
$infh->close;
return(\%commhash,\%testha
} else {
print("Unable to open $ENV{'BBHOME'}/etc/bb-xsnm
return;
} # if ($infh->open("< $ENV{'BBHOME'}/etc/bb-xsnm
} # sub read_xsnmptab
#----
# &detect_version($host,$snm
#
# Detect OS version.
# Return as a number with only one dot that can be used for comparisons
#----
sub detect_version {
my($host,$snmpsession,$ent
my $version = 0;
if ($enterprise eq 'netscreen') {
if (my $result = $snmpsession->get_request(
my $descr = $result->{$snmpoids{'nsSet
if ($descr =~ /^(\d)\.(\S+) /) {
my($major,$minor) = ($1,$2);
$minor =~ s/\D//g;
$version = "$major.$minor";
}
} else {
print("Unable to get VersionTag for ucdavis host '$host'\n");
return;
}
} elsif ($enterprise eq 'ucdavis') {
if (my $result = $snmpsession->get_request(
my $descr = $result->{$snmpoids{'ucdVe
if ($descr =~ /^(\d)\.(\S+)$/) {
my($major,$minor) = ($1,$2);
$minor =~ s/\D//g;
$version = "$major.$minor";
}
} else {
print("Unable to get VersionTag for ucdavis host '$host'\n");
return;
}
} else {
if (my $result = $snmpsession->get_request(
my $descr = $result->{$snmpoids{'sysDe
if ($enterprise eq 'cisco') {
if ($descr =~ /Version (\d+)\.([^\,]+)\,/) {
my($major,$minor) = ($1,$2);
$minor =~ s/\D//g;
$version = "$major.$minor";
} else {
print("Unable to find version for cisco '$host'\n");
return;
}
} elsif ($enterprise eq 'foundry') {
if ($descr =~ /are Version 0(\d+)\.(\S+) Compiled/) {
my($major,$minor) = ($1,$2);
$minor =~ s/\D//g;
$version = "$major.$minor";
} else {
print("Failed to find version for foundry '$host' in description '$descr'\n");
return;
}
} elsif ($enterprise eq 'netapp') {
if ($descr =~ /Release (\d+)\.(\S+)\:/) {
my($major,$minor) = ($1,$2);
$minor =~ s/\D//g;
$version = "$major.$minor";
}
} else {
# print(localtime().": ".(caller(0))[3].": Unknown enterprise '$enterprise'\n");
# return;
$version = $descr;
}
} else {
print("Unable to get sysDescr for host '$host'\n");
return;
}
} # if ($enterprise eq 'netscreen')
return $version;
} # sub detect_version