[rancid] rancid 3.7 and HP 1910-8G - can't get rancid to work with that router

Jethro R Binks jethro.binks at strath.ac.uk
Tue Dec 12 16:14:48 UTC 2017


On Mon, 11 Dec 2017, heasley wrote:

> HP OEMs a lot of their network hardware; so while badged hp, its not one
> to rancid due to the o/s.  look at rancid.types.base; there are a number
> of comments there about HP devices and the rancid types that are known to
> work with them.

1910 is a Comware 5 model.

> h3crancid is a 3rdparty module.  Those errors imply to me that some 
> command required by that module are not implemented by the device.

(I wrote it)

Output for unrecognised commands should be skipped properly (some commands 
work on some models or comware versions and not on others, but this should 
all be handled properly).

> the errors before that appear to be programming errors, likely grammar 
> that was permissible in a previous version of perl.

That seems likely, but I don't keep up much with perl to know.  But I 
don't see where this error might be coming from.

defined(%hash) is deprecated at /usr/local/rancid/bin/h3crancid line 121.
        (Maybe you should just omit the defined()?)

I've attached another h3crancid which is one I use locally.  I can't be 
sure it doesn't have some local hacks but be interesting to see if it 
makes this error go away.

Beyond that, follow David's advice by running it with some debugging, I 
would do something like:

  env NOPIPE=YES PATH=${PATH}:/usr/local/libexec/rancid rancid -d devicename

adjusting the path to rancid accordingly.  That will give you the .new and 
.raw files in the current directory which might be enlightening.

Jethro.

.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
Jethro R Binks, Network Manager,
Information Services Directorate, University Of Strathclyde, Glasgow, UK

The University of Strathclyde is a charitable body, registered in
Scotland, number SC015263.
-------------- next part --------------
#! /usr/bin/perl5
##
## $Id: $
##
## @PACKAGE@ @VERSION@
## Copyright (c) @COPYYEARS@ by Terrapin Communications, Inc.
## All rights reserved.
##
## This code is derived from software contributed to and maintained by
## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
## Pete Whiting, Austin Schutz, and Andrew Fort.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions
## are met:
## 1. Redistributions of source code must retain the above copyright
##    notice, this list of conditions and the following disclaimer.
## 2. Redistributions in binary form must reproduce the above copyright
##    notice, this list of conditions and the following disclaimer in the
##    documentation and/or other materials provided with the distribution.
## 3. All advertising materials mentioning features or use of this software
##    must display the following acknowledgement:
##        This product includes software developed by Terrapin Communications,
##        Inc. and its contributors for RANCID.
## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
##    contributors may be used to endorse or promote products derived from
##    this software without specific prior written permission.
## 5. It is requested that non-binding fixes and modifications be contributed
##    back to Terrapin Communications, Inc.
##
## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
## PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
## POSSIBILITY OF SUCH DAMAGE.
#
#  RANCID - Really Awesome New Cisco confIg Differ
#

# h3crancid
#
# h3clogin/h3crancid covers the following product ranges:
#
#  * 3Com SuperStack 4 (from 'joint venture' with Huawei)
#  * H3C
#  * HP Networking ('A' & some 'E' portfolio, post-2010 3Com acquitision)
#
# They may also work with some Huawei equipment.
#
# https://sites.google.com/site/jrbinks/code/rancid/h3c

#
# Usage: h3crancid [-dltCV] [-f filename | hostname]
#

# You can modify the behaviour by changing the variables listed in
# 'END-USER TWEAKS', below.

# Notable changes from standard *rancid programs:
#
# * abstracted path to the 'tail' utility
# * altered "cisco_cmds" to be "device_cmds"
# * define and use $logincmd
# * abstracted $rancid_type

# TODO:
#
# It may be useful to pull common subroutines like the sorting ones into
# a library for use by all the *rancid programs.
#
# abstract the comment-out char (i.e., '!' here and cisco, '#' on Juniper)
# to a variable.

