mroe1234 has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to use Net::SSH2::Cisco to connect and download config files from Cisco nexus switches. I am suffering from a timeout somewhere. My best guess is that it can't find the prompt again after I execute the command, but I have no idea why. I've been poking at this seemingly simple script for a week now. Any help would be appreciated.

to execute it I do: echo "172.16.2.11,cisco6001 (10G)" | /usr/local/bin/backup_switches.pl

172.16.2.11 is one of our cisco nexus switches

=========The Code===========
use Net::SSH2::Cisco; use Getopt::EvaP; use Parallel::ForkManager; use Data::Dumper; my $max_processes = 1; my $tftp_config_directory = "switches/conf/"; my $config_directory = "/srv/tftp/"; my $tftp_server = "192.168.0.206"; my $lp="********"; my $user = "cworker"; my @wd; my $nexus = 'cisco(9372|3048|6001|1000v)'; my $pm = new Parallel::ForkManager($max_processes); while (<>) { @wd = split /,/; my $pid = $pm->start and next; &talkto(@wd); $date = scalar localtime; sleep 1; $pm->finish; } $pm->wait_all_children; sub talkto { local($host,$model) = @_; my $error; my $configfile = $tftp_config_directory . $host . "-confg"; my $sok = Net::SSH2::Cisco->new( host => $host, Dump_Log => '/tmp/backup.log', Output_log => '/tmp/output.log', Input_log => '/tmp/input.log', Waitfor_clear => '0', #as a 0 it doesn't prepend Ctr +l-Z to the command. ); $sok->login(Name =>$user, Password =>$lp, ); my @cmdoutput; my $vrf = 'default'; if ($model =~ /$nexus/) { my $output; @cmdoutput = $sok->cmd( String => "copy startup-config tftp://$tftp_server/$con +figfile vrf $vrf", Errmode => "return", ); print Dumper @cmdoutput; if ($sok->errmsg){ ($error) = $sok->errmsg; print "Nexus IP: $host: Command failed reason: $error. Trying ag +ain...\n" ; @cmdoutput = $sok->cmd( String => "copy startup-config tftp://$tftp_server/$c +onfigfile vrf management", Errmode => "return", ); $sok->waitfor ( String => '#', Timeout => '5', Waitfor_clear => '1', ); print "Output: $output\n"; print Dumper @cmdoutput; print "Nexus IP: $host: Command failed reason: $error\n" ; } } else { @cmdoutput = $sok->cmd( String => "copy running-config tftp $tftp_server $configfile", ); if ($sok->errmsg){ ($error) = $sok->errmsg; print "Catalyst IP: $host Command failed reason: $error"; } } $sok->close; }

Replies are listed 'Best First'.
Re: Using Net::SSH2::Cisco
by VinsWorldcom (Prior) on Dec 16, 2015 at 19:33 UTC

    I put together Net::SSH2::Cisco from Net::Telnet, Net::Telnet::Cisco and Net::SSH2. You'll find the same limitations apply, specifically from Net::Telnet::Cisco:

    http://search.cpan.org/~joshua/Net-Telnet-Cisco-1.10/Cisco.pm#Sending_multiple_lines_at_once

    If your command doesn't produce the regular prompt in return, you'll have an issue. When I try this on a 7200-series, I get:

    R1#copy startup-config tftp://192.168.100.254 Address or name of remote host [192.168.100.254]? Destination filename [r1-confg]?

    which will *DEFINITELY* be the cause of an issue since the prompt is not returned without pressing enter a few times. Try adding "\n\n\n" to the end of your cmd() 'String' value.

    I see you're using waitfor() looking for "#", is that your prompt?

    Did you try setting timeout() before issuing your cmd() calls? I see you have a 5 second timeout *after* the command is issued - that won't help. Try timeout(10) *before* issuing cmd().

    Also, reading the POD from Net::Telnet and Net::Telnet::Cisco is highly recommended since I didn't port all the POD into this module and there are helpful examples about how to use those modules from which Net::SSH2::Cisco is based on.

Re: Using Net::SSH2::Cisco
by NetWallah (Canon) on Dec 16, 2015 at 19:03 UTC
    What output are you getting on STDOUT, and the /tmp logs ?

    Since you are running only one thread, debugging is unnecessarily complicated by your use of Parallel::ForkManager. Try to run without that. You can even use the built-in perl debugger!

    Your declaration of "local($host,$model) = @_;" is probably based on a misunderstanding of "local". Please change that to "my".

    Try to add error checking when you create the new Cisco object, and when you do the login.

            "I can cast out either one of your demons, but not both of them." -- the XORcist

      I'm running one thread for the purposes of debugging, this will eventually have to be set to ~8-16. The logic all works and based on my reading of the documentation the reason I'm not getting anything in @cmdoutput is because it can't find the '#'. I have been playing with timeouts for a while. Here are my logs:

      $ cat /tmp/input.log Trying to connect to tftp server...... TFTP put operation failed:No route to host + Trying to connect to tftp server...... TFTP put operation was successful + Copy complete, now saving to disk (please wait)...
      $ cat /tmp/output.log copy startup-config tftp://192.168.0.206/switches/conf/172.16.2.11-con +fg vrf default copy startup-config tftp://192.168.0.206/switches/conf/172.16.2.11-con +fg vrf management

      I added a few '\n' as you can see above with the same result. when I run the commands manually on the switch I get the following(it takes about 1-2seconds to run manually):

      ewfmb_179_cc7_b# copy startup-config tftp://192.168.0.206/switches/con +f/172.16.2.11-confg vrf management Trying to connect to tftp server...... Connection to Server Established. TFTP put operation was successful + Copy complete, now saving to disk (please wait)... ewfmb_179_cc7_b#

      I send the command twice only because some switches use a management vrf and others do not, that is why you see the first output error with 'no route to host'.

Re: Using Net::SSH2::Cisco
by salva (Canon) on Dec 17, 2015 at 18:34 UTC
    Also, ensure you have the latest versions of libssh2 and Net::SSH2 installed as several important bugs were fixed there.

      Good thought. Rather than using the debian packaged versions, I installed the following versions:

      libnet-ssh2-perl 0.56-1 libssh2-1:amd64 1.5.0-2 libssh2-1-dev:amd64 1.5.0-2

      libssh2 I pulled from debian unstable and did an SSB to jessie, libnet-ssh2-perl I pulled from CPAN and made a deb out of it. No change in the behavior.

      I added the following code to play with the timeouts as VinsWorldcom suggested with no change in behavior:

      if ($model =~ /$nexus/) { my $output; $sok->timeout(10); @cmdoutput = $sok->cmd( String => "copy startup-config tftp://$tftp_server/$con +figfile vrf $vrf\n\n\n", Errmode => "return", ); print Dumper @cmdoutput; if ($sok->errmsg){ ($error) = $sok->errmsg; print "Nexus IP: $host: Command failed reason: $error. Trying ag +ain...\n" ; $sok->timeout(10); @cmdoutput = $sok->cmd( String => "copy startup-config tftp://$tftp_server/$c +onfigfile vrf management\n\n\n", Errmode => "return", ); $sok->waitfor ( String => '#', Timeout => '5', Waitfor_clear => '1', ); print Dumper @cmdoutput; print "Nexus IP: $host: Command failed reason: $error\n" ; } }
Re: Using Net::SSH2::Cisco
by VinsWorldcom (Prior) on Dec 22, 2015 at 17:21 UTC

    Follow-on from my post above (Re: Using Net::SSH2::Cisco), I tested something simple against a 7200-series router:

    #!perl use strict; use warnings; use Net::SSH2::Cisco; my $host = Net::SSH2::Cisco->new( host => '10.254.254.1', dump_log => 'out.txt', ); $host->login( name => 'cisco', password => 'cisco', ); my @ret = $host->cmd( "copy running-config tftp://192.168.100.254\n\n\n" ); print @ret; $host->close;

    ... and it works fine (note my TFTPd server is 'tftpd-simple.pl' supplied with the Net::TFTPd module)...

    VinsWorldcom@C:\Users\VinsWorldcom\tmp> test.pl copy running-config tftp://192.168.100.254 Address or name of remote host [192.168.100.254]? Destination filename [r1-confg]? !! 9721 bytes copied in 4.400 secs (2209 bytes/sec)

    I think you need to boil your script down to basics, get something that works, then starting adding the threads and other special stuff. Notice I didn't use waitfor() or change timeout() - I'm just using defaults. Note also that I tested and it works just as well when using Net::Telnet::Cisco (instead of Net::SSH2::Cisco - s/SSH2/Telnet/g) - as it should since Net::SSH2::Cisco is supposed to be a drop and replace SSH solution for the Net::Telnet::Cisco one.