Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology

answers

Converting RANCID to use tmsh commands, and other goodies

Updated 12/7/2011 • Originally posted on 07-Dec-2011 by Colin Stubbs 111

Seriously, there doesn't seem to be any other forum posts about this, which I find odd. I can't be the only person monitoring F5 config changes via RANCID!?!?!

The patch below applies against rancid-2.3.4, and changes f5rancid to using tmsh commands completely. Includes regex statements to remove fan RPM and temperatures from the tmsh show sys hardware output to reduce spurious emails.

It also dumps ZebOS.cfg and lists sockets associated with ZebOS bgpd by looking for TCP/179 sockets with lsof. If you're using ZebOS off an F5 this is absolutely critical IMHO.

--- bin/f5rancid.in.orig        2010-06-22 23:17:29.000000000 +0000
+++ bin/f5rancid.in     2011-12-07 21:05:25.551471472 +0000
@@ -305,6 +305,34 @@
     return(0);
 }

+# This routine parses "tmsh show sys hardware"
+sub ShowHardware {
+    print STDERR "    In ShowHardware: $_" if ($debug);
+
+    while () {
+        tr/\015//d;
+        last if (/^$prompt/);
+        next if (/^(\s*|\s*$cmd\s*)$/);
+        return(1) if /^\s*\^\s*$/;
+        return(1) if /(Invalid input detected|Type help or )/;
+        return(-1) if (/command authorization failed/i);
+
+        /fan speed/i && next;
+        /chassis temperature/i && next;
+        /degC/ && next;
+        s/\d+rpm//ig;
+        s/^\|//;
+        s/^\ \ ([0-9]+)(\ +).*up.*[0-9]/  $1$2up REMOVED/i;
+        s/^\ \ ([0-9]+)(\ +).*Air\ Inlet/  $1$2REMOVED Air Inlet/i;
+        s/^\ \ ([0-9]+)(\ +)[0-9]+\ +[0-9]+/  $1$2REMOVED     REMOVED/;
+        /Type: / && ProcessHistory("COMMENTS","keysort","A0",
+                                   "#Chassis type: $'");
+
+        ProcessHistory("COMMENTS","keysort","B1","#$_") && next;
+    }
+    return(0);
+}
+
 # This routine parses "bigpipe profile list"
 sub ShowProfile {
     print STDERR "    In ShowProfile: $_" if ($debug);
@@ -413,6 +441,84 @@
     return(0);
 }

