#!/usr/bin/perl use strict; use warnings; =head1 NAME cisco_backup.pl is backup utility for Cisco IOS devices. =head1 DESCRIPTION The script connects to the Cisco box either by Telnet or SSH [default protocol is SSH] and calls the 'run sh' command. The output is then backed up to: $log_d/".$ios_device_ip. "-$stamp.log"; where $log_d is passed as an ENV var CISCO_LOGD, if not set, defaults to /tmp. my $stamp = strftime "%H_%M_%d_%m_%Y", localtime; =head1 SYNOPSIS ./cisco_backup.pl [SSH|Telnet] If status is passed, backup doesn't occur and the status of interface [second argument] is returned. For backup purposes, pass 'all'. =head1 COREQUISITES Pretty much any Perl 5 version [4 was never tested]. =head1 PREREQUISITES This script requires the C and C modules. =head1 COPYRIGHT This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SCRIPT CATEGORIES UNIX/System_administration =head1 AUTHOR Jess Portnoy =cut use Net::Appliance::Session; use POSIX qw(strftime); use Data::Dumper; $SIG{__DIE__} = sub { print "@_"; exit 3; }; if ($#ARGV < 5 ){ print "Usage:\n $0 [SSH|Telnet]\n"; exit (-1); } my ($ios_device_ip,$ios_if,$ios_username,$ios_password,$ios_enable_password,$cmd,$protocol)=@ARGV; if (!defined $protocol){ $protocol='SSH'; } my @if_arr; @if_arr=split /,/, $ios_if; my $session_obj = Net::Appliance::Session->new( Host => $ios_device_ip, Transport => $protocol, ); # give verbose output whilst we run this script #$session_obj->input_log(*STDOUT); # try to login to the ios device, ignoring host check $session_obj->connect( Name => $ios_username, Password => $ios_password, SHKC => 0 ); # drop in to enable mode $session_obj->begin_privileged($ios_enable_password); my @cmd_output; if ($cmd eq 'dump'){ @cmd_output=&dump_conf(); my $log_d; if (defined $ENV{'CISCO_LOGD'} && -d $ENV{'CISCO_LOGD'}){ $log_d=$ENV{'CISCO_LOGD'}; }else{ print "CISCO_LOGD ENV var is not set or no such dir. Defaulting to /tmp\n"; $log_d='/tmp'; } my $stamp = strftime "%H_%M_%d_%m_%Y", localtime; open LOG, ">$log_d/".$ios_device_ip. "-$stamp.log"; for my $line (@cmd_output){ print LOG "@$line\n"; } close LOG; }else{ @cmd_output=&statusme(@if_arr); my $to_print=Dumper @cmd_output; my $RC=&analyze_status($to_print); if ($RC<0){ print "UNKNOWN ERROR. Probably no route to Cisco box but check.\n"; $RC=3; } exit $RC; } $session_obj->close; sub statusme { my (@ios_ifs)=@_; my @out; my $cnt=0; foreach my $if (@ios_ifs){ push @out,$session_obj->cmd("show inter $if"); } return \@out; } sub dump_conf { my @out; $session_obj->cmd("term length 0"); push @out,$session_obj->cmd("sh run"); return \@out; } sub analyze_status { my ($to_print)=@_; my ($is_if_up,$RC)=(-1,-1); my @bad_matches; print "Analyzing IOS query results:"; while ($to_print=~ m/(.*is up.*)/g){ $is_if_up++; print "$1\n"; } if ($is_if_up == $#if_arr){ print "Found ".($is_if_up +1). " I/F up.\n"; $RC=0; # This looks redundant at first glance [why not just "else"?] but we want the last else in case we didn't match these conds. }elsif($is_if_up < $#if_arr){ push @bad_matches,$1 while $to_print =~ m/(.*is down.*)/g; if ($#bad_matches < $#if_arr){ print "WARNING: found ".($#bad_matches -1) . "I/Fs down:\n"; $RC=1; }else{ print "CRITICAL: all I/Fs are down :(\n"; $RC=2; } for my $bad (@bad_matches){ print "$bad\n"; } } return $RC; }