CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Advanced:
Net::Telnet slow

 



kp2a
New User

May 13, 2009, 9:38 PM

Post #1 of 4 (4455 views)
Net::Telnet slow Can't Post

I have to monitor and manage a network with over 4,000 nodes.
Most monitoring is via SNMP.
However
Many boxes require command line access for some functions.
I have tried perl/Net::Telnet, perl/ssh, expect/telnet, expect/ssh
all seem to perform the same - too slow!

Manual telnet or ssh is very fast - but manual - I must automate!

Scripted telnet or ssh appears to have to timeout after a "send" before the expected reply arrives. Several cycles of send/expect can eat up a lot of time because the timeout has to be set to the worse case.

I would expect (and Wireshark shows) than a reply normally occurs in milliseconds within our network.

What am I missing?

Here is my test code - and below than the log file with microsecond timing.
Log in and getting one piece of information takes 44 seconds.
(Please this is just a debug/test NOT my objective = much more complicated- I can get sysName via SNMP in few milliseconds.)


Code
use strict; 
use Net::Telnet;
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
my $timeout = 10;
my ($sec,$usec) = gettimeofday ;
my $start = $sec + ($usec/1000000.0);
sub usec {
($sec,$usec) = gettimeofday ;
$sec + ($usec/1000000.0) - $start;
}
printf "%10.6f start\n", usec;
$| = 1;

my $ip = shift;
printf "%10.6f call Telnet for $ip expect connected\n",usec;
my $t = new Net::Telnet(
Host=>$ip,
Timeout=>$timeout,
Prompt=>'/ > /',
Errmode=>'return'
);
if($t) {
printf "%10.6f telnet connected - expect Login:\n",usec;
} else {
printf "%10.6f error: telnet connect failed\n",usec;
exit;
}

unlink 'telnet.log';
$t->input_log('telnet.log');

while( !$t->eof ) {
my $line = $t->getline(Timeout => $timeout, Errmode => 'return');
last unless $line;
$line =~ s/\r//g;
chomp $line;
printf "%10.6f line <%s>\n",usec,$line;
last if $line =~ /Login:/i;
}

printf "%10.6f now send admin - expect Password:\n",usec;

$t->print('admin');

while( my $line = $t->getline(Timeout => $timeout, Errmode => 'return') ) {
last unless $line;
$line =~ s/\r//g;
chomp $line;
printf "%10.6f line <%s>\n",usec,$line;
last if $line =~ /Password:/i;
}
printf "%10.6f now send password - expect prompt ' > '\n",usec;
$t->print('*********');


while( my $line = $t->getline(Timeout => $timeout, Errmode => 'return') ) {
last unless $line;
$line =~ s/\r//g;
chomp $line;
printf "%10.6f line <%s>\n",usec,$line;
last if $line =~ / > /;
}

printf "%10.6f send command - expect echo, reply and new prompt\n",usec;
$t->print("/system identity print");

my $echo = 0;
while( my $line = $t->getline(Timeout => $timeout, Errmode => 'return') ) {
last unless $line;
$line =~ s/\r//g;
chomp $line;
printf "%10.6f line <%s>\n",usec,$line;
if( $line =~ /print>/ ) {
$echo++;
printf "%10.6f command echo\n",usec;
next;
}
if( $line =~ / > / && $echo ) {
printf "%10.6f prompt for next command, if any\n",usec;
last;
}
}
$t->close;
printf "%10.6f close\n",usec;
exit;


log file output


Code
  