+# This routine parses "cat /config/ZebOS.conf"
+sub ShowZebOSconf {
+    my($line) = (0);
+    print STDERR "    In ShowZebOSconf: $_" if ($debug);
+
+    while () {
+        tr/\015//d;
+        last if (/^$prompt/);
+        next if (/^(\s*|\s*$cmd\s*)$/);
+        return(1) if /^\s*\^\s*$/;
+        return(1) if /(Invalid input detected|Type help or )/;
+        return(-1) if (/command authorization failed/i);
+
+        if (!$line++) {
+            ProcessHistory("ZEBOSCONF","","","#\n#/config/ZebOS.conf:\n");
+        }
+        ProcessHistory("ZEBOSCONF","","","# $_") && next;
+    }
+    return(0);
+}
+
+# This routine parses "lsof -n -i :179"
+sub ShowZebOSsockets {
+    my($line) = (0);
+    print STDERR "    In ShowZebOSsockets: $_" if ($debug);
+
+    while () {
+        tr/\015//d;
+        last if (/^$prompt/);
+        next if (/^(\s*|\s*$cmd\s*)$/);
+        return(1) if /^\s*\^\s*$/;
+        return(1) if /(Invalid input detected|Type help or )/;
+        return(-1) if (/command authorization failed/i);
+
+        if (!$line++) {
+            ProcessHistory("ZEBOSSOCKETS","","","#\n#lsof -n -i :179:\n");
+        }
+        ProcessHistory("ZEBOSSOCKETS","","","# $_") && next;
+    }
+    return(0);
+}
+
+# This routine processes a "tmsh list"
+sub WriteTermTMSH {
+    my($lines) = 0;
+    print STDERR "    In WriteTerm: $_" if ($debug);
+
+    while () {
+        tr/\015//d;
+        next if (/^\s*$/);
+        # end of config - hopefully.  f5 does not have a reliable end-of-config
+        # tag.
+        if (/^$prompt/) {
+            $found_end++;
+            last;
+        }
+        return(-1) if (/command authorization failed/i);
+
+        $lines++;
+
+        if (/(bind-pw|encrypted-password|user-password-encrypted|passphrase) / && $filter_pwds >= 1) {
+            ProcessHistory("ENABLE","","","# $1 \n");
+            next;
+        }
+
+        # catch anything that wasnt matched above.
+        ProcessHistory("","","","$_");
+    }
+
+    if ($lines < 3) {
+        printf(STDERR "ERROR: $host configuration appears truncated.\n");
+        $found_end = 0;
+        return(-1);
+    }
+
+    return(0);
+}
+
 # This routine processes a "bigpipe list"
 sub WriteTerm {
     my($lines) = 0;
@@ -515,18 +621,31 @@
 sub DoNothing {print STDOUT;}

 # Main
+# bigpipe commands
+#@commandtable = (
+#      {'bigpipe version'              => 'ShowVersion'},
+#      {'bigpipe platform'             => 'ShowPlatform'},
+#      {'cat /config/bigip.license'    => 'ShowLicense'},
+#      {'bigpipe monitor list all'     => 'ShowMonitor'},
+#      {'bigpipe profile list'         => 'ShowProfile'},
+#      {'bigpipe base list'            => 'ShowBaseRun'},
+#      {'bigpipe db show'              => 'ShowDb'},
+#      {'bigpipe route static show'    => 'ShowRouteStatic'},
+#      {'ls --full-time --color=never /config/ssl/ssl.crt' => 'ShowSslCrt'},
+#      {'ls --full-time --color=never /config/ssl/ssl.key' => 'ShowSslKey'},
+#      {'bigpipe list'                 => 'WriteTerm'}
+#);
+# tmsh commands
 @commandtable = (
-       {'bigpipe version'              => 'ShowVersion'},
-       {'bigpipe platform'             => 'ShowPlatform'},
-       {'cat /config/bigip.license'    => 'ShowLicense'},
-       {'bigpipe monitor list all'     => 'ShowMonitor'},
-       {'bigpipe profile list'         => 'ShowProfile'},
-       {'bigpipe base list'            => 'ShowBaseRun'},
-       {'bigpipe db show'              => 'ShowDb'},
-       {'bigpipe route static show'    => 'ShowRouteStatic'},
-       {'ls --full-time --color=never /config/ssl/ssl.crt' => 'ShowSslCrt'},
-       {'ls --full-time --color=never /config/ssl/ssl.key' => 'ShowSslKey'},
-       {'bigpipe list'                 => 'WriteTerm'}
+        {'tmsh show /sys version'                           => 'ShowVersion'},
+        {'tmsh show /sys hardware'                          => 'ShowHardware'},
+        {'tmsh show /sys license'                           => 'ShowLicense'},
+        {'cat /config/ZebOS.conf'                           => 'ShowZebOSconf'},
+        {'lsof -i :179'                                     => 'ShowZebOSsockets'},
+        {'tmsh show /net route static'                      => 'ShowRouteStatic'},
+        {'ls --full-time --color=never /config/ssl/ssl.crt' => 'ShowSslCrt'},
+        {'ls --full-time --color=never /config/ssl/ssl.key' => 'ShowSslKey'},
+        {'tmsh list'                                        => 'WriteTermTMSH'},
 );
 # 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.
1
Rate this Question

Answers to this Question

10 Answers:

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Updated 07-Dec-2011 • Originally posted on 07-Dec-2011 by Colin Stubbs 111
Actually, "tmsh list" should be "tmsh -q list", otherwise it may/may not prompt rancid to enter y/n :-(
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Updated 26-Jan-2012 • Originally posted on 26-Jan-2012 by ingard 234
Have you gotten this to work?

With only running with the first tmsh cmd I get this:
/f5rancid -d 10.0.10.250
executing /var/lib/rancid/test/clogin -t 90 -c"tmsh show /sys version" 10.0.10.250
PROMPT MATCH: \[admin@bigip1:Active\] ~ #
HIT COMMAND:[admin@bigip1:Active] ~ # tmsh show /sys version
In ShowVersion: [admin@bigip1:Active] ~ # tmsh show /sys version
10.0.10.250: End of run not found
10.0.10.250: End of run not found

If I add more of the tmsh cmds I get:
./f5rancid -d 10.0.10.250
executing /var/lib/rancid/test/clogin -t 90 -c"tmsh show /sys version;tmsh show /sys hardware" 10.0.10.250
PROMPT MATCH: \[admin@bigip1:Active\] ~ #
HIT COMMAND:[admin@bigip1:Active] ~ # tmsh show /sys version
In ShowVersion: [admin@bigip1:Active] ~ # tmsh show /sys version
HIT COMMAND:[admin@bigip1:Active] ~ # tmsh show /sys hardware
In ShowHardware: [admin@bigip1:Active] ~ # tmsh show /sys hardware
HIT COMMAND:[admin@bigip1:Active] ~ # tmsh show /sys hardware
10.0.10.250: found unexpected command - "tmsh show /sys hardware"
write(spawn_id=1): broken pipe
while executing
"send_user -- "$expect_out(buffer)""
invoked from within
"expect -nobrace -re+ { exp_continue } -re {^[^
*]*\[admin@big([^#>\r\n]+)?[#>](\([^)\r\n]+\))?} { send_user -- "$expect_out(buffer)"
} -re {..."
invoked from within
"expect {
-re "\b+" { exp_continue }
-re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)"
}
-re "^\[^\n\r]*$reprom..."
(procedure "run_commands" line 39)
invoked from within
"run_commands $prompt $command"
("foreach" body line 174)
invoked from within
"foreach router [lrange $argv $i end] {
set router [string tolower $router]
# attempt at platform switching.
set platform ""
send_user ..."
(file "/var/lib/rancid/test/clogin" line 757)
10.0.10.250: End of run not found
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Updated 13-Mar-2012 • Originally posted on 13-Mar-2012 by Tim Davies 0
ingard and Colin,

First off, can you confirm that your expect is patched as per instructions on http://www.shrubbery.net/rancid/#osystems ? I've seen the 'End of run not found" on my system before I had it patched.

Assuming you do have other scripts working correctly and it is patched, I have the same issue and it seems to be a problem with the output of the tmsh show /sys hardware command. Perhaps the regexp for removing the fan RPM doesn't work for me. Anyway, It's possible to bypass it by commenting it out of the command table in the f5rancid script and move onto the 'next' issue!

The next issue I had was with the tmsh list command as it was prompting me with "Display all 480 items? (y/n) " which caused the script to hang. I changed the command to "tmsh -q list" which removed the promp (must have missed Colin's 2nd comment about that)t. I commented out the ZebOS line too as I don't have it. The lsof command also caused me problems ("found unexpected command - "lsof -i :179"") so I commented it out.

After all this, the closest I came to having it working was with the following command table in f5rancid:

# tmsh commands
  @commandtable = (
        {'tmsh show /sys version'                           => 'ShowVersion'},
#        {'tmsh show /sys hardware'                          => 'ShowHardware'},
        {'tmsh show /sys license'                           => 'ShowLicense'},
#        {'cat /config/ZebOS.conf'                           => 'ShowZebOSconf'},
#        {'lsof -i :179'                                     => 'ShowZebOSsockets'},
        {'tmsh show /net route static'                      => 'ShowRouteStatic'},
        {'ls --full-time --color=never /config/ssl/ssl.crt' => 'ShowSslCrt'},
        {'ls --full-time --color=never /config/ssl/ssl.key' => 'ShowSslKey'},
        {'tmsh -q list'                                        => 'WriteTermTMSH'},
);


Which gives me the following output (PS - run "export NOPIPE=YES" to have rancid output a .raw and .new file showing its progress/output) :

[rancid@hostname bin]$ export NOPIPE=YES
[rancid@hostname bin]$ ./f5rancid -d bigip01.XXX
executing clogin -t 90 -c"tmsh show /sys version;tmsh show /sys license;tmsh show /net route static; \
ls --full-time --color=never /config/ssl/ssl.crt;ls --full-time --color=never /config/ssl/ssl.key;tmsh -q list" bigip01.XXX PROMPT MATCH: \[root@bigip01:Active\] config # HIT COMMAND:[root@bigip01:Active] config # tmsh show /sys version In ShowVersion: [root@bigip01:Active] config # tmsh show /sys version HIT COMMAND:[root@bigip01:Active] config # tmsh show /sys license In ShowLicense: [root@bigip01:Active] config # tmsh show /sys license HIT COMMAND:[root@bigip01:Active] config # tmsh show /net route static In ShowRouteStatic: [root@bigip01:Active] config # tmsh show /net route static HIT COMMAND:[root@bigip01:Active] config # ls --full-time --color=never /config/ssl/ssl.crt In ShowSslCrt: [root@bigip01:Active] config # ls --full-time --color=never /config/ssl/ssl.crt HIT COMMAND:[root@bigip01:Active] config # ls --full-time --color=never /config/ssl/ssl.key In ShowSslKey: [root@bigip01:Active] config # ls --full-time --color=never /config/ssl/ssl.key HIT COMMAND:[root@bigip01:Active] config # tmsh -q list In WriteTerm: [root@bigip01:Active] config # tmsh -q list ERROR: bigip01.cloud.securekey.local configuration appears truncated. bigip01.cloud.securekey.local: End of run not found bigip01.cloud.securekey.local: End of run not found # -rw-r--r-- 1 root root 1679 2012-03-01 16:08:34.000000000 -0500 dtdi.key [rancid@sk-cld-splunk01 bin]$


Running the clogin command on its own is about as simple as it gets for testing and what we'd need to get working first:

[rancid@hostname bin]$ clogin -t 90 -c"tmsh -q list" bigip01.XXX
bigip01.XXX
spawn ssh -c 3des -x -l root bigip01.XXX
Password: 
Last login: Tue Mar 13 10:40:44 2012 from 
[root@bigip01:Active] config # 
[root@bigip01:Active] config # terminal length 0
-bash: terminal: command not found
[root@bigip01:Active] config # terminal width 132
-bash: terminal: command not found
[root@bigip01:Active] config #  tmsh -q list

wom endpoint-discovery { }
wom server-discovery { }
[root@bigip01:Active] config #exit
logout

Connection to bigip01.XXX closed.
bad spawn_id (process died earlier?)
    while executing
"expect -nobrace -re {^[^
 *]*\[root@bigi([^#>\r\n]+)?[#>](\([^)\r\n]+\))?} {
                                                  # the Cisco CE and Jnx ERX
                                                  # return to non-enabled mode
..."
    invoked from within
"expect {
        -re "^\[^\n\r *]*$reprompt"             {
                                                  # the Cisco CE and Jnx ERX
                                                  # return to non-enabled mode
                                                  # on exit in enabled mode.
                ..."
    (procedure "run_commands" line 65)
    invoked from within
"run_commands $prompt $command"
    ("foreach" body line 186)
    invoked from within
"foreach router [lrange $argv $i end] {
    set router [string tolower $router]
    # attempt at platform switching.
    set platform ""
    send_user ..."
    (file "/usr/local/rancid/bin/clogin" line 740)
[rancid@sk-cld-splunk01 bin]$ 


The issue appears to be that the script issues the 'exit' command after successfully running the command, the F5 logs off and then the expect script hits an error as it's not expecting the connection to have dropped. It seems to be something like it's trying to drop out of enable mode (but of course there's no enable mode on F5s...)

Anyway, this is as far as I've got after a few days of troubleshooting. I'm not good enough with expect and perl to figure out how to fix it (and I've tried randomly hacking a few bits and pieces into the file). Looks to me like either a separate clogin expect script is needed to handle the prompts (e.g. f5login) or clogin needs to be fixed to handle it. I'm hoping this debugging might enable someone to fix this script for the next version of rancid as I'd like to be able to use it!

At this point, I'm looking at other ways to backup the F5, e.g. write my own very simple expect script to create a UCS file on the bigip and copy that into our SVN every day.
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Updated 25-Jul-2012 • Originally posted on 25-Jul-2012 by Sartuche 0
Here is my tmsh file for rancid. I just created another file called f5tmshrancid in the Rancid /bin location. I then added an additional array value to the rancid-fe file called "'f5tmsh' => 'f5tmshrancid'," and put it below the f5 value. Now I can either use bigpipe or tmsh just depends on the code version on the f5 and I have to make sure in the router.db file is pointed to either f5 or f5tmsh. Hope this helps anyone since I was having problems and can't seem to find a good solution other than this.


#! /usr/bin/perl ## ## $Id: f5tmsh 2279 2011-01-31 22:41:00Z heas $ ## ## rancid 2.3.8 ## Copyright (c) 1997-2008 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. # # This version of rancid tries to deal with F5 BigIPs using TMSH. # # RANCID - Really Awesome New Cisco confIg Differ # # usage: rancid [-dV] [-l] [-f filename | hostname] # use Getopt::Std; getopts('dflV'); if ($opt_V) { print "rancid 2.3.8\n"; exit(0); } $log = $opt_l; $debug = $opt_d; $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; $timeo = 90; # clogin timeout in seconds # force a terminal type so as not to confuse the POS $ENV{'TERM'} = "vt100"; 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,@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 routine parses "cat /config/bigip.license" sub ShowLicense { my($line) = (0); print STDERR " In ShowLicense: $_" if ($debug); ProcessHistory("","","","############# START OF SHOW LICENSE #############\n"); while () { tr/\015//d; # v9 software license does not have CR at EOF s/^#-+($prompt.*)/$1/; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /^\s*\^\s*$/; return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/command authorization failed/i); if (!$line++) { ProcessHistory("LICENSE","","","#\n#/config/bigip.license:\n"); } ProcessHistory("LICENSE","","","# $_") && next; } ProcessHistory("","","","############# END OF SHOW LICENSE #############\n"); return(0); } # This routine parses "bigpipe platform" sub ShowPlatform { print STDERR " In ShowPlatform: $_" if ($debug); ProcessHistory("","","","############# START OF SHOW HARDWARE #############\n"); while () { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /^\s*\^\s*$/; return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/command authorization failed/i); /fan speed/i && next; /chassis temperature/i && next; /degC/ && next; s/\d+rpm//ig; s/^\|//; /Type: / && ProcessHistory("COMMENTS","keysort","A0", "#Chassis type: $'"); ProcessHistory("COMMENTS","keysort","B1","#$_") && next; } ProcessHistory("","","","############# END OF SHOW HARDWARE #############\n"); return(0); } # This routine parses "ls --full-time --color=never /config/ssl/ssl.key" sub ShowSslKey { print STDERR " In ShowSslKey: $_" if ($debug); ProcessHistory("","","","############# START OF SHOW SSL KEYS #############\n"); while () { tr/\015//d; # v9 software license does not have CR at EOF s/^#-+($prompt.*)/$1/; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /^\s*\^\s*$/; return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/command authorization failed/i); ProcessHistory("SSLKEY","","","# $_") && next; } ProcessHistory("","","","############# END OF SHOW SSL KEYS #############\n"); return(0); } # This routine parses "ls --full-time --color=never /config/ssl/ssl.crt" sub ShowSslCrt { print STDERR " In ShowSslCrt: $_" if ($debug); ProcessHistory("","","","############# START OF SHOW SSL CERTS #############\n"); while () { tr/\015//d; # v9 software license does not have CR at EOF s/^#-+($prompt.*)/$1/; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /^\s*\^\s*$/; return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/command authorization failed/i); ProcessHistory("SSLCRT","","","# $_") && next; } ProcessHistory("","","","############# END OF SHOW SSL CERTS #############\n"); return(0); } # This routine parses "bigpipe route static show" sub ShowRouteStatic { print STDERR " In ShowRouteStatic: $_" if ($debug); ProcessHistory("","","","############# START OF SHOW STATICS #############\n"); while () { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(1) if /^\s*\^\s*$/; return(1) if /(Invalid input detected|Type help or )/; return(-1) if (/command authorization failed/i); ProcessHistory("ROUTE","",""," $_") && next; } ProcessHistory("","","","############# END OF SHOW STATICS #############\n"); return(0); } # This routine parses "tmsh show /sys version" sub ShowVersion { print STDERR " In ShowVersion: $_" if ($debug); ProcessHistory("","","","############# START OF SHOW VERSION #############\n"); while () { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); return(-1) if (/command authorization failed/i); /^kernel:/i && ($_ = ) && ProcessHistory("COMMENTS","keysort","A3","#Image: Kernel: $_") && next; if (/^package:/i) { my($line); while ($_ = ) { tr/\015//d; last if (/:/); last if (/^$prompt/); chomp; $line .= " $_"; } ProcessHistory("COMMENTS","keysort","A2", "#Image: Package:$line\n"); } if (/:/) { ProcessHistory("COMMENTS","keysort","C1","#$_"); } else { ProcessHistory("COMMENTS","keysort","C1","#\t$_"); } } ProcessHistory("","","","############# END OF SHOW VERSION #############\n"); return(0); } # This routine processes a "tmsh -q list" # Want to run both just encase something is missed sub TMSHList { my($lines) = 0; print STDERR " In TMSHList: $_" if ($debug); ProcessHistory("","","","############# START OF TMSH LIST OF CONFIG #############\n"); while () { tr/\015//d; next if (/^\s*$/); # end of config - hopefully. f5 does not have a reliable end-of-config # tag. if (/^$prompt/) { $found_end++; last; } return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX s/^<-+ More -+>\s*//; /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked # filter out any RCS/CVS tags to avoid confusing local CVS storage s/\$(Revision|Id):/ $1:/; $lines++; if (/^(enable )?(password|passwd) / && $filter_pwds >= 1) { ProcessHistory("ENABLE","","","! $1$2 \n"); next; } if (/^(enable secret) / && $filter_pwds >= 2) { ProcessHistory("ENABLE","","","# $1 \n"); next; } if (/^username (\S+)(\s.*)? secret /) { if ($filter_pwds >= 2) { ProcessHistory("USER","keysort","$1","# username $1$2 secret \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 \n"); } elsif ($filter_pwds == 1 && $4 ne "5"){ ProcessHistory("USER","keysort","$1","# username $1$2 password \n"); } else { ProcessHistory("USER","keysort","$1","$_"); } next; } if (/^(\s*)password / && $filter_pwds >= 1) { ProcessHistory("LINE-PASS","","","# $1password \n"); next; } if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { ProcessHistory("","","","# neighbor $1 password \n"); next; } # order logging statements /^logging (\d+\.\d+\.\d+\.\d+)/ && ProcessHistory("LOGGING","ipsort","$1","$_") && next; # order/prune tacacs/radius server statements if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) { ProcessHistory("","","","# $1 key \n"); next; } # order clns host statements /^clns host \S+ (\S+)/ && ProcessHistory("CLNS","keysort","$1","$_") && next; # order alias statements /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next; # delete ntp auth password - this md5 is a reversable too if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) { ProcessHistory("","","","# $1 \n"); 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 line statements /^ip host line(\d+)/ && ProcessHistory("IPHOST","numsort","$1","$_") && next; # order ip nat source static statements /^ip nat (\S+) source static (\S+)/ && ProcessHistory("IP NAT $1","ipsort","$2","$_") && next; # catch anything that wasnt matched above. ProcessHistory("","","","$_"); } if ($lines < 3) { printf(STDERR "ERROR: $host configuration appears truncated.\n"); $found_end = 0; return(-1); } ProcessHistory("","","","############# END OF TMSH LIST OF CONFIG #############\n"); return(0); } # This routine processes a "cat /config/bigip_user.conf /config/bigip_base.conf /config/bigip.conf" sub ShowConfs { my($lines) = 0; print STDERR " In ShowConfs: $_" if ($debug); ProcessHistory("","","","############# START OF CONF FILES #############\n"); while () { tr/\015//d; next if (/^\s*$/); # end of config - hopefully. f5 does not have a reliable end-of-config # tag. if (/^$prompt/) { $found_end++; last; } return(-1) if (/command authorization failed/i); # the pager can not be disabled per-session on the PIX s/^<-+ More -+>\s*//; /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked # filter out any RCS/CVS tags to avoid confusing local CVS storage s/\$(Revision|Id):/ $1:/; $lines++; if (/^(enable )?(password|passwd) / && $filter_pwds >= 1) { ProcessHistory("ENABLE","","","! $1$2 \n"); next; } if (/^(enable secret) / && $filter_pwds >= 2) { ProcessHistory("ENABLE","","","# $1 \n"); next; } if (/^username (\S+)(\s.*)? secret /) { if ($filter_pwds >= 2) { ProcessHistory("USER","keysort","$1","# username $1$2 secret \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 \n"); } elsif ($filter_pwds == 1 && $4 ne "5"){ ProcessHistory("USER","keysort","$1","# username $1$2 password \n"); } else { ProcessHistory("USER","keysort","$1","$_"); } next; } if (/^(\s*)password / && $filter_pwds >= 1) { ProcessHistory("LINE-PASS","","","# $1password \n"); next; } if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { ProcessHistory("","","","# neighbor $1 password \n"); next; } # order logging statements /^logging (\d+\.\d+\.\d+\.\d+)/ && ProcessHistory("LOGGING","ipsort","$1","$_") && next; # order/prune tacacs/radius server statements if (/^(tacacs-server|radius-server) key / && $filter_pwds >= 1) { ProcessHistory("","","","# $1 key \n"); next; } # order clns host statements /^clns host \S+ (\S+)/ && ProcessHistory("CLNS","keysort","$1","$_") && next; # order alias statements /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next; # delete ntp auth password - this md5 is a reversable too if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) { ProcessHistory("","","","# $1 \n"); 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 line statements /^ip host line(\d+)/ && ProcessHistory("IPHOST","numsort","$1","$_") && next; # order ip nat source static statements /^ip nat (\S+) source static (\S+)/ && ProcessHistory("IP NAT $1","ipsort","$2","$_") && next; # catch anything that wasnt matched above. ProcessHistory("","","","$_"); } if ($lines < 3) { printf(STDERR "ERROR: $host configuration appears truncated.\n"); $found_end = 0; return(-1); } ProcessHistory("","","","############# END OF CAT OF CONF FILES #############\n"); return(0); } # dummy function sub DoNothing {print STDOUT;} # Main @commandtable = ( {'tmsh show /sys version' => 'ShowVersion'}, {'tmsh show /sys hardware' => 'ShowPlatform'}, {'cat /config/bigip.license' => 'ShowLicense'}, {'tmsh show /net route static' => 'ShowRouteStatic'}, {'ls --full-time --color=never /config/ssl/ssl.crt' => 'ShowSslCrt'}, {'ls --full-time --color=never /config/ssl/ssl.key' => 'ShowSslKey'}, {'tmsh -q list' => 'TMSHList'}, {'cat /config/bigip_user.conf /config/bigip_base.conf /config/bigip.conf' => 'ShowConfs'} ); # 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); $cisco_cmds=join(";",@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); } } 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}) && $ENV{NOPIPE} =~ /^YES/i) { system "clogin -t $timeo -c \"$cisco_cmds\" $host $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 ) { tr/\015//d; 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; } } if (/\#\s?exit$/) { $clean_run=1; last; } } 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); } # 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); } 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); }
0
Comments on this Answer
Comment made 09-Dec-2014 by annielee 0
hi.. can you share the rancid config ?? i've tried your method, but it failed. 1. created bin/f5tmshrancid (from the git website) 2. append bin/rancid-fe with f5tmsh (below f5) 3. add .cloginrc with f5 login details as per below : ##### F5 v11.2 ##### add user 10.* {admin} add password 10.* {password} add method 10.* {ssh} But logs shows error "exec failed router manufacturer f5tmsh: No such file or directory" Can you assist where i did wrong ??
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Updated 17-Oct-2012 • Originally posted on 17-Oct-2012 by istong 0
Does anyone have this they can repost or send to me? The line feeds are missing when I try to copy and paste it.
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Updated 23-Oct-2012 • Originally posted on 23-Oct-2012 by Mick O'Rourke 0
Istong - just copy it from the rancid git repo https://github.com/dotwaffle/rancid-git/tree/master/bin

I've done this with my rancid 2.3 version, add the environment up the top and it's working well.
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Updated 23-Oct-2012 • Originally posted on 23-Oct-2012 by Mick O'Rourke 0
Has anyone been able to get this working with F5 11.x configuration partitions?
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Updated 22-Jun-2015 • Originally posted on 22-Jun-2015 by Vidar S 5

This is a long shot, but did anyone find a workaround for using the F5 RANCID script with AD/LDAP/RADIUS users? "Advanced Shell" is no longer an option for remote user groups as of a specific BIG-IP version. This means you are stuck with tmsh as long as you are using remote authentication and/or remote user groups.

In short we need the script to be configurable to drop a user to bash by typing "bash" in the tmsh shell. This might be possible to do with RANCID itself outside of the script, but that's beyond my knowledge :-(

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Updated 22-Jun-2015 • Originally posted on 22-Jun-2015 by Stanislas 2416

I dont't know about F5 RANDCID script, but if the need is to allow user to authenticate with remote authentication and execute bash command, create a new user.

As authentication is defined as remote, all users except admin authenticate on remote server. on this user, you can define bash as shell.

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Updated 25-Jun-2015 • Originally posted on 25-Jun-2015 by Vidar S 5

Thank you Stanislas, I didn't even think of that.

That actually solved my problem - although it would be easier to allow bash logins from remote users without local invervention. But this is a nice workaround and got RANCID working for me.

Thank you!

0
;