# NOTES:
# 
# * the dir commands need a user greater than at least level 1 on some
#   platforms

############################################################################
# END-USER TWEAKS

# The login program to use.  If no path is given, $PATH is searched:
my $logincmd = "h3clogin";
#my $logincmd = "/usr/local/libexec/h3clogin";
#
my $TAIL = "/usr/bin/tail";
#
# Enable display of the FIB:
my $display_fib = 1;
#
# Enable display of the routing table:
my $display_iproutes = 1;
#
# Enable display of the vlans:
my $display_vlan_all = 1;
#
# Enable display of STP root:
my $display_stproot = 1;
#
# Enable display of transceiver interface:
my $display_xcvr_int = 0;

# END OF END-USER TWEAKS
#############################################################################

my $rancid_type = 'h3c';

use Getopt::Std;
getopts('dflt:CV');
if ($opt_V) {
    print "@PACKAGE@ @VERSION@\n";
    exit(0);
}
$log = $opt_l;
$debug = $opt_d;
$file = $opt_f;
$host = $ARGV[0];
$clean_run = 0;
$found_end = 0;
#$timeo = 90;			# login command timeout in seconds
$timeo = 20;			# login command timeout in seconds

my(@commandtable, %commands, @commands);# command lists
my($aclsort) = ("ipsort");		# ACL sorting mode
my($filter_commstr);			# SNMP community string filtering
my($filter_pwds);			# password filtering mode

# This routine is used to print out the router configuration
sub ProcessHistory {
    my($new_hist_tag,$new_command,$command_string, at string)=(@_);
    if((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
       && scalar %history) {
       print eval "$command \%history";
       undef %history;
    }
    if (($new_hist_tag) && ($new_command) && ($command_string)) {
        if ($history{$command_string}) {
            $history{$command_string} = "$history{$command_string}@string";
        } else {
            $history{$command_string} = "@string";
        }
    } elsif (($new_hist_tag) && ($new_command)) {
        $history{++$#history} = "@string";
    } else {
        print "@string";
    }
    $hist_tag = $new_hist_tag;
    $command = $new_command;
    1;
}

sub numerically { $a <=> $b; }

# This is a sort routine that will sort numerically on the
# keys of a hash as if it were a normal array.
sub keynsort {
    local(%lines)=@_;
    local($i) = 0;
    local(@sorted_lines);
    foreach $key (sort numerically keys(%lines)) {
        $sorted_lines[$i] = $lines{$key};
        $i++;
    }
    @sorted_lines;
}

# This is a sort routine that will sort on the
# keys of a hash as if it were a normal array.
sub keysort {
    local(%lines)=@_;
    local($i) = 0;
    local(@sorted_lines);
    foreach $key (sort keys(%lines)) {
        $sorted_lines[$i] = $lines{$key};
        $i++;
    }
    @sorted_lines;
}

# This is a sort routine that will sort on the
# values of a hash as if it were a normal array.
sub valsort{
    local(%lines)=@_;
    local($i) = 0;
    local(@sorted_lines);
    foreach $key (sort values %lines) {
        $sorted_lines[$i] = $key;
        $i++;
    }
    @sorted_lines;
}

# This is a numerical sort routine (ascending).
sub numsort {
    local(%lines)=@_;
    local($i) = 0;
    local(@sorted_lines);
    foreach $num (sort {$a <=> $b} keys %lines) {
        $sorted_lines[$i] = $lines{$num};
        $i++;
    }
    @sorted_lines;
}

# This is a sort routine that will sort on the
# ip address when the ip address is anywhere in
# the strings.
sub ipsort {
    local(%lines)=@_;
    local($i) = 0;
    local(@sorted_lines);
    foreach $addr (sort sortbyipaddr keys %lines) {
        $sorted_lines[$i] = $lines{$addr};
        $i++;
    }
    @sorted_lines;
}

# These two routines will sort based upon IP addresses
sub ipaddrval {
    my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);
    $a[3] + 256 * ($a[2] + 256 * ($a[1] + 256 * $a[0]));
}
sub sortbyipaddr {
    &ipaddrval($a) <=> &ipaddrval($b);
}

# This is a sort routine that will sort on the
# ip route when the ip route is anywhere in
# the strings.
sub iproutesort {
    local(%lines)=@_;
    local($i) = 0;
    local(@sorted_lines);
    foreach $iproute (sort sortbyiproute keys %lines) {
        $sorted_lines[$i] = $lines{$iproute};
        $i++;
    }
    @sorted_lines;
}

# These two routines will sort based upon IP route
sub iprouteval {
    my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)/(\d+)$#);
    $a[4] + ($a[3] + 256 * ($a[2] + 256 * ($a[1] + 256 * $a[0])));
}
sub sortbyiproute {
    &iprouteval($a) <=> &iprouteval($b);
}

