#!/opt/vdops/bin/perl # This script queries CPQHOST-MIB and CPQSINFO-MIB variables to produce a # report summarizing firmware (and driver) versions # V Who When What # --------------------------------------------------------------------------- # 1.2.0 skendric 2011-02-21 Upgrade to Netops 1.4.0 # 1.1.0 skendric 2010-03-30 Upgrade to perl 5.10.1 # 1.0.0 skendric 2009-04-07 First Version # # Author: Stuart Kendrick, sbk {put at sign here} skendric {put dot here} com # # Source: http://www.skendric.com/device # # This software is available under the GNU GENERAL PUBLIC LICENSE, see # http://www.fsf.org/licenses/gpl.html # # # This script takes the following approach: # -Parses the hosts table for a list of targets (or accepts a command- # line list) # -Queries a bunch of Compaq-specific variables # -Produces a report # # # Requirements: # -The target(s) must be pingable # # -PERL modules: the WI::Netops collection # # # Assumptions: # # # Tested on: # -perl-5.12.2 # -net-snmp-5.6 # # # Instructions: # -Customize the script for your site: find the 'user-configurable # variables' section and modify as appropriate # -Type "compaq-firmware" to see the command-line options # -Try it out # # # # Caveats: # # # Known Bugs: # # # To do: # # Begin script # Load modules use strict; use warnings; use feature 'say'; use feature 'switch'; use Carp qw(carp cluck croak confess); use Data::Dumper; use English qw( -no_match_vars ); use Getopt::Std; use List::MoreUtils qw(uniq); use Text::Trim; use WI::Netops::HostTools 1.0.4; use WI::Netops::NetopsTools 2.2.3; use WI::Netops::NetopsData 1.4.0; use WI::Netops::PingTools 1.1.7; use WI::Netops::SNMPTools 1.5.3; use WI::Netops::Utilities 1.4.4; # Declare global variables my %cpqSeSysRomVer; my %cpqSeRedundantSysRomVer; my %cpqSiSysSerialNum; my %cpqSiSysProductId; my %cpqSiProductName; my %cpqSiServerSystemId; my %cpqHoFwVerIndex; my %cpqHoFwVerDisplayName; my %cpqHoFwVerVersion; my %cpqHoFwVerDisplayIid; # Inverse of %cpqHoFwVerDisplayName my %device; # Hash of references to a hash of array refs, # organizing by model and OS # %device = ( # 'ProLiant DL320 G5' => ( # 'Linux' => [family, genus, species], # 'Windows' => [bird, fish, mammal] # ) # 'ProLiant DL380 G5' => ( # 'Linux' => [carbon, iron, nickel], # 'Windows' => [lion, tiger, bear] # ) # ); # Define global variables $program_name = 'compaq-firmware'; $usage = 'Usage: compaq-firmware -s yes|no [-d {integer}] [-r] [-a | -e {expr} | -f {filename} | target1 target2 target3 ...]'; $version = '1.2.0'; # Grab arguments getopts('ad:e:f:rs:', \%option); @target = @ARGV; # Set mode if ($option{r}) { $mode = 'report' } elsif (-t STDIN) { $mode = 'interactive' } else { $mode = 'batch' } ### Begin Main Program ############################################### { check_args(); # Check arguments read_config(); # Read Netops config file compile_mibs(); # Compile MIB files build_target(); # Populate @target target_check(); # Look for errors in @target basic_info(); # Gather information sanity_check(); # Check for major errors do_the_work(); # Do the work print_report(); # Print report } ##### End Main Program ############################################### ######################################################################## # Do the work ######################################################################## sub do_the_work { # Debug trace trace_location('begin') if $debug; # Notify operator print_it('Querying targets...'); unless ($dome) { sleep $short; return 1; } # Loop through targets for my $target (@target) { my (%arg, $val, $vb); # Debug info say "Processing $target" if $debug; # Acquire cpqSeSysRomVer say 'Getting cpqSeSysRomVer.0' if $debug > 3; %arg = (host => $target, oid => '.1.3.6.1.4.1.232.1.2.6.1.0'); $val = snmpGet(\%arg); $val //= $QUERY; $val = $DASH if $val eq $EMPTY_STR; $cpqSeSysRomVer{$target} = $val; # Acquire cpqSeRedundantSysRomVer say 'Getting cpqSeRedundantSysRomVer.1' if $debug > 3; %arg = (host => $target, oid => '.1.3.6.1.4.1.232.1.2.6.4.1'); $val = snmpGet(\%arg); $val //= $QUERY; $val = $DASH if $val eq $EMPTY_STR; $cpqSeRedundantSysRomVer{$target} = $val; # Acquire cpqSiSysSerialNum say 'Getting cpqSiSysSerialNum.0' if $debug > 3; %arg = (host => $target, oid => '.1.3.6.1.4.1.232.2.2.2.1.0'); $val = snmpGet(\%arg); $val //= $QUERY; $val = $DASH if $val eq $EMPTY_STR; $cpqSiSysSerialNum{$target} = $val; # Acquire cpqSiSysProductId say 'Getting cpqSiSysProductId.0' if $debug > 3; %arg = (host => $target, oid => '.1.3.6.1.4.1.232.2.2.2.6.0'); $val = snmpGet(\%arg); $val //= $QUERY; $val = $DASH if $val eq $EMPTY_STR; $cpqSiSysProductId{$target} = $val; # Acquire cpqSiProductName say 'Getting cpqSiProductName.0' if $debug > 3; %arg = (host => $target, oid => '.1.3.6.1.4.1.232.2.2.4.2.0'); $val = snmpGet(\%arg); $val //= $QUERY; $val = $DASH if $val eq $EMPTY_STR; $cpqSiProductName{$target} = $val; # Acquire cpqSiServerSystemId say 'Getting cpqSiServerSystemId.0' if $debug > 3; %arg = (host => $target, oid => '.1.3.6.1.4.1.232.2.2.4.17.0'); $val = snmpGet(\%arg); $val //= $QUERY; $val = $DASH if $val eq $EMPTY_STR; $cpqSiServerSystemId{$target} = $val; # Acquire cpqHoFwVerIndex say 'Walking cpqHoFwVerIndex' if $debug > 3; %arg = (host => $target, oid => '.1.3.6.1.4.1.232.11.2.14.1.1.1'); $vb = snmpWalk(\%arg); for my $varbind (@$vb) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; ($val = $val) =~ s/"//g; $cpqHoFwVerIndex{$target}->{$iid} = $val; say " index $iid = $val" if $debug > 2; } # Acquire cpqHoFwVerVersion say 'Walking cpqHoFwVerVersion' if $debug > 3; %arg = (host => $target, oid => '.1.3.6.1.4.1.232.11.2.14.1.1.5'); $vb = snmpWalk(\%arg); for my $varbind (@$vb) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; ($val = $val) =~ s/"//g; $cpqHoFwVerVersion{$target}->{$iid} = $val; say " index $iid = $val" if $debug > 2; } # Acquire cpqHoFwVerDisplayName say 'Walking cpqHoFwVerDisplayName' if $debug > 3; %arg = (host => $target, oid => '.1.3.6.1.4.1.232.11.2.14.1.1.4'); $vb = snmpWalk(\%arg); for my $varbind (@$vb) { my ($iid, $val); $iid = $varbind->{iid}; $val = $varbind->{val}; say " index $iid = $val" if $debug > 2; ($val = $val) =~ s/"//g; ($val = trim $val) =~ tr/ / /s; # Strip spaces $cpqHoFwVerDisplayName{$target}->{$iid} = $val; $cpqHoFwVerDisplayIid{$target}->{$val}= $iid; } # Entertain operator print $BANG if $mode eq 'interactive'; } # Make things look pretty say "\n" if $mode eq 'interactive'; # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Tell the operator what I discovered ######################################################################## sub print_report { my %device; # Hash of array refs, keyed by model name, # listing the targets which belong to that model my $handle; my @models; # List of models underneath @target my $now = get_now(); my $total = @target; # If we are running in test mode, skip this routine unless ($dome) { print_it("Running in test mode, cannot print a meaningful report\n"); return 1; } # Debug trace trace_location('begin') if $debug; # Direct output to file open $handle, '>', $report_file or die "Cannot open $report_file: $!\n"; print {$handle} < $report_subject
#
# Title:           $report_subject
#
# Institution:     $institution
#
# Date of Report:  $now
#
# Description:     This report lists Compaq firmware and driver versions
#
# Active:          $total
#
# Questions:       If you have questions or comments regarding this
#                  report, please mail them to $report_queries
#
#
EOF # Build a list of models @models = uniq (values %cpqSiSysProductId); say 'models = ', join ', ', sort @models if $debug; # Clump targets by model for my $target (@target) { push @{$device{$cpqSiSysProductId{$target}}}, $target; } # Walk through devices for my $model (sort @models) { my @cdn; say "Processing model $model" if $debug; # Extract list of devices matching this model my @devices = @{$device{$model}}; my $first_target = 1; # Develop list of cpqHoFwVerDisplayName column headings # for this model for my $target (@devices) { my $cdn_ref = $cpqHoFwVerDisplayName{$target}; for my $iid (sort keys %$cdn_ref) { my $string = $cdn_ref->{$iid}; push @cdn, $string; } } @cdn = uniq @cdn; # Print title print {$handle} "
\n"; print {$handle} "

