Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

(code) Cisco sho ver

by ybiC (Prior)
on Apr 12, 2001 at 05:49 UTC ( #71921=sourcecode: print w/ replies, xml ) Need Help??

Category: Networking Code
Author/Contact Info ybiC
Description: Automate collection of Cisco router and LAN switch information for inventory purposes:
    device name, hardware type, IOS/CatOS ver, serial number

From a Perlish standpoint, this has been an excercise in using hashes instead of buckets o' scalar variables or array with obtuse $file[0], and more discriminate use of subroutines so not need passel o' global variables.

Updated:
2001-04-13 perldoc switchver.pl for details.

Todo:
Use Net::Snmp sysDescr instead of Net::Telnet::Cisco.
    simplify data structure
    simplify parsing
    simplify program
    improve security

#!/usr/bin/perl -w

# switchver.pl
# pod at tail

use strict;
use Net::Telnet::Cisco;                    # simplify telnet to Cisco 
+devices
use Term::ReadKey;                         # disable screen echo durin
+g password entry
use Getopt::Long;                          # support command-line swit
+ches
use vars qw(
    $opt_target
    $opt_infile
    $opt_outfile
    @targets
    );

my %ntcparm = (
    errmode    => 'return',                # bad command won't kill sc
+ript
    ntctimeout => 20,                      # seconds to wait for devic
+e response
    pwtimeout  => 120,                     # seconds to wait for passw
+ord entry from user
    );
my %file = (
    def_out => 'switchver.csv',
    tmp0    => 'switchver.tmp0',
    tmp1    => 'switchver.tmp1',
    tmp2    => 'switchver.tmp2',
    );
my @tmpfiles = (
    $file{tmp0},
    $file{tmp1},
    $file{tmp2}
    );
my @commands = (                           # run these from Net::Telne
+t::Cisco session
    'term leng 0',                         # IOS
    'set leng 0',                          # CatOS
    'sho ver',                             # What This Program Is All 
+About
    );
my @keep = (                               # whole lines of text to be
+ *kept*
    '>sho ver',                            # IOS device name
    # 'Version',                           # IOS
    # 'System serial number',              # IOS
    # 'uptime',                            # IOS
    '> sho ver',                           # CatOS device name
    'WS-C',                                # CatOS
    );
my @strip = (                              # specific text to be *stri
+pped* from what's left
    '\r',                                  # CatOS bogus end-of-line (
+should be first regexp)
    '>sho ver',                            # IOS device name
    '> sho ver',                           # 2948g device name
    'System Bootstrap.*$',                 # 2948g
    'Hardware Version.*$',                 # 2948g
    'System serial number: ',              # IOS
    'Model number.*$',                     # 3548
    'cisco ',                              # IOS to leave model as lea
+ding string in line
    ' \(PowerPC.*$',                       # IOS processor, memory, et
+c following model number
    'Software.*$',                         # CatOS sw info following m
+odel number
    '^\d.*',                               # CatOS chassis blade hw in
+fo
    '^\s+',                                # leading blanks
    ',',                                   # first step to csv-ifying 
+output
    );

######################################################################
+############
# preliminaries and opening message
umask oct 177;                             # temp files viewable only 
+by user running this program
print "\nStarting $0\n";
GetOptions(
    'target=s'  => \$opt_target,
    'infile=s'  => \$opt_infile,
    'outfile=s' => \$opt_outfile,
    );

######################################################################
+############
# get list of target device(s)
if (defined $opt_target) {
    @targets = $opt_target;
    print "  Target given at command-line switch.\n";
    }
elsif (defined $opt_infile) {
    $file{in} = $opt_infile;
    unless (-r $file{in} && -T _) {
        &USAGE("Error reading input file \"$file{in}\": \"$!\"");
        }
    print "  Target list at $file{in}\n";
    open (INFILE, "< $file{in}")               or die "Error opening $
+file{in}: $!";
    @targets = <INFILE>;
    close INFILE;
    }
else {
    &USAGE('Error - target device or input file not specified!');
     }

######################################################################
+############
# get name of output file
if (defined $opt_outfile) {
    $file{out} = $opt_outfile;
    print "  Output file given at command-line switch.\n";
    }
else {
    $file{out} = $file{def_out};
    print "  Using default output file.\n";
    }

