#!/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 <device_ip> <interface|all> <username> <password> <enable mode password> <status|dump> [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<Net::Appliance::Session> and C<Data::Dumper> 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 <kernel01@gmail.com>

=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 <device_ip> <interface|all> <username> <password> <enable mode password> <status|dump> [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;
}