#!/opt/vdops/bin/perl # This script automates the process of resetting devices # V Who When What # --------------------------------------------------------------------------- # 2.1.0 skendric 02-21-2011 Upgrade to Netops 1.4.0 # 2.0.1 skendric 06-25-2010 Allow $error{$target} to be undef # 2.0.0 skendric 02-05-2010 Upgrade to perl 5.10.1 # 1.9.0 skendric 01-26-2008 Migrate to new get_time function # 1.8.9 skendric 12-31-2008 Suport new snmpSet format # 1.8.8 skendric 12-16-2008 Support updated snmpGet # 1.8.7 skendric 11-30-2008 Display time when device is reset # 1.8.6 skendric 05-12-2008 Simplify handling of IOS devices # 1.8.5 skendric 07-23-2007 Report fiddles # 1.8.4 skendric 03-21-2007 Stylistic mods # 1.8.3 skendric 03-06-2007 Hand $wait to poll_by_ping # 1.8.2 skendric 10-23-2006 Replace Object Values with OIDs # 1.8.1 skendric 10-10-2005 Move poll_list to Netops.pm # 1.8.0 skendric 05-09-2005 Support Netops.pm-1.2 # 1.7.3 skendric 11-11-2004 Refine interactive output # 1.7.2 skendric 09-02-2004 Refine interactive output # 1.7.1 skendric 05-16-2044 Add logging in case of "-a" option # 1.7.0 skendric 05-09-2004 Migrate common functions to Netops.pm # 1.6.0 skendric 04-30-2004 Enhance command-line options # 1.5.3 skendric 11-16-2003 Use Net::Ping::External # 1.5.2 skendric 08-10-2003 Minor bug fixes # 1.5.1 skendric 04-13-2003 Added support for TAOS (Ascend) # 1.5.0 skendric 03-28-2003 Numerous minor updates # 1.4.0 skendric 03-24-2003 Added support for HP and Allied Telesyn # 1.3.3 skendric 01-30-2003 Replaced probeSoftwareRev with # moduleSwVersion.1 # 1.3.2 skendric 01-26-2003 Tightened scoping, changed DEBUG to $debug # 1.3.1 skendric 12-18-2002 Added support for Cisco Aironet # 1.3.0 skendric 11-14-2002 Added @version, improved error handling # 1.2.1 skendric 06-28-2002 Fixed errors in which_hardware # 1.2.0 skendric 05-31-2002 Auto-detect running from cron # 1.1.3 skendric 05-10-2002 Logs username of operator # 1.1.2 skendric 05-05-2002 More clean-up # 1.1.1 skendric 05-01-2002 Clean-up # 1.1.0 skendric 04-21-2002 Ping targets until they answer # 1.0.0 skendric 01-05-2002 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 high-level approach: # -Produce a report showing the operator what will be rebooted # and the currently running OS of each device # -Pause for 30 seconds to allow the operator to cancel # -Reboot the devices # -Wait a while # -Produce a report showing the operator which devices are alive # and the currently running OS of each device # # # Requirements: # -The target(s) must be pingable # # -IOS devices must have the line "snmp system-shutdown" in their # running config files # # -The following MIB modules stashed in /opt/vdops/share/snmp/mibs, # or wherever it is that you store MIB modules: # CISCO-PRODUCTS-MIB.my # # -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 # -Play with the script in "firing blanks" mode, to get a feel for # what it does. Type "reset-device -s no [target1] {target2} ..." # -When you are ready to do damage, run it # # Caveats: # # # Known Bugs: # -None # # # To do: # -Add support for SNMPv3 # # 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 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 # All hashes are keyed by target my %new_device; # Device from which target booted after the reset my %new_image; # Image from which target booted after the reset my %old_device; # Device from which target booted before the reset my %old_image; # Image from which target booted before the reset my %reboot_oids; # SNMP OIDs for rebooting devices my $wait; # Seconds to wait for devices to reboot # Define global variables $program_name = 'reset-device'; $usage = 'Usage: reset-device -s {yes|no} [-d {integer}] [-a | -e {expr} | -f {filename} | target1 target2 target3 ...]'; $version = '2.1.0'; # Define user-configurable variables # Wait Time $wait = 600; # These are the OIDs for the devices which I know how to reboot. # Notice that I leave off the trailing '.0' %reboot_oids = ( AT => '.1.3.6.1.4.1.207.8.4.4.3.2.0', # Allied Telesyn restart HP => '.1.3.6.1.4.1.11.2.14.11.1.4.1.0', # Hewlett-Packard hpicfReset CatOS => '.1.3.6.1.4.1.9.5.1.1.9.0', # Cisco CatOS sysReset IOS => '.1.3.6.1.4.1.9.2.9.9.0', # Cisco IOS tsMsgSend TAOS => '.1.3.6.1.4.1.529.9.8.0.0' # Ascend sysReset ); # Grab arguments getopts('ad:e:f:s:', \%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 info_before(); # Gather more information print_before(); # Tell the operator what I will do do_the_work(); # Go for it info_after(); # Gather new_image information print_after(); # Tell the operator what I did } ##### End Main Program ############################################### ######################################################################## # Reboot devices ######################################################################## sub do_the_work { # Debug trace trace_location('begin') if $debug; # Loop through targets, resetting them as we go TARGET: for my $target (@target) { my ($branch, $leaf, $oid, $result, $time, @varbind); $oid = $reboot_oids{$os_flavor{$target}}; ($branch, $leaf) = ($oid =~ /^(.*)\.(\d+)\Z/); @varbind = ($branch, $leaf, 2, 'INTEGER'); $time = get_time(); # Do it if ($dome) { print "Rebooting $target at $time ... " if $mode eq 'interactive'; say('') if $debug; log_it("Rebooting $target at $time"); $result = snmpSet( { host => $target, varbind => \@varbind } ); } else { print "Rebooting $target at $time ... " if $mode eq 'interactive'; sleep $short; $result = 0; say 'just kidding' if $mode eq 'interactive'; } # Grab time $time = get_time(); # Figure out what happened if ($result) { say " Reset at $time" if $mode eq 'interactive'; log_it("$target reset"); } else { say " Failed to reset at $time" if $mode eq 'interactive'; log_it("$target failed to reset"); } } # Talk about it afterward print_it("\nFinished resetting devices; waiting for them to return to life"); # Wait for devices to return to life sleep $mid; poll_by_ping(\@target, $wait); my $time = get_time(); print_it("Continuing at $time..."); # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Gather information after reboots ######################################################################## sub info_after { my %phoenix; # '1' means the device recovered from the reset, # '0' means that it did not # Debug trace trace_location('begin') if $debug; # Loop through targets, gathering information for my $target (@target) { # See who is alive $phoenix{$target} = ping_it($target); # Gather image info if ( not defined $phoenix{$target} ) { $phoenix{$target} = 0; $new_image{$target} = 'Not answering pings'; } elsif (defined $error{$target}) { $new_image{$target} = 'Did not reboot'; } else { ($new_device{$target}, $new_image{$target}) = which_image($target); } } # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Gather more information ######################################################################## sub info_before { # Debug trace trace_location('begin') if $debug; # Notify operator print_it('Gathering more information...'); # Loop through targets, gathering information for my $target (@target) { # Identify boot image ($old_device{$target}, $old_image{$target}) = which_image($target); $old_image{$target} = 'unknown' unless defined $old_image{$target}; # 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 did ######################################################################## sub print_after { my $shit_happens = 0; # Did errors occur? # Debug trace trace_location('begin') if $debug; # Record errors for my $target (@target) { $shit_happens++ if defined $error{$target}; } # If running from cron, don't print report return 1 if $mode eq 'batch'; # Print report if ($dome) { say "\n# Here are the boxes I rebooted"; } else { say "\n# Here are the boxes I would have rebooted, had you been serious"; } print < 0) { print "\n\n\n\n"; print < 10) { double_check(); } # If running from cron, don't print report return 1 if $mode eq 'batch'; print <