#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long qw(:config no_ignore_case bundling);
use Net::Telnet::Cisco;
use FileHandle;
use Term::ReadKey;
use Config::Tiny;
$|=1;
#!
#!
my $version="0.07";
my $version_date="07/22/03";
#!
#!
#Get command line options
my $ln_group="";
my $ln_router="";
my $user_name="";
my $password="";
my $input_file="";
my $output_file="";
my $flag_help=0;
my $flag_version=0;
my $command="";
GetOptions(
'r=s'=>\$ln_router, 'router=s'=>\$ln_router,
'g=s'=>\$ln_group, 'group=s'=>\$ln_group,
'u=s'=>\$user_name, 'username=s'=>\$user_name,
'p=s'=>\$password, 'password=s'=>\$password,
'i=s'=>\$input_file, 'input=s'=>\$input_file,
'o=s'=>\$output_file, 'output=s'=>\$output_file,
'c=s'=>\$command, 'command=s'=>\$command,
'h'=>\$flag_help, 'help'=>\$flag_help,
'v'=>\$flag_version, 'version'=>\$flag_version,
);
#Validate command line options
#my @commands=();
#if ($command ne "")
#{
# $commands[0]="first array";
# push (@commands,$command);
# my $line="";
# foreach $line (@commands)
# {
# print $line . "\n";
# }
#}
#exit 0;
if ($flag_help)
{
#List Options
print STDOUT "Batch Router - the batch router configurator\n";
print STDOUT "\n";
print STDOUT "List of options and their functions:\n";
print STDOUT "-r --router \t Specify a single router name from the config file, overides -g/--group.\n";
print STDOUT "-g --group \t Specify a single group of routers from the config file.\n";
print STDOUT "-u --username \t Specifies username to use for TACACS logins. If not supplied then script will prompt for name. Cannot be blank\n";
print STDOUT "-p --password \t Specifies password to use for TACACS logins. If not supplied then script will prompt for password. Cannot be blank\n";
print STDOUT "-c --command \t Specifies single command to run. Command must be surround with double qoutes, if there are spaces.\n";
print STDOUT "-i --input \t Specifies name and path to file which has the commands that will be ran on each router. If not supplied then script will prompt for path/name. Cannot be blank\n";
print STDOUT "-o --output \t Specifies name and path where to send output from routers. If not supplied output will be sent to STDOUT\n";
print STDOUT "-h --help \t This help screen. Displays a list of options.\n";
print STDOUT "-v --version \t Display version information for this script.\n";
exit 0;
}
if ($flag_version)
{
#Show Version
print STDOUT "Batch Router - the batch router configurator\n";
print STDOUT "Version number $version\n";
print STDOUT "Latest revision on $version_date\n";
exit 0;
}
#Load Config file
my %routers=();
my $conf = Config::Tiny->read('batch_router.cnf');
my $conf_routers = $conf->{routers}; # Hash ref with routers information
my $conf_groups = $conf->{groups}; # Hash ref with group information
my $validation=0;
if ($ln_router ne "")
{
#Check for Single Host
#Validate router with config file
$validation = &Check_routers($conf_routers, $ln_router);
if (!$validation)
{
print STDOUT "Router \'$ln_router\' is not in routers list.\n";
exit 1;
}
$routers{$ln_router}=$conf_routers->{$ln_router};
}
elsif ($ln_group ne "")
{
#Check for group of hosts
#Validate group with config file
$validation = &Check_groups($conf_groups, $ln_group);
if (!$validation)
{
print STDOUT "Group \'$ln_group\' is not in group list.\n";
exit 1;
}
#Pull each router name from $conf_group and put into a list
my @router_list=&Group_to_routers($conf_groups->{$ln_group});
#Validate each router name in group
my $line = "";
foreach $line (@router_list)
{
#Reset Validation to false
$validation=0;
$validation = &Check_routers($conf_routers, $line);
if (!$validation)
{
print STDOUT "Router \'$line\' in group \'$ln_group\' is not in routers list.\n";
exit 1;
}
$routers{$line}=$conf_routers->{$line};
}
}
else
{
#Make sure single or group of hosts selected
print STDOUT "You must select a router or group to run this script.\n";
exit 0;
}
#Prompt for user name if not provided
if ($user_name eq "")
{
print STDOUT "Please enter your user name: ";
ReadMode('normal');
$user_name = ReadLine(0);
chomp $user_name;
ReadMode('restore');
if ($user_name eq "")
{
print STDOUT "User name cannot be blank.\n";
exit 1;
}
}
#prompt for password if not provided
if ($password eq "")
{
print STDOUT "Please enter your password: ";
ReadMode('noecho');
$password = ReadLine(0);
chomp $password;
ReadMode('restore');
if ($password eq "")
{
print STDOUT "Password cannot be blank.\n";
exit 1;
}
print "\n";
}
if ($input_file eq "" && $command eq "")
{
print STDOUT "Please enter \'input' filename, with path if needed: ";
ReadMode('normal');
$input_file = ReadLine(0);
chomp $input_file;
ReadMode('restore');
if ($input_file eq "")
{
print STDOUT "Input filename can not be blank name cannot be blank.\n";
exit 1;
}
}
#Get list of commands from Input file or from the command line
my @commands=();
if ($command ne "")
{
push (@commands,$command);
}
elsif ($input_file ne "")
{
print STDOUT "*Reading in commands from Input File...";
@commands= &Open_input_file($input_file);
#Check for returned error
if (scalar(@commands) <= 0)
{
print STDOUT "\nInput file '$input_file' does not exist, is unreadable, or is empty.\n";
exit 1;
}
print STDOUT "Done\n";
}
#Set $out_fh(refernce to output file handle) to STDOUT or output file
print STDOUT "*Setting up output file, if any...";
my $out_FH = &Set_output_FH($output_file);
if (!$out_FH)
{
print STDOUT "\nOutput file '$output_file' can not be created or opened.\n";
exit 1;
}
print STDOUT "Done\n";
print STDOUT "*Logging into Routers.\n";
if ($output_file eq "") {print "\n";}
my $host="";
my %Result=();
foreach $host (keys %routers)
{
print STDOUT "*Logging into router $host($routers{$host}).\n";
if ($output_file ne "")
{
print $out_FH "Router $host($routers{$host}).\n";
}
%Result= &Router($user_name,$password, $routers{$host}, @commands);
my $line = "";
foreach $line (@commands)
{
print $out_FH "-" . $line . "\n";
my $output_list="";
foreach $output_list ($Result{$line})
{
my $output_line="";
foreach $output_line (@$output_list)
{
chomp ($output_line);
print $out_FH "\t" . $output_line . "\n";
}
}
}
print $out_FH "\n";
print $out_FH "----------------------------------------------------\n";
if ($output_file eq "") {print STDOUT "\n";}
}
if ($output_file eq "") {print STDOUT "\n";}
print STDOUT "*Closing output file, if any...";
if (!$output_file eq "")
{
close ($out_FH);
}
print STDOUT "Done\n";
## Start of subfunctions
sub Check_routers
{
#Check router Hash reference for router string
my ($conf_routers, $ln_router)=@_;
if (!defined($conf_routers->{$ln_router}))
{
return 0;
}
return 1;
}
sub Check_groups
{
#Check group Hash refernce for group string
my ($conf_groups, $ln_group)=@_;
if (!defined($conf_groups->{$ln_group}))
{
return 0;
}
return 1;
}
sub Group_to_routers
{
#Convert group router string into list of router names
my ($group)=@_;
chomp $group;
$group =~ s/[ \[\]]//g;
my @router_list = split/,/,$group;
return @router_list;
}
sub Open_input_file
{
#Open config file
($input_file)=@_;
my @list = ();
#Check if file exists and size > 0, else return error
if (-s $input_file)
{
#Open Input file, else return Error
unless (open IP_FH, "<$input_file")
{
close IP_FH;
return ();
}
@list = ;
chomp(@list);
}
else
{
close IP_FH;
return ();
}
close IP_FH;
return @list;
}
sub Set_output_FH
{
#Set output file handle, default to STDOUT
($output_file)=@_;
my $out_FH="";
if ($output_file eq "")
{
$out_FH = \*STDOUT;
}
else
{
unless (open OUT_FH,">$output_file")
{
return 0;
}
$out_FH=\*OUT_FH;
}
return $out_FH;
}
sub Router
{
#Log into single router. Return command output in hash (with nested list)
my ($user_name,$password, $host, @commands)=@_;
my $t = Net::Telnet::Cisco->new(Host => $host,
Dump_log=> "telnetlog$host.txt");
#Log in With Username and Password
$t->login($user_name,$password);
my @level = $t->cmd("show privilege");
#Check if at level 15, if not then enable
if (!($level[0] =~ /15/))
{
# if user level not 15 then enable
$t->enable($password);
}
my $command="";
$t->cmd("terminal length 0");
my %Result=();
foreach $command (@commands)
{
@{$Result{$command}} = $t->cmd($command);
}
$t->close;
return %Result;
}
####
## Router Identification
[routers]
any-core_12016 = 192.168.1.1
any-edge_12012 = 192.168.1.2
##Group of routers
[groups]
network = [any-core_12016, any-edge_12012]