0.000000 start
0.000000 call Telnet for 10.100.72.223 expect connected
0.011000 telnet connected - expect Login:
0.076000 line <>
0.076000 line <MikroTik v3.20>
11.080933 now send admin - expect Password:
11.093933 line <Login: admin>
22.101867 now send password - expect prompt ' > '
22.118866 line <Password: >
22.153866 line <>
22.153866 line <>
22.154866 line <>
22.154866 line <>
22.154866 line <>
22.154866 line <>
22.166866 line <>
22.167866 line <>
22.167866 line < MMM MMM KKK TTTTTTTTTTT KKK>
22.167866 line < MMMM MMMM KKK TTTTTTTTTTT KKK>
22.167866 line < MMM MMMM MMM III KKK KKK RRRRRR OOOOOO TTT III KKK KKK>
22.167866 line < MMM MM MMM III KKKKK RRR RRR OOO OOO TTT III KKKKK>
22.168866 line < MMM MMM III KKK KKK RRRRRR OOO OOO TTT III KKK KKK>
22.168866 line < MMM MMM III KKK KKK RRR RRR OOOOOO TTT III KKK KKK>
22.168866 line <>
22.168866 line < MikroTik RouterOS 3.20 (c) 1999-2009 http://www.mikrotik.com/>
22.168866 line <>
33.254799 send command - expect echo, reply and new prompt
33.267799 line < <min@Sandey] > <min@Sandey] > /system identity print<min@Sandey Wilton Johnbaptiste 23614] > /system identity print>
^[[?62;9;c^[[24;20R
33.359798 line < name: "Sandey">
44.367732 close


The characters "^[[?62;9;c^[[24;20R" in the reply are unexpected. They appear to be terminal commands? or terminal negotiation? could be a clue that telnet negotiations are not properly hangled?

Password and name has been edited, of course.


1arryb
User

May 18, 2009, 10:38 AM

Post #2 of 4 (4375 views)
Re: [kp2a] Net::Telnet slow [In reply to] Can't Post

Hi kp2a,

I rewrote your program to use Net::SSH::Perl. It runs alot faster than your Telnet script. As you can see, most of the execution time is taken up instantiating the Net::SSH::Perl object itself.

Update:

My first test (on Windows/Cygwin) took about 15 second to login. Net::Perl::SSH relies on Math::BigInt to handle ssl's crypto calculations. If you see:

Code
Math::BigInt: couldn't load specified math lib(s), fallback to  
Math::BigInt::FastCalc at ...

That means that you don't have os-level math lib support (libgmp) installed and available to Perl. To fix this, you need to install Math::GMP, Math::BigInt::GMP, and supporting libraries.

Update 2:

Getting libgmp installed on cygwin is a little tricky. See this thread for a resolution: http://www.nntp.perl.org/group/perl.perl5.porters/2007/07/msg126961.html. After I installed the gmp stuff, login time dropped dramatically.

Code
#!/usr/bin/perl 

use strict;
use warnings;

use Net::SSH::Perl;
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );

my ($sec,$usec) = gettimeofday ;
my $start = $sec + ($usec/1000000.0);
sub usec {
($sec,$usec) = gettimeofday ;
$sec + ($usec/1000000.0) - $start;
}
printf "%10.6f start\n", usec;
$| = 1;

my ($host, $user, $passwd) = @ARGV;
die "usage: $0 <host> <user> <passwd>" unless ($host and $user and $passwd);


printf "%10.6f call SSH for $user\@$host \n", usec;
my $s = Net::SSH::Perl->new($host);
if($s) {
printf "%10.6f SSH connected\n",usec;
} else {
printf "%10.6f error: SSH connect failed\n",usec;
exit;
}

printf "%10.6f attempt SSH login:\n",usec;

eval {
$s->login($user, $passwd);
};
if ($@) {
printf "%10.6f SSH login failed: %s\n",usec,$@;
exit -1;
} else {
printf "%10.6f SSH login succeeded:\n",usec;
}

my $cmd = "echo \"hello\"";

printf "%10.6f attempt SSH cmd \"%s\":\n",usec,$cmd;

my ($out, $err, $ret) = $s->cmd($cmd);

if ( $ret) {
printf "%10.6f SSH cmd failed. Retcode was %d:\n",usec,$ret;
} else {
printf "%10.6f SSH cmd succeeded:\n",usec;
}
print "Standard output for \"$cmd\":\n";
print $out ? $out : "\n";
print "Standard error for \"$cmd\":\n";
print $err ? $err : "\n";


Running this program against a server on my local net I get:

Code
$ perl perl_ssh.pl myhost myuser mypasswd 
0.000012 start
0.001523 call SSH for collector@sleet
0.196202 SSH connected
0.197735 attempt SSH login:
0.875000 SSH login succeeded:
0.876531 attempt SSH cmd "echo "hello"":
1.050429 SSH cmd succeeded:
Standard output for "echo "hello"":
hello
Standard error for "echo "hello"":


Cheers,

Larry


(This post was edited by 1arryb on May 18, 2009, 11:03 AM)


kp2a
New User

May 18, 2009, 2:30 PM

Post #3 of 4 (4363 views)
Re: [1arryb] Net::Telnet slow [In reply to] Can't Post

wow! Thanks! I will give it a try and report.

I hate mysteries!
I am still puzzled about why I have to wait for the timeout to get a response. Is that how Net::Telnet or "expect" is expected to work? What am I missing?


1arryb
User

May 18, 2009, 5:43 PM

Post #4 of 4 (4354 views)
Re: [kp2a] Net::Telnet slow [In reply to] Can't Post

Hi kp2a,

I played around with this program for awhile. It looks like the Timeout value is applied to every call to the telnet server. I simplified your program a bit and was able to tune the program for better speed. Minimum timeout value is 1, however. If you set it to zero, the program "succeeds" but the remote command is never executed.

What I learned about Net::Telnet:

1. The timeout is adjustable, minimum value is 1.
2. waitfor() is cool.
3. cmd() is NOT cool: I was never able to get either a return code from the remote command OR the output via either of the scalar or list variants.
4. Unless you set Errmode to 'return', waitfor() fails with a bogus 'timeout waiting for regex' error.

All in all, I'd say this module isn't ready for prime time suitable for high volume remote command execution.


Code
#!/usr/bin/perl 

use strict;
use warnings;
use Net::Telnet;
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
my ($sec,$usec) = gettimeofday ;
my $start = $sec + ($usec/1000000.0);
sub usec {
($sec,$usec) = gettimeofday ;
$sec + ($usec/1000000.0) - $start;
}
printf "%10.6f start\n", usec;
$| = 1;

my ($ip, $user, $pass) = @ARGV;
die "usage: $0 <host> <user> <pass>" unless $ip and $user and $pass;
printf "%10.6f call Telnet for $ip expect connected\n",usec;
my $timeout = 1;
my $t = new Net::Telnet(
Host => $ip,
Timeout => $timeout,
Prompt => '/ > /',
Input_log => "input.log",
Errmode => 'return'
);
if($t) {
printf "%10.6f telnet connected - expect Login:\n",usec;
} else {
printf "%10.6f error: telnet connect failed\n",usec;
exit;
}

$t->waitfor('/login:/i');

printf "%10.6f now send $user - expect Password:\n",usec;

$t->print($user);

$t->waitfor('/password:/i');

printf "%10.6f now send password - expect prompt ' > '\n",usec;

$t->print($pass);

$t->waitfor('/ > /');

printf "%10.6f send command - expect echo, reply and new prompt\n",usec;

my @output = ();
eval {
my $ret = $t->cmd(String => "echo hello");
};
if ($@) {
printf "%10.6f command failed, ret=%s\n",usec, $@;
$t->close;
exit -1;
}

printf "%10.6f command suceeded:\n",usec;

my $echo = 0;
while( my $line = $t->getline(Timeout => $timeout, Errmode => 'return') ) {
last unless $line;
$line =~ s/\r//g;
chomp $line;
printf "%10.6f line <%s>\n",usec,$line;
if( $line =~ /print>/ ) {
$echo++;
printf "%10.6f command echo\n",usec;
next;
}
if( $line =~ / > / && $echo ) {
printf "%10.6f prompt for next command, if any\n",usec;
last;
}
}

printf "%10.6f close\n",usec;
$t->close;

Here's the output:

Code
  0.000008 start 
0.000052 call Telnet for myserver expect connected
0.001049 telnet connected - expect Login:
0.006488 now send admin - expect Password:
0.046403 now send password - expect prompt ' > '
2.086405 send command - expect echo, reply and new prompt
4.087419 command suceeded:
4.087634 line < >
4.087709 line <Last login: Mon May 18 17:32:18 from mytesthost>
4.087785 line <[admin@myserver ~]$ echo hello>
4.087868 line <hello>
6.087356 close

Cheers,

Larry


(This post was edited by 1arryb on May 19, 2009, 6:55 AM)

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives