From 0938cd1651dadfb9a0a19f7c9cd0c32950ea767b Mon Sep 17 00:00:00 2001 From: Christian Ramseyer Date: Mon, 27 Jan 2020 21:03:23 +0100 Subject: [PATCH] New version of the IOSXR module using Expect * The previous module only worked for 32-bit IOSXR, and already there some fiddling with the STDIN of the process was required when being run from netdisco-backend * In 64-bit IOSXR, the STDIN workaround stopped working and created a stuck ssh process on every arpnip * This new version uses Expect instead of plain SSH, so a proper pty is provided under any circumstances * Successfully tested on recent 32- and 64-bit variants --- .../Netdisco/SSHCollector/Platform/IOSXR.pm | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/lib/App/Netdisco/SSHCollector/Platform/IOSXR.pm b/lib/App/Netdisco/SSHCollector/Platform/IOSXR.pm index 70ef7eb3..de1e784c 100644 --- a/lib/App/Netdisco/SSHCollector/Platform/IOSXR.pm +++ b/lib/App/Netdisco/SSHCollector/Platform/IOSXR.pm @@ -6,7 +6,10 @@ App::Netdisco::SSHCollector::Platform::IOSXR =head1 DESCRIPTION -Collect ARP entries from Cisco IOSXR devices. +Collect ARP entries from IOSXR routers using Expect + +This is a reworked version of the IOSXR module, and it is suitable +for both 32- and 64-bit IOSXR. =cut @@ -14,6 +17,7 @@ use strict; use warnings; use Dancer ':script'; +use Expect; use Moo; =head1 PUBLIC METHODS @@ -34,20 +38,31 @@ Returns a list of hashrefs in the format C<{ mac =E MACADDR, ip =E IPADD sub arpnip { my ($self, $hostlabel, $ssh, $args) = @_; - # IOSXR show commands seem to depend on an available STDIN - unless (-t STDIN){ - open STDIN, "<", "/dev/zero" or warn "Failed to fake stdin: $!"; - } - debug "$hostlabel $$ arpnip()"; - my @data = $ssh->capture("show arp vrf all"); - chomp @data; - my @arpentries; + my ($pty, $pid) = $ssh->open2pty; + unless ($pty) { + warn "unable to run remote command [$hostlabel] " . $ssh->error; + return (); + } + my $expect = Expect->init($pty); + + my ($pos, $error, $match, $before, $after); + my $prompt = qr/# +$/; + my $timeout = 10; + + ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt); + + $expect->send("terminal length 0\n"); + ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt); + + $expect->send("show arp vrf all\n"); + ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt); + + my @arpentries = (); + my @data = split(m/\n/, $before); - # 0.0.0.0 00:00:00 0000.0000.0000 Dynamic ARPA GigabitEthernet0/0/0/0 foreach (@data) { - my ($ip, $age, $mac, $state, $t, $iface) = split(/\s+/); if ($ip =~ m/(\d{1,3}\.){3}\d{1,3}/ @@ -56,6 +71,10 @@ sub arpnip { } } + + $expect->send("exit\n"); + $expect->soft_close(); + return @arpentries; }