#!/opt/vdops/bin/perl # This script automates the process of copying copying config, data, or # event files from APC management cards to a centralized location # V Who When What # --------------------------------------------------------------------------- # 1.2.0 skendric 2011-02-21 Upgrade to Netops 1.4.0 # 1.1.1 skendric 2010-06-25 Allow $error{$target} to be undef # 1.1.0 skendric 2009-12-23 Remove Net::SNMP support # 1.0.6 skendric 2009-04-06 Verify permissions more thoroughly # 1.0.5 skendric 2008-07-25 Verify write permissions # 1.0.4 skendric 2008-04-27 Handle ftp'ing more robustly # 1.0.3 skendric 2008-03-06 Correct usage statement # 1.0.2 skendric 2007-03-21 Stylistic mods # 1.0.1 skendric 2006-10-23 Replace Object Values with OIDs # 1.0.0 skendric 2006-09-21 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: # -Download the file via ftp # # Requirements: # -The target(s) must be pingable # # -The following MIB modules stashed in /opt/vdops/share/snmp/mibs, # or wherever it is that you store MIB modules: # PowerNet-MIB # # -PERL modules: the WI::Netops collection # # # # Assumptions: # # # Tested on: # -APC 9x1x Network Management Card # -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 "apc-save-files" to see the command-line options # -Try it out # # # Caveats: # # # Known Bugs: # -If the FTP server on the mangement card is disabled, the code # bombs. I'm trying to use 'eval' to trap this error, but it # doesn't seem to work. # # # To do: # -Test username/password foo # # 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 Net::FTP; use WI::Netops::APCTools 1.2.2; 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 $dstdir; # Directory where we store the config files my $dstfile; # The name of the destination file my $filetype; # config, data, or event my $password; # Password for ftp'ing my $srcfile; # The name of the source file my $username; # Username for ftp'ing # Define global variables $program_name = 'apc-save-files'; $usage = 'Usage: apc-save-files -s {yes|no} [-d {integer}] [-u {username} -p {passwd}] [-t {config|data|event} [-g {dstdir} [-a | -e {expr} | -f {filename} | target1 target2 target3 ...]'; $version = '1.2.0'; # Define user-configurable variables # Directories $dstdir = '/tftpboot/whatever'; # File default $filetype = 'config'; # Grab arguments getopts('ad:e:f:g:p:s:t:u:', \%option); @target = @ARGV; $dstdir = $option{g} if defined $option{g}; $filetype = $option{t} if defined $option{t}; $username = $option{u} if defined $option{u}; $password foo die 'Must specify -g dstdir' unless defined $dstdir; die 'Must specify -t filetype' unless defined $filetype; die 'Must specify -u username' unless defined $username; die 'Must specify -p password' unless defined $password; die 'Filetype must be config, data, or event' unless $filetype eq 'config' or $filetype eq 'data' or $filetype eq 'event'; # 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(); # Check for major errors sanity_check(); # Check for major errors print_before(); # Tell operator what I will do do_the_work(); # Upload config file info_after(); # Gather information print_after(); # Tell the operator what I did } ##### End Main Program ############################################### ######################################################################## # Do the work: copy file from targets to destination directory ######################################################################## sub do_the_work { my $direction = 'get'; my $dstfile; my $srcfile; # Debug trace trace_location('begin') if $debug; # Build $srcfile given ($filetype) { when ('config') { $srcfile = $filetype . '.ini' } default { $srcfile = $filetype . '.txt' } } # Loop through @target, uploading images TARGET: for my $target (@target) { my (%arg, $result); # Build dstfile given ($filetype) { when ('config') { $dstfile = $target . '-config.ini' } when ('data') { $dstfile = $target . '-data.txt' } when ('event') { $dstfile = $target . '-event.txt' } } # Verify that we can write to this file unless (touch_file("$dstdir/$dstfile", 0660)) { print_it("Cannot write to $dstdir/$dstfile, skipping"); next TARGET; } # Build argument hash %arg = ( target => $target, username => $username, password foo local_file => $srcfile, remote_file => "$dstdir/$dstfile", direction => $direction ); # Announce start say '--------------------------------------------------------' if $mode eq 'interactive'; print_it("Beginning to process $target"); # If this is for real if ($dome) { # Download file $result = ftp_file(\%arg); if ($result) { print_it(" Downloaded $dstfile"); chmod 0660, "$dstdir/$dstfile" or warn " Cannot chmod $dstdir/$dstfile: $!"; } else { print_it(" Cannot download $dstfile"); } } else { sleep $short; } # Announce completion print_it("Done processing $target"); say "-------------------------------------------------------\n\n" if $mode eq 'interactive'; } # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Figure out which devices survived the experience ######################################################################## sub info_after { # Debug trace trace_location('begin') if $debug; # Notify operator print_it('Pinging targets...'); # Pause to allow agents to reboot sleep $long; # Loop through targets for my $target (@target) { # Poll device until it answers unless (ping_it($target)) { print_it("$target is no longer answering pings"); $error{$target} .= 'Cannot ping '; } } # Make things look pretty say "\n" if $mode eq 'interactive'; # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Tell operator what I did ######################################################################## sub print_after { my $shit_happens = 0; # Debug trace trace_location('begin') if $debug; # If running from cron, don't print report return 1 if $mode eq 'batch'; say "\n# Here is what I see"; # If we are running in test mode, then return unless ($dome) { say "Running in test mode, cannot print a meaningful report\n"; return 1; } # Iterate through @target for my $target (@target) { log_it("Downloaded $filetype for $target to $dstdir") if $dome; $shit_happens++ if defined $error{$target}; } say(''); print < 0) { print "\n\n\n\n"; print <