Product ID $model

\n"; print {$handle} "\n"; # Walk through targets for this particular model for my $target (sort @devices) { say " Focussing on target $target" if $debug; # Shrink hashes my $cdi_ref = $cpqHoFwVerIndex{$target}; my $cdiid_ref = $cpqHoFwVerDisplayIid{$target}; my $cdn_ref = $cpqHoFwVerDisplayName{$target}; my $cv_ref = $cpqHoFwVerVersion{$target}; # If this is the first target, print title and column headings if ($first_target) { # Print first seven column headings print {$handle} " \n"; print {$handle} " \n"; print {$handle} " \n"; print {$handle} " \n"; print {$handle} " \n"; print {$handle} " \n"; print {$handle} " \n"; print {$handle} " \n"; # Print the cpqHoFwVerDisplayName column headings for my $cdn (sort @cdn) { print {$handle} " \n"; } # Close the column headings row print {$handle} " \n"; # Don't do this again for this model $first_target = 0; } # End 'If this is the first target ...' # Now print the data for this target print {$handle} " \n"; # Start new row print {$handle} " \n"; # Print target print {$handle} " \n"; print {$handle} " \n"; print {$handle} " \n"; print {$handle} " \n"; print {$handle} " \n"; print {$handle} " \n"; # Walk through the list of cpqHoFwVerDisplayName for this model for my $cdn (sort @cdn) { say " Handling $cdn" if $debug > 3; # If this device knows about this cpqHoFwVerDisplayName, print it if (defined $cdiid_ref->{$cdn}) { my $index = $cdiid_ref->{$cdn}; print {$handle} " \n"; } # Whereas, if the device does not know about this # cpqHoFwVerDisplayName, print a dash else { print {$handle} " \n"; # Empty cell } } # End 'Walk through the list of cpqHoFwVerDisplayName for this...' # Close this row print {$handle} " \n"; } # End 'Walk through targets for this particular model' # Terminate table print {$handle} "
HostModelSerial #SystemIdsysObjectIDPrimary ROMBackup ROM$cdn
$target$cpqSiProductName{$target}$cpqSiSysSerialNum{$target}$cpqSiServerSystemId{$target}$sysObjectID{$target}$cpqSeSysRomVer{$target}$cpqSeRedundantSysRomVer{$target}$cv_ref->{$index}$DASH
\n"; } # End 'Walk through models' # Terminate HTML print {$handle} "\n"; print {$handle} "\n"; # Clean-up unless ($handle =~ /STDOUT/) { close $handle or warn "Cannot close $report_file: $!\n"; } # Notify operator log_it("Ending $PROGRAM_NAME"); say "Ending $PROGRAM_NAME" if $mode eq 'interactive'; # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Sanity check ######################################################################## sub sanity_check { my @remove; # Debug trace trace_location('begin') if $debug; # Notify operator print_it('Sanity check...'); # Loop through targets, removing non-Dell devices SANITY: for my $target (@target) { # Identify manufacturer unless ($manufacturer{$target} eq 'Compaq') { say "\nManufacturer of $target is not Compaq, ignoring" if $debug; push @remove, $target; next SANITY; } # Entertain operator print $BANG if $mode eq 'interactive'; } # Remove entries which failed checks prune_basic(@remove); # Make things look pretty say "\n" if $mode eq 'interactive'; # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Output help ######################################################################## sub HELP_MESSAGE { print <