######################################################################
+########
# sanity-check target(s) list
print "  Validating target list...\n";
foreach my $nonsane(@targets) {
    chomp $nonsane;
    print ("    $nonsane\n");
    unless ($nonsane =~ (/^(\w|-|\.)+$/)) {
        print "\n  Ack - \"$nonsane\" is an improperly formatted devic
+e name.\n";
        print "  Only alphanumeric, underscore, dash and dot allowed.\
+n\n";
        print "  Edit $file{in} or re-enter targets to remove puctuati
+on, blank lines and/or blank spaces.\n\n";
        exit;                              # "exit" instead of "die" s
+o no error to console
        }
    }
print ("  Specified target name(s) valid.\n");

######################################################################
+############
# prompt for access password (enable pass not needed for 'show ver' co
+mmand
print "  Enter access password (*not* echoed to screen): ";
ReadMode('noecho');                        # don't echo password to sc
+reen
eval {
    local $SIG{ALRM} = sub { die "ALARUM" };
    alarm("$ntcparm{pwtimeout}");
    chomp($ntcparm{pwinput} = <STDIN>);
    alarm(0);
    };
if ($@ =~ /ALARUM/) {
    print "\n\n";
    print "Sorry - You waited too long before entering a password.\n";
    print "Try again, if you want.\n\n";
    ReadMode(0);                           # re-activate screen echo
    exit;                                  # "exit" instead of "die" s
+o no error to console
    }
$ntcparm{password} = $ntcparm{pwinput};
ReadMode(0);                               # re-activate screen echo
print "\n";

######################################################################
+########
# delete existing out/tmp files
print '  Unlinking prior out and temp files...';
&UNLINK($file{out}, 'quiet');
foreach my $tmpfile (@tmpfiles) {
    &UNLINK($tmpfile, 'quiet');
    }
print "  *poof*\n";

######################################################################
+############
# connect to each target device, then run command to get device info
print ("  Target devices queried:\n");
foreach my $target(@targets) {
    my $ntc;
    chomp $target;
    if ($ntc=Net::Telnet::Cisco->new(
        host      => $target,
        timeout   => $ntcparm{ntctimeout},
        errmode   => $ntcparm{errmode},
        input_log => $file{tmp0},
        ))
        {
        $ntc->login('',$ntcparm{password});
        print "    ", $ntc->last_prompt, " ";
        foreach my $command (@commands) {
            my @output = $ntc->cmd($command);
            }
        print "    ", $ntc->last_prompt, "\n";
        $ntc->close;

        # if multiple Cisco sessions, append each to same tmpfile
        open (TMP0, "<$file{tmp0}")        or die "Can't open $file{tm
+p0} RO: \"$!\"";
        open (TMP1, ">>$file{tmp1}")       or die "Can't open $file{tm
+p1} for append: \"$!\"";
        while (<TMP0>) { print TMP1 $_; }
        close (TMP0)                       or die "Can't close $file{t
+mp0}: \"$!\"";
        close (TMP1)                       or die "Can't close $file{t
+mp1}: \"$!\"";
        } else { warn "Can't connect to $target\n";} #: " . $ntc->errm
+sg; }          # if telnet connection failed
    my @output = $ntc->cmd();
    }
&UNLINK ($file{tmp0}, 'quiet');            # don't leave pw's laying a
+round

######################################################################
+############
# munge temp file data
# extract lines we *do* want to see
open (TMP1, "<$file{tmp1}")                or die "Can't open $file{tm
+p1} RO: \"$!\"";
open (TMP2, ">>$file{tmp2}")               or die "Can't open $file{tm
+p2} WO: \"$!\"";
while (<TMP1>) {
    foreach my $keep(@keep) {
        print (TMP2 $_) if /$keep/;
        }
    }
close (TMP1)                               or die "Can't close $file{t
+mp1}: \"$!\"";
close (TMP2)                               or die "Can't close $file{t
+mp2}: \"$!\"";
#---------------------------------------------------------------------
+---#
# delete specific text don't care about
open (TMP2, "<$file{tmp2}")                or die "Can't open $file{tm
+p2} RO: \"$!\"";
open (OUT,  ">>$file{out}")                or die "Can't open $file{ou
+t} WO: \"$!\"";
    while (<TMP2>) {
        foreach my $strip(@strip) {
            s/$strip//g;
            }
        s/\n/,\n/g;                        # second step toward csvify
+ing
        s/\s+,/,/g;                        # CatOS device-type
        chomp unless(/WS-/);               # final step to csvify
        print (OUT $_);
    }
close (TMP2)                               or die "Can't close $file{t
+mp2}: \"$!\"";
close (OUT)                                or die "Can't close $file{o
+ut}: \"$!\"";
 
######################################################################
+############
# turn out the lights, it's time to go
print "  Finished switch versions check.\n";
print '  Unlinking temp files...';
foreach my $tmpfile(@tmpfiles) {
    &UNLINK($tmpfile, 'quiet');
    }
