Backup/Restore from RANCID

DOWNLOAD THE LATEST FIRMWARE HERE
User avatar
mnitech
Member
 
Posts: 21
Joined: Wed Oct 21, 2015 1:21 pm
Location: Morgan Hill, CA
Has thanked: 0 time
Been thanked: 0 time

Re: Backup/Restore from RANCID

Sat Jan 09, 2016 5:49 pm

What you have sounds good. I just want to track changes. The binary method seems to be good for a backup but won't track changes.

User avatar
SyncKev
Member
 
Posts: 6
Joined: Wed Dec 09, 2015 3:24 pm
Location: Bremen, GA
Has thanked: 0 time
Been thanked: 1 time

Re: Backup/Restore from RANCID

Tue Jan 19, 2016 10:30 am

mnitech wrote:What you have sounds good. I just want to track changes. The binary method seems to be good for a backup but won't track changes.


Here is the script I created and tested. Since it does not contain all of the information needed for a full restore, I have not worked on it further. Some additional code cleanup could be done. I named the script 'ntxrancid'


Code: Select all
 

#! /usr/bin/perl
##
## $Id: adrancid.in,v 1.172 2004/03/14 16:57:05 heas Exp $
##
## Copyright (C) 1997-2004 by Terrapin Communications, Inc.
## All rights reserved.
##
## This software may be freely copied, modified and redistributed
## without fee for non-commerical purposes provided that this license
## remains intact and unmodified with any RANCID distribution.
##
## There is no warranty or other guarantee of fitness of this software.
## It is provided solely "as is". The author(s) disclaim(s) all
## responsibility and liability with respect to this software's usage
## or its effect upon hardware, computer systems, other software, or
## anything else.
##
## Except where noted otherwise, rancid was written by and is maintained by
## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz.
##
##
##
## Netonix - Will perform 'show config' on netonix switches; however, this is not enough information
## for a full config restore.
#
# RANCID - Really Awesome New Cisco confIg Differ
#
# usage: rancid [-d] [-l] [-f filename | $host]
#
use Getopt::Std;
getopts('dfl');
$log = $opt_l;
$debug = $opt_d;
$file = $opt_f;
$host = $ARGV[0];
$clean_run = 0;
$found_end = 0;
$timeo = 90; # clogin timeout in seconds

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,@string)=(@_);
 if((($new_hist_tag ne $hist_tag) || ($new_command ne $command))
 && defined %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 routing 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 routing 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 routing 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 routing (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 routine processes a "write term"
sub WriteTerm {
 print STDERR " In WriteTerm: $_" if ($debug);
 my($lineauto,$comment,$linecnt) = (0,0,0);

 while (<INPUT>) {
 tr/\015//d;
 last if(/^$prompt/);
 return(0) if ($found_end); # Only do this routine once
 $linecnt++;
 $lineauto = 0 if (/^[^ ]/);
 # skip the crap
 if (/^(##+$|(Building|Current) configuration)/i) {
 while (<INPUT>) {
 next if (/^Current configuration\s*:/i);
 next if (/^:/);
 next if (/^([%!].*|\s*)$/);
 last;
 }
 tr/\015//d;
 }

 # skip consecutive comment lines to avoid oscillating extra comment
 # line on some access servers. grrr.
 if (/^!/) {
 next if ($comment);
 ProcessHistory("","","",$_);
 $comment++;
 next;
 }
 $comment = 0;

 # Dog gone Cool matches to process the rest of the config
 /^ntp clock-period / && next; # kill ntp clock-period
 /^ length / && next; # kill length on serial lines
 /^ width / && next; # kill width on serial lines
 $lineauto = 1 if /^ modem auto/;
 /^ speed / && $lineauto && next; # kill speed on serial lines
 /^ clockrate / && next; # kill clockrate on serial interfaces
 if (/^(enable )?(password|passwd) / && $filter_pwds >= 1) {
 ProcessHistory("ENABLE","","","!$1$2 <removed>\n");
 next;
 }
 if (/^(enable secret) / && $filter_pwds >= 2) {
 ProcessHistory("ENABLE","","","!$1 <removed>\n");
 next;
 }
 if (/^username (\S+)(\s.*)? secret /) {
 if ($filter_pwds >= 2) {
 ProcessHistory("USER","keysort","$1","!username $1$2 secret <removed>\n");
 } else {
 ProcessHistory("USER","keysort","$1","$_");
 }
 next;
 }
 if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) {
 if ($filter_pwds >= 2) {
 ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n");
 } elsif ($filter_pwds >= 1 && $4 ne "5"){
 ProcessHistory("USER","keysort","$1","!username $1$2 password <removed>\n");
 } else {
 ProcessHistory("USER","keysort","$1","$_");
 }
 next;
 }
 if (/^( set session-key (in|out)bound ah \d+ )/ && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1<removed>\n");
 next;
 }
 if (/^( set session-key (in|out)bound esp \d+ (authenticator|cypher) )/ && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1<removed>\n");
 next;
 }
 if (/^(\s*)password / && $filter_pwds >= 1) {
 ProcessHistory("LINE-PASS","","","!$1password <removed>\n");
 next;
 }
 if (/^(\s*)secret / && $filter_pwds >= 2) {
 ProcessHistory("LINE-PASS","","","!$1secret <removed>\n");
 next;
 }
 if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) {
 ProcessHistory("","","","! neighbor $1 password <removed>\n");
 next;
 }
 if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed>\n"); next;
 }
 if (/^(ip ftp password) / && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed>\n"); next;
 }
 if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed>\n"); next;
 }
 # isis passwords appear to be completely plain-text
 if (/^\s+isis password (\S+)( .*)?/ && $filter_pwds >= 1) {
 ProcessHistory("","","","!isis password <removed>$2\n"); next;
 }
 if (/^\s+(domain-password|area-password) (\S+)( .*)?/
 && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed>$3\n"); next;
 }
 # this is reversable, despite 'md5' in the cmd
 if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed>\n"); next;
 }
 if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed> $'"); next;
 }
 # filter HSRP passwords
 if (/^(\s+standby \d authentication) / && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed>\n"); next;
 }
 # this appears in "measurement/sla" images
 if (/^(\s+key-string \d?)/ && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed>\n"); next;
 }
 if (/^( l2tp tunnel \S+ password)/ && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed>\n"); next;
 }
 # i am told these are plain-text on the PIX
 if (/^(vpdn username \S+ password)/ && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed>\n"); next;
 }
 if (/^( cable shared-secret ) / && $filter_pwds >= 1) {
 ProcessHistory("","","","!$1 <removed>\n");
 next;
 }
 /fair-queue individual-limit/ && next;
 # sort ip explicit-paths.
 if (/^ip explicit-path name (\S+)/) {
 my($key) = $1;
 my($expath) = $_;
 while (<INPUT>) {
 tr/\015//d;
 last if (/^$prompt/);
 last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/);
 if (/^ip explicit-path name (\S+)/) {
 ProcessHistory("EXPATH","keysort","$key","$expath");
 $key = $1;
 $expath = $_;
 } else {
 $expath .= $_;
 }
 }
 ProcessHistory("EXPATH","keysort","$key","$expath");
 }
 # sort route-maps
 if (/^route-map (\S+)/) {
 my($key) = $1;
 my($routemap) = $_;
 while (<INPUT>) {
 tr/\015//d;
 last if (/^$prompt/ || ! /^(route-map |[ !])/);
 if (/^route-map (\S+)/) {
 ProcessHistory("ROUTEMAP","keysort","$key","$routemap");
 $key = $1;
 $routemap = $_;
 } else {
 $routemap .= $_;
 }
 }
 ProcessHistory("ROUTEMAP","keysort","$key","$routemap");
 }

 # filter out any RCS/CVS tags to avoid confusing local CVS storage
 s/\$(Revision|Id):/ $1:/;
 # order access-lists
 /^ip access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ &&
 ProcessHistory("ACL $1 $2","ipsort","$3","$_") && next;
 # order extended access-lists
 /^ip access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ &&
 ProcessHistory("EACL $1 $2","ipsort","$3","$_") && next;
 /^ip access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ &&
 ProcessHistory("EACL $1 $2","ipsort","$3","$_") && next;
 /^ip access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ &&
 ProcessHistory("EACL $1 $2","ipsort","0.0.0.0","$_") && next;
 /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ &&
 ProcessHistory("PACL $1 $3","ipsort","$4","ip prefix-list $1 $3 $4$5\n")
 && next;
 # order logging statements
 /^logging (\d+\.\d+\.\d+\.\d+)/ &&
 ProcessHistory("LOGGING","ipsort","$1","$_") && next;
 # order/prune snmp-server host statements
 # we only prune lines of the form
 # snmp-server host a.b.c.d <community>
 if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) {
 if (defined($ENV{'NOCOMMSTR'})) {
 my($ip) = $1;
 my($line) = "snmp-server host $ip";
 my(@tokens) = split(' ', $');
 my($token);
 while ($token = shift(@tokens)) {
 if ($token eq 'version') {
 $line .= " " . join(' ', ($token, shift(@tokens)));
 } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) {
 $line .= " " . $token;
 } else {
 $line = "!$line " . join(' ', ("<removed>", join(' ', at tokens)));
 last;
 }
 }
 ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n");
 } else {
 ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_");
 }
 next;
 }
 if (/^(snmp-server community) (\S+)/) {
 if (defined($ENV{'NOCOMMSTR'})) {
 ProcessHistory("SNMPSERVERCOMM","keysort","$_","!$1 <removed>$'") && next;
 } else {
 ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next;
 }
 }
 # order alias statements
 /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next;
 # order ntp peers/servers
 if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) {
 $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5);
 ProcessHistory("NTP","keysort",$sortkey,"$_");
 next;
 }
 # order ip host statements
 /^ip host (\S+) / &&
 ProcessHistory("IPHOST","keysort","$1","$_") && next;
 # order ip nat source static statements
 /^ip nat (\S+) source static (\S+)/ &&
 ProcessHistory("IP NAT $1","ipsort","$2","$_") && next;
 # order atm map-list statements
 /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ &&
 ProcessHistory("ATM map-list","ipsort","$1","$_") && next;
 # order ip rcmd lines
 /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && next;

 # catch anything that wasnt matched above.
 ProcessHistory("","","","$_");
 # end of config. the ": " game is for the PIX
 if (/^end$/) {
 $found_end = 1;
 return(1);
 }
 }
 $found_end = 1; # no config end marker, just hard set this.
 #Force clean run acceptance
 #$clean_run = 1;
 ProcessHistory("","","","end\n");
 return(0);
}

