[rancid] [PATCH 2/2] Multiple fixes/improvements for Extreme XOS

Zenon Mousmoulas zmousm at noc.grnet.gr
Mon Nov 28 13:36:45 UTC 2011


Improve support for Extreme Networks devices running XOS:
- Fix end of config detection, since there is no "# End of configuration file"
  anymore, since XOS 12.2 or maybe earlier (xrancid).
- Handle more forms of syntax error messages (xrancid).
- Also parse "show switch" output to grab chassis type (xrancid).
- ANSI escape sequences seem to be used since XOS 12.3 or maybe earlier
  to draw the pager prompt, skip them if found in order to help with
  pager prompt detection (clogin).
- The pager can be disabled per session since XOS 12.3, try to do that
  in order to avoid struggling with pager prompts and ANSI sequences
  altogether (clogin).
- Eat all space that may be there after username/password prompts (clogin).
- XOS runs a large banner by default after login (which matches prompt
  detection!), however output buffering is traditionally and consistently
  broken on XOS devices, causing mismatches in prompt detection and
  subsequent commands. Therefore we need to wait 1 second to eat all output
  up to the first prompt, for things to work from there on. Unfortunately
  the delay affects all devices, not just XOS.

Signed-off-by: Zenon Mousmoulas <zmousm at noc.grnet.gr>
---

diff -ru rancid-2.3.6/bin/clogin.in rancid-2.3.6-grnet/bin/clogin.in
--- rancid-2.3.6/bin/clogin.in	2011-02-16 01:16:59.000000000 +0200
+++ rancid-2.3.6-grnet/bin/clogin.in	2011-11-26 00:15:17.000000000 +0200
@@ -610,11 +610,9 @@
     global do_saveconfig in_proc platform
     set in_proc 1
 
-    # If the prompt is (enable), then we are on a switch and the
-    # command is "set length 0"; otherwise its "terminal length 0".
-    # skip if its an extreme (since the pager can not be disabled on a
-    # per-vty basis).
     if { [ string compare "extreme" "$platform" ] } {
+        # If the prompt is (enable), then we are on a switch and the
+        # command is "set length 0"; otherwise its "terminal length 0".
 	if [ regexp -- ".*> .*enable" "$prompt" ] {
 	    send "set length 0\r"
 	    # This is ugly, but reduces code duplication, allowing the
@@ -631,7 +629,12 @@
 	    -re "\[\n\r]+"	{ exp_continue }
 	}
     } else {
+	send "disable clipaging\r"
 	set reprompt $prompt
+	expect {
+	    -re $reprompt	{}
+	    -re "\[\n\r]+"	{ exp_continue }
+	}
     }
 
     # this is the only way i see to get rid of more prompts in o/p..grrrrr
@@ -640,11 +643,14 @@
     set commands [split $command \;]
     set num_commands [llength $commands]
     # the pager can not be turned off on the PIX, so we have to look
-    # for the "More" prompt.  the extreme is equally obnoxious, with a
-    # global switch in the config.
+    # for the "More" prompt.
     for {set i 0} {$i < $num_commands} { incr i} {
 	send -- "[subst -nocommands [lindex $commands $i]]\r"
 	expect {
+	    -re "^\x1b(\\\[|\(|\))\[;?0-9]*\[0-9A-Za-z]" { # skip ANSI escape sequences
+							   set seen_ansi 1
+							   exp_continue
+							 }
 	    -re "\b+"				{ exp_continue }
 	    -re "^\[^\n\r *]*$reprompt"		{ send_user -- "$expect_out(buffer)"
 						}
@@ -658,12 +664,14 @@
 	    -re "\[\n\r]+"			{ send_user -- "$expect_out(buffer)"
 						  exp_continue
 						}
-	    -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*"	{
+	    -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*" {
 						  send " "
+						  if { ! $seen_ansi } {
 						  # bloody ^[[2K after " "
-						  expect {
-							-re "^\[^\r\n]*\r" {}
-							}
+						      expect {
+							  -re "^\[^\r\n]*\r" {}
+						      }
+						  }
 						  exp_continue
 						}
 	    -re "^ *--More--\[^\n\r]*"		{
@@ -808,19 +816,19 @@
     # Figure out prompts
     set u_prompt [find userprompt $router]
     if { "$u_prompt" == "" } {
-	set u_prompt "(Username|Login|login|user name|User):"
+	set u_prompt "(Username|Login|login|user name|User): *"
     } else {
 	set u_prompt [join [lindex $u_prompt 0] ""]
     }
     set p_prompt [find passprompt $router]
     if { "$p_prompt" == "" } {
-	set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):"
+	set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+): *"
     } else {
 	set p_prompt [join [lindex $p_prompt 0] ""]
     }
     set e_prompt [find enableprompt $router]
     if { "$e_prompt" == "" } {
-	set e_prompt "\[Pp]assword:"
+	set e_prompt "\[Pp]assword: *"
     } else {
 	set e_prompt [join [lindex $e_prompt 0] ""]
     }