print "  *poof*\n";
print "Results at $file{out}\n\n";


######################################################################
+########
# Subroutines start here
######################################################################
+########

# cleanup temp files when done with them
sub UNLINK {
    my $file = $_[0];
    my $echo = $_[1];
    if (-e $file && -w _) {
        print "  Unlinking $file..."       if ($echo eq 'verbose');
        unlink $file                       or die "Error unlinking $fi
+le: \"$!\"";
        print "  *poof*\n"                 if ($echo eq 'verbose');
        }
    }
######################################################################
+###
sub PAUSE {
    print "  Ctrl+c to abort  or  <enter> to continue.";
    (<STDIN>);
    }
######################################################################
+############
# Really don't have to explain this'un, eh?
sub USAGE {
    my $specific_err = $_[0];
    print <<EOF;

$specific_err

Usage: getopt.pl <(-t|--target) host> <(-i|--infile) file> <(-o|--outf
+ile) file>

If target given, then infile switch is ignored.
Target can be IP address or hostname or FQDN.

Switches include:
(note that "=" is optional)
  --target=sparky         *or*  -t 172.31.0.5
  --outfile another_file  *or*  -o=another_file
  --infile=some_file      *or*  -i some_file

You *must* specify either targets or infile.
If no outfile given, then hardcoded $file{def_out} is used.

EOF
    ;
    exit;
    }
######################################################################
+############


=head1 Name

 switchver.pl

=head1 Summary

 Automate collection of Cisco LAN switch and router information:
   device name, hardware type, IOS/CatOS ver, serial number
 Comments or suggestions are quite welcomed.

=head1 Usage

 Usage: getopt.pl <(-t|--target) host> <(-i|--infile) file> <(-o|--out
+file) file>

 If target given, then infile switch is ignored.
 Target can be IP address or hostname or FQDN.

 Switches include:
 (note that "=" is optional)
   --target=sparky         *or*  -t 172.31.0.5
   --outfile another_file  *or*  -o=another_file
   --infile=some_file      *or*  -i some_file

 You *must* specify either targets or infile.
 If no outfile given, then hardcoded $file{def_out} is used.


=head1 Tested

 with:    Perl 5.00503 on Debian 2.2 "Espy"
 against: 2916, 2924, 3548, 2948g, 4000 5000, 6000

=head1 Updated

 2001-04-13  17:30  Remove unecessary Getopt::Long switch abreviations
                    Outfile in csv format
                    Add '\r' to @strip regexp for CatOS data >8^(
 2001-04-11         Add command-line switches for target, infile, outf
+ile
                      using Getopt::Long.
                    Submit to www.perlmonks.org.
 2001-04-10         Hashamafy file and ntc variables.
                    Sanity-check target names.
                    Prompt for access password instead of hard-coded.
 2001-04-03         Eliminate unecessary global variables.
                    Consistant indenting.
                    Replace double quotes with single for strings.
                    Eliminate quotes for numbers.
                    Replace multiple "my $tmpfile" with @tmpfile.
                    Unlink temp files instead of overwrite.
                    Add &USAGE().
               
 2000-10-05         Initial working code.

=head1 ToDos

 Use Net::Snmp sysDescr instead of Net::Telnet::Cisco.
   simplify data structure
   simplify parsing/munging
   simplify program
   improve security
 Add regex so hostname with IPaddr-format not stripped by '^\d' in @st
+rip
 Fix ntc so not die on unreachable target
 Print console to logfile so record of failed attempts
 Hashamafy Getopt::Long scalar variables
 Add support for multiple targets and -t switch.
 Use File::Temp instead of $file{tmp(0..2)}.

=head1 Author

 ybiC

=head1 Credits

thanks to Petruchio, jeroenes, geektron, damian1301,
  crazyinsomniac, ar0n and yakko for Getopt::Long suggestions.

=cut



Comment on (code) Cisco sho ver
Download Code
Re: Cisco sho ver
by idnopheq (Chaplain) on Apr 12, 2001 at 18:22 UTC
    Very nice! I like the interface, and this script provides useful information. I cannot count the number of routers & switches the LAN/WAN folks deploy w/o providing the info about the hardware. At least they're kind enough to set up the RADUIS and tell us the IP.

    Have yourself a Fresca(tm)!

    --
    idnopheq
    Apply yourself to new problems without preparation, develop confidence in your ability to to meet situations as they arrise.

Back to Code Catacombs

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: sourcecode [id://71921]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (5)
As of 2014-12-29 07:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (185 votes), past polls