# dummy function
sub DoNothing {print STDOUT;}

# Main
%commands=(
 'show config' => "WriteTerm",
);
# keys() doesnt return things in the order entered and the order of the
# cmds is important (show version first and write term last). pita
@commands=(
 "show config",
);
$cisco_cmds=join(";",@commands);
$cmds_regexp=join("|",@commands);

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 clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug);
 print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log);
 if (defined($ENV{NOPIPE})) {
 system "clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n";
 open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
 } else {
 open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "clogin failed for $host: $!\n";
 }
}

# 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: Netonix\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;
 if (/[>#]\s?exit$/) {
 $clean_run=1;
 last;
 }
 if (/^Error:/) {
 print STDOUT ("$host clogin error: $_");
 print STDERR ("$host clogin error: $_") if ($debug);
 $clean_run=0;
 last;
 }
 while (/#\s*($cmds_regexp)\s*$/) {
 $cmd = $1;
 if (!defined($prompt)) {
 $prompt = ($_ =~ /^([^#]+#)/)[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}};
 delete($commands{$cmd});
 if ($rval == -1) {
 $clean_run = 0;
 last TOP;
 }
 }
 # Force clean run
 $clean_run=1;
}
print STDOUT "Done $logincmd: $_\n" if ($log);
# Flush History
ProcessHistory("","","","");
# Cleanup
close(INPUT);
close(OUTPUT);

if (defined($ENV{NOPIPE})) {
 unlink("$host.raw") if (! $debug);
}

# check for completeness
if (scalar(%commands) || !$clean_run || !$found_end) {
 if (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);
 }
print STDERR "clean $clean_run end $found_end\n";
 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("/usr/bin/tail -1 $host.new");
 }
 unlink "$host.new" if (! $debug);
}

 

User avatar
mnitech
Member
 
Posts: 21
Joined: Wed Oct 21, 2015 1:21 pm
Location: Morgan Hill, CA
Has thanked: 0 time
Been thanked: 0 time

Re: Backup/Restore from RANCID

Sat Jan 30, 2016 12:37 pm

I was just looking for something that would provide some config management rather than a backup. Your script might be a good starting place

User avatar
SyncKev
Member
 
Posts: 6
Joined: Wed Dec 09, 2015 3:24 pm
Location: Bremen, GA
Has thanked: 0 time
Been thanked: 1 time

Re: Backup/Restore from RANCID

Sat Jan 30, 2016 2:37 pm

mnitech wrote:I was just looking for something that would provide some config management rather than a backup. Your script might be a good starting place


It does work for that purpose; I hope it is helpful.

User avatar
jbaird
Member
 
Posts: 43
Joined: Fri Oct 09, 2015 3:47 pm
Location: Danville, KY
Has thanked: 0 time
Been thanked: 2 times

Re: Backup/Restore from RANCID

Fri Feb 05, 2016 11:35 am

Thanks for the script. I hope at some point we'll be able to do full restores from this.

belsamber
Member
 
Posts: 1
Joined: Thu Nov 05, 2015 10:32 pm
Has thanked: 0 time
Been thanked: 0 time

Re: Backup/Restore from RANCID

Tue Jun 14, 2016 1:19 am

Sorry to resurrect an old thread but this seemed like an appropriate place to post.

Based on Eric's comment earlier in the thread I put together the attached RANCID scripts.

As written they log into the switch, run the backup command, SCP the file to your host, untar, then pass the config.json file up the line so it gets committed to CVS.

It keeps a single copy of the tar file for each switch for restore purposes (by default this is in the /tmp/ directory)

There's very little error checking and I make no claims about code quality - it's just something I hacked together this morning to solve an immediate problem. Hopefully it'll be helpful to someone else as well :smile:
Attachments
wisprancid.txt
(1.34 KiB) Downloaded 432 times
wisplogin.txt
(6.82 KiB) Downloaded 444 times

Previous
Return to Hardware and software issues

Who is online

Users browsing this forum: No registered users and 12 guests