Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Peer review of Cisco switch administration utility (was: ok I know it's crap but I'm proud of it...)

by fingers (Acolyte)
on May 10, 2001 at 11:16 UTC ( #79340=perlquestion: print w/replies, xml ) Need Help??

fingers has asked for the wisdom of the Perl Monks concerning the following question:

I currently have quite alot of cisco switches and routers that I am responsible for maintaining. I got very sick of having to log into a dozen different devices to make the same changes on everyone of them.

I started playing around with perl hoping it would get the job done. I've really never done much programming in the past, aside from very simple shell scripts.

I wrote the following piece of code to simplify my life abit and am happy with how it works. I know there are some obvious security problems with it (currently I run it as root to be able to ping my targets first to verify that they are up) and there are problem several spots where I could have been much more concise.

I am basically looking for some constructive criticism on what I've got and how to improve it. Like I wrote earlier I don't have much programming experience so don't abuse me too bad.

The script takes as its first argument the name of the file that it will feed to the device it connects to. It can take as additional arguments either the name of a file full of IPs(specified with -l as the second argument) or will accept any number of IPs as arguments.

#!/usr/bin/perl -w #********************************************************************* +** #** Written to make making the same configuration changes to a number +** #** of devices less of a pain in the ass. Written with CISCO Routers +** #** and switches in mind it should work with any devices that can be +** #** sent commands via telnet. +** #********************************************************************* +** use strict; my ($script, $i, $telnetpid); unless ( @ARGV >= 2 ) { die "usage: $0 script ip ... " }#Test to verif +y that the re is the minimum number of arguments $script = $ARGV[0]; #Take the first argument as the name of the fi +le to pull commands from shift; #Remove the first argument from the list of ar +guments #Feeding a list of IPs if ( $ARGV[0] eq '-l' ){ #If the new first argument is -l we know to l +ook for a list of IPs if ( $ARGV[1] ){ #Make sure there is a list specified on the c +ommand lin e open(IPLIST, $ARGV[1]) || die "can't open $ARGV[1]\n"; while(<IPLIST>){ feedip($script, $_); } close(IPLIST) } else { die "Need to supply a list of IPs when using $ARGV[0] + \n"; } } #Feeding IPs from the command line else { foreach $i (@ARGV ) { feedip($script, $i); } } #*************************************************************** #** Subroutines below here ** #*************************************************************** #This subroutine is based heavily on code mooched from "Learning Perl" + by Randal l Schwartz and Tom Christainsen sub telnet { use IO::Socket; my ($host, $port, $kidpid, $handle, $line); unless (@_ == 2) { die "usage: $0 host port" } $host = $_[0]; $port = $_[1]; #creates a tcp connection to the specified host and port $handle = IO::Socket::INET->new(Proto => "tcp", PeerAddr => $host, PeerPort => $port) or die "can't connect to port $port on $host: $!"; $handle->autoflush(1); # so output gets there right away print STDERR "[Connected to $host:$port]\n"; # split the program into two processes die "can't fork: $!" unless defined($kidpid = fork()); #the if{} block runs only in the parent process if ($kidpid) { #copy the socket to standard output while (defined ($line = <$handle>)) { print STDOUT $line; } kill("TERM", $kidpid); #send SIGTERM to child } #the else{} block runs only in the child process else { # copy standard input to the socket while (defined ($line = <SCRIPT>)){ print $handle $line; } } } sub feedip { my($p); use Net::Ping; $p = new Net::Ping("icmp"); unless (@_ == 2) { die "usage: $0 host port" } if ($_[1] =~ m{\d+\.\d+\.\d+\.\d+}){ #Test to see if we +were given an IP, invalid IPs can still slip through if ($p->ping($_[1])){ #Test to see that host is up $p->close(); open(SCRIPT, $_[0]) || die "Cannot open $scrip +t\n"; # Open the script file #Fork a new process for the telnet subroutine, + wait for it to finish before returning if (!defined($telnetpid = fork())) { die "Cannot fork: $!"; } elsif ($telnetpid == 0) { telnet($_[1], 23); #Options be +ing sent t o sub telnet( IP, Port) exit; } else { waitpid($telnetpid, 0); } close(SCRIPT) || die "Cannot close $script\n"; + #Close th e script file } else{ print "$_[1] does not appear to be responding, + skipping. \n"; $p->close(); } } else { warn "$_[1] did not appear to be an IP address, skippi +ng.\n "; } }
Thanks in advance for any input you can give me.

2001-05-14 Edit by Corion : Changed title to be more descriptive. Added formatting.

  • Comment on Peer review of Cisco switch administration utility (was: ok I know it's crap but I'm proud of it...)
  • Download Code

Replies are listed 'Best First'.
Re: ok I know it's crap but I'm proud of it...
by LiTinOveWeedle (Scribe) on May 10, 2001 at 12:17 UTC
    Hi man,
    You can simplified your work a lot when you use Net::Telnet::Cisco lib - I using it - and if your switches have an IOS it's piece of cake with this lib. Try CPAN for details.

    I am using this lib to print commands from external config file to telnet connection to device and also to get summmary reports from my Cisco devices.

    Li Tin O've Weedle
    mad Tsort's philosopher

Re: ok I know it's crap but I'm proud of it...
by Mungbeans (Pilgrim) on May 10, 2001 at 15:04 UTC
    Looks cool, some brief comments:

    You may want to use Getopt::Long and pod2usage to get your arguments, and print errors if insufficient args (perldoc getopt::long). I like to assign args to my variables early rather than passing ARGV around - it makes it easier to work out what parameters a subroutine is using.

    Consider validating the IP addresses after you get parameters, drop a warning message then and only feedip the valid ones. This reduces the nesting.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://79340]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (5)
As of 2023-10-03 04:02 GMT
Find Nodes?
    Voting Booth?

    No recent polls found