sub filter_lines {
    my ($l) = (@_);

    # Filter out some ANSI crud as a result of us not being able to turn
    # off per-session terminal paging:
    #s/^\033\[42D +\033\[42D(.+)$/$1/;
    # hwlogin+mods:
    #s/\033\133\064\062\104\s*\033\133\064\062\104//g;
    $l =~ s/\033\133\064\062\104\s+\033\133\064\062\104//g;
    $l =~ s/\033\133\061\066\104\s+\033\133\061\066\104//g;
    $l =~ s/\033\133\064\062\104//g;
    $l =~ s/\033\133\061\062\104//g;
    $l =~ s/.*\[37D(.*)/$1/g;    # MA5600
    # Probably not needed:
    $l =~ s/\s*---- More ----\s*//;
    $l =~ s/^               //; # Comware7
    $l =~ s/Synchronization is finished.//g;
    return $l;
}

sub DisplayFib {

    print STDERR "    In DisplayFib: $_" if ($debug);

    chomp;

    # Display the command we're processing in the output:
    #s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g;
    ProcessHistory("FIB","","","!\n! '$cmd':\n!\n");

    while (<INPUT>) {
        tr/\015//d;
        last if(/^\s*$prompt/);
        chomp;
        $_ = filter_lines($_);
        return(1) if (
            /^\s+\^$/ ||
            /% Too many parameters found at '\^' position/ ||
            /% Unrecognized command found at '\^' position/ ||
            /(% )?Wrong parameter found at '\^' position/ ||
            /% Wrong device .+/ ||
            /Permission denied\./
        );

        next if /^$/;
        next if /^Destination count: \d+ FIB entry count: \d+/;

        # Chop out some detail that changes over time (Comware 3):
        s/(\s+)TimeStamp\s+/$1/;        # TimeStamp column heading

        ProcessHistory("FIB","","","! $_\n");

        if ( m,Destination/Mask, ) {
            while (<INPUT>) {
                tr/\015//d;
                last if(/^\s*$prompt/);
                chomp;
                $_ = filter_lines($_);

                # Chop out some detail that changes over time (Comware 3):
                s/(\s+)t\[\d+\]\s+/$1/;    # TimeStamp data

                # "display fib" on comware7 shows host entries for things
                # learned via arp too.  For a distribution router, that's all
                # the devices on subnets routed by it!
                # If we filter out all "UH" entries that are NOT InLoop, we
                # get acceptable output.
                #
                # So we want to keep:
                #
                # 0.0.0.0/32         127.0.0.1       UH  InLoop0 Null
                #
                # but reject:
                #
                # 10.1.44.161/32  10.1.44.161  UH  Vlan44  Null
                #
                # However I've a feeling that this is a problematic
                # solution, and some object to the notion that rancid
                # should be representing such potentially dynamic data in
                # the first place, which is why we created the
                # $display_fib flag.

		($dest, $nexthop, $flag, $outint, $label) = split;
                next if ( $flag eq 'UH' && $outint !~ /InLoop/ );
                ProcessHistory("FIB", "iproutesort", "$dest", "! $_\n");
            }

            ProcessHistory("FIB", "", "", "!\n");

            # return here to ensure that we don't keep swallowing the
            # next command's output by returning to the surrounding
            # while loop
            return(0);
        }
    }
    return(0);
}

sub DisplayIPRoutes {
    print STDERR "    In DisplayIPRoutes: $_" if ($debug);

    chomp;

    # Display the command we're processing in the output:
    #s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g;
    ProcessHistory("IPR","","","!\n! '$cmd':\n!\n");

    while (<INPUT>) {
        tr/\015//d;
        last if(/^\s*$prompt/);
        chomp;
        $_ = filter_lines($_);
        return(1) if (
            /^\s+\^$/ ||
            /% Too many parameters found at '\^' position/ ||
            /% Unrecognized command found at '\^' position/ ||
            /(% )?Wrong parameter found at '\^' position/ ||
            /% Wrong device .+/ ||
            /Permission denied\./
        );

        ProcessHistory("IPR","","","! $_\n");

        if ( m,Destination/Mask, ) {
            my $lastkey = "";
            my $lastspaces = "";
            while (<INPUT>) {
                tr/\015//d;
                last if(/^\s*$prompt/);
                chomp;
                $_ = filter_lines($_);

                # If the key is blank, indicating multiple nexthops for
                # a particular route, then we use the previous one
                if ( m/^\s+(.+)/ ) {
                    $key = $lastkey;
                    $line = $key . $lastspaces . $1;
                    ProcessHistory("IPR", "iproutesort", "$key", "! $line\n");
                    # $lastkey and $lastspaces are retained in case
                    # they are needed for an additional line
                }
                if ( m/^(\S+)(\s+).+/ ) {
                    $key = $1;
                    $line = $_;
                    $spaces = $2;
                    ProcessHistory("IPR", "iproutesort", "$key", "! $line\n");
                    $lastkey = $key;
                    $lastspaces = $spaces;
                }
            }

# This isn't quite right; for example, it messes up oddities like this:
# ...
# 10.1.2.84/30     OSPF   10   1010         10.159.2.53     Vlan3660
# 10.1.2.88/30     OSPF   10   1100         10.159.2.53     Vlan3660
#                  OSPF   10   1100         10.159.2.49     Vlan3661
# 10.1.2.92/30     OSPF   10   1015         10.159.2.53     Vlan3660
# ...

            ProcessHistory("IPR", "", "", "!\n");

            # return here to ensure that we don't keep swallowing the
            # next command's output by returning to the surrounding
            # while loop
            return(0);
        }
    }
    return(0);
}

#sub DisplayTransInt {
#    print STDERR "    In DisplayTransInt: $_" if ($debug);
#
#    chomp;
#
#    # Display the command we're processing in the output:
#    s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g;
#    ProcessHistory("TRINT","","","! $_\n!\n");
#
#    while (<INPUT>) {
#        tr/\015//d;
#        last if(/^\s*$prompt/);
#        chomp;
#        $_ = filter_lines($_);
#        return(1) if (
#            /^\s+\^$/ ||
#            /% Too many parameters found at '\^' position/ ||
#            /% Unrecognized command found at '\^' position/ ||
#            /(% )?Wrong parameter found at '\^' position/ ||
#            /% Wrong device .+/ ||
#            /Permission denied\./
#        );
#
#
#        ProcessHistory("TRINT","","","! $_\n");
#    }
#    ProcessHistory("TRINT","","","!\n");
#    return(0);
#}

#sub DisplayNTPStatus {
#    print STDERR "    In DisplayNTPStatus: $_" if ($debug);
#
#    chomp;
#
#    # Display the command we're processing in the output:
#    s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g;
#    ProcessHistory("NTP","","","! $_\n!\n");
#
#    while (<INPUT>) {
#        tr/\015//d;
#        last if(/^\s*$prompt/);
#        chomp;
#        $_ = filter_lines($_);
#        return(1) if (
#            /^\s+\^$/ ||
#            /% Too many parameters found at '\^' position/ ||
#            /% Unrecognized command found at '\^' position/ ||
#            /(% ?)Wrong parameter found at '\^' position/ ||
#            /% Wrong device .+/ ||
#            /Permission denied\./
#        );
#
#        next unless m/(Clock status|Clock stratum|Reference clock ID)/;
#
#        ProcessHistory("NTP","","","! $_\n");
#    }
#    ProcessHistory("NTP","","","!\n");
#    return(0);
#}

## This routine processes general output of "display" commands
sub CommentOutput {
    print STDERR "    In CommentOutput: $_" if ($debug);

    chomp;

    # Display the command we're processing in the output:
    #s/^[\[<].*?[\]>]\a?\s?(.*)/\'$1\':/g;
    #ProcessHistory("COMMENTS", "", "", "! $_\n!\n");
    #(my $cmd = $_) =~ s/^[\[<].*?[\]>]\a?\s?(.*)/$1/g;
    ProcessHistory("COMMENTS", "", "", "!\n! '$cmd':\n!\n");

    while (<INPUT>) {
        tr/\015//d;

        # If we find the prompt, we're done
        # Ordinarily this matches from the start of the line, however
        # we've seen circumstances at least in Comware7 where the
        # prompt is preceded by whitespace, like so:
        # ^M^M               ^M<router>display boot-loader^M
        last if(/^\s*$prompt/);
        chomp;

	# filter out some junk
        $_ = filter_lines($_);

        # Some commands are not supported on some models or versions
        # of code.  These lines simply remove the associated error
        # messages:
        return(1) if (
            /^\s+\^$/ ||
            /% Too many parameters found at '\^' position/ ||
            /% Unrecognized command found at '\^' position/ ||
            /(% )?Wrong parameter found at '\^' position/ ||
            /% Wrong device .+/ ||
            /Permission denied\./
        );

	# Now we skip or modify some lines from various commands to
        # remove irrelevant content, or to avoid insignificant diffs

        # 'display local-user':
        s/\s+Current AccessNum:.+$//;

        # 'display version':
        next if (/^(Uptime is \d|.+ [Uu]ptime is \d).+$/);
        # No longer necessary since skipping the whole Uptime line:
        # Mangle these lines:
        #s/(.*)[Uu]ptime.*.weeks.*.days*.*hours*.*minutes*(.*)/$1 $2/;
        #s/(.*)[Uu]ptime.*days*.*hours*.*minutes*(.*)/$1 $2/;

        # MSRs display a 'last reboot' time, but sometimes the seconds
        # vary by one or two (presumably internal rounding), so simply make
        # the last digit a fixed '0'.  It would probably be safer to make
        # the last two digits a fixed '00'.
        # (Thx Alexander Belokopytov)
        s/(^Last reboot.+)\d$/${1}0/;

        # 'dir ' commands
        if ( $cmd =~ /^dir / ) {
            # First field is just an index number, chop it out
            s/^\s+\d+\s+(.+)/ $1/;
            # Remove filenames that are updated frequently
            next if (
                /logfile\.log$/ ||
                /lauth\.dat$/ ||
                /ifindex\.dat$/ ||
                /startup\.mdb$/ ||
                /private-data\.txt$/ ||
                /dhcpleases$/ ||
                /.+ KB total \(.+ KB free/ ||
                /.+ KB total \(.+ KB free/ ||
                /\.trash/
            );
        }

	# 'display ospf brief'/'display ospf'
        if ( $cmd =~ 'display ospf( brief)?' ) {
            #next if (/^(Ospf is not enabled yet|Info: OSPF routing process is not enabled|The feature OSPF has not been enabled.).+$/);
            next if (/^\s+SPF (Computation|Scheduled|calculation) Count:.+$/i);
        }

        if ( $cmd eq 'display power' ) {
            next if (/^(\s+Input Power).+$/);
        }

        if ( $cmd eq 'display poe powersupply' ) {
            next if (/^(PSE Total Power Consumption|PSE Available Power|PSE Peak Value|PSE Average Value).+$/);
        }

        if ( $cmd eq 'display ntp-service status' ) {
            next unless m/(Clock status|Clock stratum|Reference clock ID)/i;
        }

        if ( $cmd eq 'display transceiver interface' ) {
            s/^(\S+ transceiver information:).+$/$1/;   # filter random garbage
            s/^Error: The transceiver is absent.$/  No transceiver present./;
            s/^Error: The combo port is inactive.$/  Inactive combo port./;
        }

        # Add the processed lines to the output buffer:
        ProcessHistory("COMMENTS","","","! $_\n");
    }

    # Add a blank comment line to the output buffer
    ProcessHistory("COMMENTS", "", "", "!\n");
    return(0);
}

## This routine processes a "display current"
sub DisplayCurrent {
    print STDERR "    In DisplayCurrent: $_" if ($debug);

    # We aren't chomping these lines

    while (<INPUT>) {
        tr/\015//d;
        last if(/^\s*$prompt/);

        $_ = filter_lines($_);
        return(0) if ($found_end);

        # Filter out some sensitive data:
        if ( $filter_commstr &&
             /^ ?(snmp-agent (usm-user|community (read|write)) )(\S+)/ 
           ) {
            ProcessHistory("","","","! $1<removed>$'");
            next;
        }
        if ( $filter_pwds >= 1 &&
            /^ ?(password (?:simple|cipher) )(\S+)/ ||
            /^ ?(super password( level \d)? (cipher|simple) )(\S+)/ ||
            /^ ?(set authentication password (cipher|simple) )(\S+)/ ||
            /^ ?(key (?:authentication|accounting) )(\S+)/ 
           ) {
            ProcessHistory("","","","! $1<removed>$'");
            next;
        }

	# Filter mac addresses dynamically added to config
	next if (/^ ?mac-address security.+$/);

        ProcessHistory("", "", "", "$_");

        # end of config
	
        if (/^return/) {
            $found_end = 1;
            return(0);
        }
    }
    return(0);
}

# dummy function
sub DoNothing {print STDOUT;}

# Main
## Not all commands are supported on all models and code versions
## Not all of these should necessarily be included
@commandtable = (
# Commands relating to the operating system/version:
    {'display version'			=> 'CommentOutput'},
    {'display boot-loader'		=> 'CommentOutput'},
    {'display startup'			=> 'CommentOutput'},
    {'dir /all'				=> 'CommentOutput'},
    {'dir /all unit2>flash:/'		=> 'CommentOutput'},
    {'dir /all slot2#flash:/'		=> 'CommentOutput'},
    {'dir /all unit3>flash:/'		=> 'CommentOutput'},
    {'dir /all slot3#flash:/'		=> 'CommentOutput'},
    {'dir /all unit4>flash:/'		=> 'CommentOutput'},
    {'dir /all slot4#flash:/'		=> 'CommentOutput'},
    {'dir /all unit5>flash:/'		=> 'CommentOutput'},
    {'dir /all slot5#flash:/'		=> 'CommentOutput'},
    {'dir /all unit6>flash:/'		=> 'CommentOutput'},
    {'dir /all slot6#flash:/'		=> 'CommentOutput'},
    {'dir /all unit7>flash:/'		=> 'CommentOutput'},
    {'dir /all slot7#flash:/'		=> 'CommentOutput'},
    {'dir /all unit8>flash:/'		=> 'CommentOutput'},
    {'dir /all slot8#flash:/'		=> 'CommentOutput'},
# Commands relating to the hardware:
    {'display device'			=> 'CommentOutput'},
    {'display device manuinfo'		=> 'CommentOutput'},
    {'display fan'			=> 'CommentOutput'},
    {'display power'			=> 'CommentOutput'},
    {'display poe powersupply'		=> 'CommentOutput'},
    {'display poe temperature-protection'	=> 'CommentOutput'},
    {'display transceiver interface'   => 'CommentOutput'},
# Commands relating to authentication:
    {'display cluster'			=> 'CommentOutput'},
    {'display domain'			=> 'CommentOutput'},
    {'display local-user'		=> 'CommentOutput'},
    {'display password-control'		=> 'CommentOutput'},
    {'display password-control super'	=> 'CommentOutput'},
    {'display ssh server status'	=> 'CommentOutput'},
# Commands relating to system state:
    {'display irf'			=> 'CommentOutput'},
    {'display xrn-fabric'		=> 'CommentOutput'},
    {'display ftm topology-database'	=> 'CommentOutput'},
    {'display fib'			=> 'DisplayFib'},
    {'display ip routing-table'		=> 'DisplayIPRoutes'},
    {'display ospf'			=> 'CommentOutput'},
    {'display ospf brief'		=> 'CommentOutput'},
    {'display vlan all'			=> 'CommentOutput'},
    {'display lacp sys'			=> 'CommentOutput'},
    {'display link-aggregation summary'	=> 'CommentOutput'},
    {'display link-aggregation verbose'	=> 'CommentOutput'},
    {'display mirror all'		=> 'CommentOutput'},
    {'display ntp-service status'       => 'CommentOutput'},
    {'display stp root'                 => 'CommentOutput'},
# And the system config itself:
    {'display current-configuration'	=> 'DisplayCurrent'},
);

# Remove some commands from the comman table if the user has toggled the
# options not to execute them
if ($display_fib == 0) 
    { grep(delete $$_{'display fib'} , @commandtable) };
if ($display_iproutes == 0) 
    { grep(delete $$_{'display ip routing-table'} , @commandtable) };
if ($display_vlan_all == 0)
    { grep(delete $$_{'display vlan all'} , @commandtable) };
if ($display_stproot == 0)
    { grep(delete $$_{'display stp root'} , @commandtable) };
if ($display_xcvr_int == 0)
    { grep(delete $$_{'display transceiver interface'} , @commandtable) };

# Use an array to preserve the order of the commands and a hash for mapping
# commands to the subroutine and track commands that have been completed.
@commands = map(keys(%$_), @commandtable);
%commands = map(%$_, @commandtable);
$commandcnt = scalar(keys %commands);

$device_cmds=join(";", at commands);
$cmds_regexp=join("|", map quotemeta($_), @commands);

if (length($host) == 0) {
    if ($file) {
        print(STDERR "Too few arguments: file name required\n");
        exit(1);
    } else {
        print(STDERR "Too few arguments: host name required\n");
        exit(1);
    }
}
if ($opt_C) {
    print "$logincmd -t $timeo -c\'$commandstr\' $host\n";
    exit(0);
}
open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
select(OUTPUT);
# make OUTPUT unbuffered if debugging
if ($debug) { $| = 1; }

if ($file) {
    print STDERR "opening file $host\n" if ($debug);
    print STDOUT "opening file $host\n" if ($log);
    open(INPUT,"<$host") || die "open failed for $host: $!\n";
} else {
    print STDERR "executing $logincmd -t $timeo -c\"$device_cmds\" $host\n" if ($debug);
    print STDOUT "executing $logincmd -t $timeo -c\"$device_cmds\" $host\n" if ($log);
    if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
#	system "$logincmd -noenable -t $timeo -c \"$device_cmds\" $host </dev/null > $host.raw 2>&1" || die "$logincmd failed for $host: $!\n";
#    system "$logincmd -t $timeo -c \"$device_cmds\" $host </dev/null > $host.raw 2>&1" || die "$logincmd failed for $host: $!\n";
    system "$logincmd -t $timeo -c \"$device_cmds\" $host </dev/null > $host.raw 2>&1" || die "$logincmd failed for $host: $!\n";
    open(INPUT, "< $host.raw") || die "$logincmd failed for $host: $!\n";
    } else {
#	open(INPUT,"$logincmd -noenable -t $timeo -c \"$device_cmds\" $host </dev/null |") || die "$logincmd failed for $host: $!\n";
    open(INPUT,"$logincmd -t $timeo -c \"$device_cmds\" $host </dev/null |") || die "$logincmd failed for $host: $!\n";
    }
}

# determine ACL sorting mode
if ($ENV{"ACLSORT"} =~ /no/i) {
    $aclsort = "";
}
# determine community string filtering mode
if (defined($ENV{"NOCOMMSTR"}) &&
    ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
    $filter_commstr = 1;
} else {
    $filter_commstr = 0;
}
# determine password filtering mode
if ($ENV{"FILTER_PWDS"} =~ /no/i) {
    $filter_pwds = 0;
} elsif ($ENV{"FILTER_PWDS"} =~ /all/i) {
    $filter_pwds = 2;
} else {
    $filter_pwds = 1;
}

ProcessHistory("","","","!RANCID-CONTENT-TYPE: $rancid_type\n!\n");
#ProcessHistory("COMMENTS","keysort","B0","!\n");
#ProcessHistory("COMMENTS","keysort","D0","!\n");
#ProcessHistory("COMMENTS","keysort","F0","!\n");
#ProcessHistory("COMMENTS","keysort","G0","!\n");
TOP: while(<INPUT>) {
    tr/\015//d;
# h3c:
# Look for the command at the end of the output
#    if (/\#exit$/) {
#    if (/\#quit$/) {
# h3c:
     if (/[\]>#]\a?\s*quit/) {
#    if (/^[\[<].*[\]>]\a?\s?quit/) {
      $clean_run=1;
      last;
    }
    if (/^Error:/) {
    print STDOUT ("$host $logincmd error: $_");
    print STDERR ("$host $logincmd error: $_") if ($debug);
    $clean_run=0;
    last;
    }
#    while (/#\s*($cmds_regexp)\s*$/) {
# h3c:
    while (/[\]>#]\a?\s*($cmds_regexp)\s*$/) {
#    while (/^[\[<].*[\]>]\a?\s*($cmds_regexp)\s*$/) {
    $cmd = $1;
    if (!defined($prompt)) {
    # h3c:
    # Extract the prompt: look for something not [ or < at the start
    # of the line, until either ] or > or # is reached:
        #$prompt = ($_ =~ /^([^#]+#)/)[0];
        #$prompt =~ s/([][}{)(\\])/\\$1/g;
        #$prompt = ($_ =~ /^([^\]>]+[\]>]\007?)/)[0]; 
        $prompt = ($_ =~ /^([^\]>#]+[\]>]\a?)/)[0]; 
        $prompt =~ s/([][}{)(\\])/\\$1/g;
	print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
    }

    print STDERR ("HIT COMMAND:$_") if ($debug);
    if (! defined($commands{$cmd})) {
        print STDERR "$host: found unexpected command - \"$cmd\"\n";
        $clean_run = 0;
        last TOP;
    }
    $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd);
    delete($commands{$cmd});
    if ($rval == -1) {
        $clean_run = 0;
        last TOP;
    }
    }
}
print STDOUT "Done $logincmd: $_\n" if ($log);
# Flush History
ProcessHistory("","","","");
# Cleanup
close(INPUT);
close(OUTPUT);

if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
    unlink("$host.raw") if (! $debug);
}

printf(STDOUT "$host: clean_run=$clean_run found_end=$found_end\n") if ($debug);

# check for completeness
if (scalar(%commands) || !$clean_run || !$found_end) {
    if (scalar(keys %commands) eq $commandcnt) {
        printf(STDERR "$host: missed cmd(s): all commands\n");
    } elsif (scalar(%commands)) {
        printf(STDOUT "$host: missed cmd(s): %s\n", join(',', keys(%commands)));
        printf(STDERR "$host: missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug);
    }
    if (!$clean_run || !$found_end) {
        print STDOUT "$host: End of run not found\n";
        print STDERR "$host: End of run not found\n" if ($debug);
        system("$TAIL -1 $host.new");
    }
    unlink "$host.new" if (! $debug);
}


More information about the Rancid-discuss mailing list