r4057 Huawei VRP 5.70 pseudo-interactive telnet support (fixes multiple problems...
authorAlexey Andriyanov <alan@al-an.info>
Thu, 23 Dec 2010 10:16:11 +0000 (10:16 +0000)
committerAlexey Andriyanov <alan@al-an.info>
Thu, 23 Dec 2010 10:16:11 +0000 (10:16 +0000)
new netcat wrapper written in Perl: gateways/deviceconfig/nc.pl
requires netcat for operating

ChangeLog
gateways/deviceconfig/nc.pl [new file with mode: 0755]
gateways/deviceconfig/vrp55.connector

index 62eb625..e496dcf 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -14,6 +14,7 @@
        update: links to ports added to object search results
        update: custom rearch results provided by users' plugins now supported
        new feature: syncdomain.php now can create child processes to speed up 802.1Q sync
+       update: Huawei VRP 5.70 pseudo-interactive telnet support (fixes multiple problems caused by fast commands post through netcat)
 0.18.7
        bugfix: adjust 802.1Q command generation
        bugfix: fixed telnet session hanging in NX-OS4 connector
diff --git a/gateways/deviceconfig/nc.pl b/gateways/deviceconfig/nc.pl
new file mode 100755 (executable)
index 0000000..2b91efc
--- /dev/null
@@ -0,0 +1,106 @@
+#!/usr/bin/perl -w
+use strict;
+use Getopt::Long qw(:config pass_through);;
+use Fcntl;
+use IPC::Open2;
+my $NC_EXEC = 'nc';
+
+my ($marker, $marker_halt);
+my $wait_for;
+my $help;
+GetOptions ("stopwhen=s" => \$marker,
+                       "haltwhen=s" => \$marker_halt,
+                       "putwhen=s" => \$wait_for,
+                       "help|h" => \$help);
+if ($help) {
+       print <<END;
+Wrapper around nc for non-interactive sessions.
+It can close session when it sees the regexp-matching string in session output.
+It can wait for command prompt to push the next command to remote side.
+It DOES NOT directly link its standard input with nc`s standard input.
+
+Additional options availivle:
+--help, -h           This help message
+--stopwhen=<regexp>  Close nc when this string is seen in the output
+--putwhen=<regexp>   Put next line only if last output line complies to regexp
+
+Original nc options:
+END
+       exec($NC_EXEC);
+       exit;
+}
+
+my $hostname = 'unknown';
+if (@ARGV >= 2) {
+       $hostname = $ARGV[$#ARGV - 1];
+}
+my ($break_re, $prompt_re, $halt_re);
+if ($marker) {
+       $break_re = qr/($marker)/m;
+}
+if ($marker_halt) {
+       $halt_re = qr/($marker_halt)/m;
+}
+if ($wait_for) {
+       $prompt_re = qr/$wait_for/;
+}
+$| = 1;
+
+my @cmds = <STDIN>;
+
+my $log = '';
+local (*Reader, *Writer);
+my $pid = open2(\*Reader, \*Writer, $NC_EXEC, @ARGV) or die "cant start $NC_EXEC: $!\n";
+my $stdin_ended = 0;
+
+my $total_read = 0;
+my $vec = '';
+while () {
+       vec($vec, fileno(Reader), 1) = 1;
+       select($vec, undef, undef, undef);
+
+       my $buff;
+       my $nb = sysread(Reader, $buff, 64 * 1024);
+       $total_read += $nb;
+       print $buff if $nb; # echo to STDOUT
+       if (! $nb) {
+               if (@cmds and $total_read) {
+                       print STDERR "$hostname: connection interrupted by remote side.\n";
+               }
+               last; # exit if nc closed connection
+       }
+
+       $log .= $buff;
+       my $halt_matched = $halt_re && $log =~ $halt_re;
+       if ($halt_matched or $break_re && $log =~ $break_re) {
+               if ($halt_matched) {
+                       chomp $log;
+                       $log =~ s/.*\n//;
+                       $log =~ s/[^ -~]//g;
+                       print STDERR "$hostname: Matched line '$log', connection interrupted.\n";
+                       exit 1;
+               }
+               else {
+                       exit 0;
+               }
+       }
+       $log =~ s/.*\n//s; # keep only last line in log
+
+       if ($prompt_re and $log =~ $prompt_re) { # if interative mode and pending commands
+               if (@cmds) {
+                       print Writer shift @cmds; # push one command
+                       $log = '';
+               }
+               else { # if interactive mode and no more commands, exit
+                       last;
+               }
+       }
+       elsif (! $prompt_re and @cmds) { # if non-interactive mode and pending commands, push them all
+               print Writer @cmds;
+               undef @cmds;
+       }
+}
+close Reader;
+close Writer;
+waitpid( $pid, 0 );
+exit $? >> 8;
index 3b679ab..6fe5bf1 100755 (executable)
@@ -43,6 +43,7 @@ prepare_connect_commands()
 }
 
 MYNAME=`basename $0`
+MYDIR=`dirname $0`
 SESSION=`mktemp /tmp/$MYNAME.XXXXXX`
 [ -f "$SESSION" ] || exit 5
 prepare_connect_commands $ENDPOINT
@@ -71,6 +72,6 @@ deploy)
 esac
 printf 'quit\n' >> "$SESSION"
 rc=0
-nc -w 30 $ENDPOINT 23 < "$SESSION" > "$outfile" || rc=4
+$MYDIR/nc.pl --putwhen='(^Username:$|^Password:$)|^<[^<>]*>$|^\[[^\[\]]*\]$' --stopwhen='^Now saving the current configuration' -w 30 $ENDPOINT 23 < "$SESSION" > "$outfile" || rc=4
 rm -f "$SESSION"
 exit $rc