@@ -861,6 +869,18 @@
 	# if login failed or rsh was unsuccessful, move on to the next device
 	continue
     }
+
+    # Get all (output after login) you can eat in 1s
+    # (hopefully up to and including the first prompt).
+    # This is mostly necessary to work around
+    # stoopid extreme output buffering.
+    expect {
+	-timeout 1
+	-re "\[\n\r]+"	{ exp_continue }
+	-re "\[^\n\r]+"	{ exp_continue -continue_timer }
+	timeout		{}
+    }
+
     # Figure out the prompt.
     if { [regexp -- "(#| \\(enable\\))" $prompt_match junk] == 1 } {
 	set enable 0
diff -ru rancid-2.3.6/bin/xrancid.in rancid-2.3.6-grnet/bin/xrancid.in
--- rancid-2.3.6/bin/xrancid.in	2011-02-16 01:16:59.000000000 +0200
+++ rancid-2.3.6-grnet/bin/xrancid.in	2011-11-26 00:15:17.000000000 +0200
@@ -280,6 +280,8 @@
 	/^(boot |next reboot)/i && next;
 	/^(auto |qos mode|sys\S*:|temperature|time)/i && next;
 
+	/^system type\s*:\s*(.+)/i &&
+		ProcessHistory("COMMENTS","keysort","A0","#Chassis type: $1\n") && next;
 	/^power supply: (.*)/i &&
 		ProcessHistory("COMMENTS","keysort","C0","#$1") && next;
 	/^license/i && ProcessHistory("COMMENTS","keysort","D0","#Image: $_")
@@ -300,14 +302,17 @@
     print STDERR "    In WriteTerm: $_" if ($debug);
     my($comment) = 1;	# strip extra comments, esp to preserve chassis type
 
+    $found_end = 0;
     while (<INPUT>) {
 	tr/\015//d;
 	last if(/^$prompt/);
 	next if(/^\s*$/);
 	return(0) if(/^syntax error at token /i);
+	return(0) if(/^%% Invalid input detected at /i);
+	return(0) if(/^%% Ambiguous command:/i);
 	# the pager can not be disabled per-session on the PIX
 	s/^<-+ More -+>\s*//;
-	return(0) if ($found_end);
+	last if ($found_end);
 
 	s/^\s*$/#/;
 	next if (/full detail configuration/i);
@@ -389,12 +394,6 @@
 
 	# catch anything that wasnt match above.
 	ProcessHistory("COMMENTS","keysort","H0","$_");
-	# end of config
-	if (/^# End of configuration file/i) {
-	    printf STDERR "    End WriteTerm: $_" if ($debug);
-	    $found_end = 1;
-	    return(0);
-	}
     }
 
     if ($lines < 3) {
@@ -403,6 +402,7 @@
 	return(-1);
     }
     $found_end = 1;
+    printf STDERR "    End WriteTerm: $_" if ($debug);
 
     return(0);
 }
@@ -487,19 +487,19 @@
 ProcessHistory("COMMENTS","keysort","X0","#\n");
 TOP: while(<INPUT>) {
     tr/\015//d;
-    # note: this match sucks rocks, but currently the extreme bits are
-    # unreliable about echoing the 'exit\n' command.  this match might really
-    # be a bad idea, but instead rely upon WriteTerm's found_end?
-    if (/$prompt\s?(quit|exit|Connection( to \S+)? closed)/ && $found_end) {
-	$clean_run = 1;
-	last;
-    }
     if (/^Error:/) {
 	print STDOUT ("$host clogin error: $_");
 	print STDERR ("$host clogin error: $_") if ($debug);
 	$clean_run = 0;
 	last;
     }
+    # note: this match sucks rocks, but currently the extreme bits are
+    # unreliable about echoing the 'exit\n' command.  this match might really
+    # be a bad idea, but instead rely upon WriteTerm's found_end?
+    if (/($prompt\s?(quit|exit)|Connection( to \S+)? closed)/ && $found_end) {
+	$clean_run = 1;
+	last;
+    }
     while (/$prompt\s*($cmds_regexp)\s*$/) {
 	$cmd = $1;
 	if (!defined($prompt)) {


More information about the Rancid-discuss mailing list