Nornir is getting empty results

Hi everybody.

I’m using Nornir to send commands on Cisco routers but the problem is when I send different commands I don’t get any results, on the router I’ve configured xml agent tty and xml agent interation of but the result is the same.

Is important to say that I ran the script on a gns3 router and works great but when I use the physical router does not get the expected results. The main difference between both scenarios is the tacacs configuration.

my principal code:


    self.NornirObj = InitNornir(config_file=configPath + "config.yaml",
                                runner=num_workers)

    self.filtered = self.NornirObj.filter(F(layer="bb") & F(hostname="10.10.10.10"))

    print(self.NornirObj.config.runner.options["num_workers"])
    print(self.filtered.inventory.hosts.keys())

def execute_commands(self, task):
            comandos = ["show int des"]
            #alarms = task.run(task=napalm_cli, commands=comandos)
	alarms = task.run(task=napalm_get, getters=["bgp_neighbors"])
            print_result(alarms)


self.filtered.run(task=self.execute_commands)

when I execute the script my results are

root@7f2430077365:/home/PROY_123# python3.8 monitor.py
1 ---------> one runner
dict_keys([‘router-XR-1’]) ---------> one router

--------------------> Empty results
vvvv router-XR-1’: napalm_get ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvv INFO
{‘bgp_neighbors’: {‘global’: {‘peers’: {}, ‘router_id’: ‘’}}}
^^^^ END napalm_get ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If I use napalm_cli and change the command my result is the command string

root@7f2430077365:/home/PROY_123# python3.8 monitor.py
1 ---------> one runner
dict_keys([‘router-XR-1’]) ---------> one router

{‘show int des’: ‘show int des’}
{‘show clock’: ‘show clock’}
{‘show ver’: ‘show ver’}
{‘show ip int brief’: ‘show ip int brief’}

Does any one knows if tacacs can affect the Nornir behavior?
Does any one can give me any advice how resolve this issue?

Cheers.

Hi everybody,

I’d made some testings using nornir 2.4, 2.5 and 3.0 with a router cisco NCS-6000 version 6.4.2 and my founds are:

  • nornir 2.4 works well using a local user and tacacs account, the script get the expected results.

root@6115afc705bc:/home/test2.4# python3.8 Nornir.py
vvvv napalm_cli ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
{ ‘sh ver’: ‘Cisco IOS XR Software, Version 6.4.2\n’
‘Copyright © 2013-2017 by Cisco Systems, Inc.\n’
‘\n’
‘Build Information:\n’
’ Built By : radharan\n’

  • nornir 2.5 and 3.0 can connect to the router using a local and a tacacs account, but the script doesn’t get any

root@c7ab93fd2a20:/home/test2.5# python3.8 Nornir.py
vvvv napalm_cli ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
{‘sh ver’: ‘sh ver’}
^^^^ END napalm_cli ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

root@c7ab93fd2a20:/home/test3.0# python3.8 Nornir.py
vvvv napalm_cli ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
{‘sh ver’: ‘sh ver’}
^^^^ END napalm_cli ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

My code is so simple

nr = InitNornir(config_file = “config.yaml”)

filtered = nr.filter(F(platform=“iosxr”) and F(modelo=“NCS”))

print(filtered.inventory.hosts.keys())

def show_commands(task):

comandos = ["sh ver"]

alarms = task.run(task=napalm_cli, commands=comandos)
print_result(alarms)

filtered.run(task=show_commands)

Does anyone has presented a similar behavior?

This is weird. It is as if the result is just an echo of the command itself. Does it happen on other platforms?

Nope, I tried with ASR9k and the problem isn’t present, my founds point to napalm because I made a script to connect NCS router and the result is an error because it returns a empty list.

from napalm import get_network_driver

driver = get_network_driver(‘iosxr’)
device = driver(‘1.1.1.1’, ‘XXX’, ‘XXX’) ----> NCS router

device.open()
commands = [‘show run’]
res = device.cli(commands)
device.close()
print(res)

root@c7ab93fd2a20:/home/test3.0# python3.8 mynapalm.py
Traceback (most recent call last):
File “mynapalm.py”, line 9, in
res = device.get_facts()
File “/usr/local/lib/python3.8/dist-packages/napalm/iosxr/iosxr.py”, line 169, in get_facts
system_time_tree = facts_rpc_reply.xpath(system_time_xpath)[0]
IndexError: list index out of range

We generated a case with Cisco TAC and they doesn’t found any problem on the NCS router. The error is similar to an old bug (https://github.com/napalm-automation/napalm/issues/532)

root@c7ab93fd2a20:/home/test3.0# pip3 list |egrep “napalm|netmiko|paramiko|nornir|pyiosxr”

napalm 3.2.0
netmiko 3.3.2
nornir 3.0.0
nornir-napalm 0.1.1
nornir-netmiko 0.1.1
nornir-pyez 0.0.9
nornir-utils 0.1.1
paramiko 2.7.2

I have zero experience with Napalm or iosxr, but out of curiosity you could temporarily edit that iosxr.py file with the same fix as the issue 532 and see if that helps.

Change

system_time_tree = facts_rpc_reply.xpath(system_time_xpath)[0]

to

try:
    system_time_tree = facts_rpc_reply.xpath(system_time_xpath)[0]
except IndexError:
    system_time_tree = facts_rpc_reply.xpath(system_time_xpath)

I made the change 2 days ago in the iosxr.py but Nornir and Napalm doesn’t work

  • This is the original code

    facts_rpc_request = "<Get><Operational><SystemTime/><PlatformInventory/>\
    </Operational></Get>"
    facts_rpc_reply = ETREE.fromstring(self.device.make_rpc_call(facts_rpc_request))
    system_time_xpath = ".//SystemTime/Uptime"
    platform_attr_xpath = ".//RackTable/Rack/Attributes/BasicInfo"
    system_time_tree = facts_rpc_reply.xpath(system_time_xpath)[0]
    try:
        platform_attr_tree = facts_rpc_reply.xpath(platform_attr_xpath)[0]
    except IndexError:
        platform_attr_tree = facts_rpc_reply.xpath(platform_attr_xpath)

I changed it


    facts_rpc_request = "<Get><Operational><SystemTime/><PlatformInventory/>\
    </Operational></Get>"
    facts_rpc_reply = ETREE.fromstring(self.device.make_rpc_call(facts_rpc_request))
    system_time_xpath = ".//SystemTime/Uptime"
    platform_attr_xpath = ".//RackTable/Rack/Attributes/BasicInfo"
    #system_time_tree = facts_rpc_reply.xpath(system_time_xpath)[0]   ------>comment
    try:
        system_time_tree = facts_rpc_reply.xpath(system_time_xpath)[0] -----> add
        platform_attr_tree = facts_rpc_reply.xpath(platform_attr_xpath)[0]
    except IndexError:
        platform_attr_tree = facts_rpc_reply.xpath(platform_attr_xpath)
        system_time_tree = facts_rpc_reply.xpath(system_time_xpath)  ----> add

Napalm output with sh platform command

root@c7ab93fd2a20:/home/test3.0# python3.8 mynapalm.py
{‘show platform’: ‘show platform’}

Nornir output with sh platform command

root@c7ab93fd2a20:/home/test3.0# python3.8 Nornir.py
dict_keys([‘EAS-XR’])
vvvv EAS-XR: napalm_cli ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
{‘sh platform’: ‘sh platform’}
^^^^ END napalm_cli ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

napalm debug output.

I think that pyiosxr use some data about get_facts but as these data are empty only print the same string like the command, because I can see in the debug ouput the show platform has data .

root@c7ab93fd2a20:/home/test3.0# napalm --debug --user XXXX --password XXX --vendor iosxr “1.1.1.1” call cli --method-kwargs “commands=[‘show platform’]”

2020-12-16 17:41:57,040 - napalm - DEBUG - Starting napalm’s debugging tool
2020-12-16 17:41:57,040 - napalm - DEBUG - Gathering napalm packages
2020-12-16 17:41:57,040 - napalm - DEBUG - napalm==3.2.0
2020-12-16 17:41:57,040 - napalm - DEBUG - get_network_driver - Calling with args: (‘iosxr’,), {}
2020-12-16 17:41:57,041 - napalm - DEBUG - get_network_driver - Successful
2020-12-16 17:41:57,046 - napalm - DEBUG - init - Calling with args: (<class ‘napalm.iosxr.iosxr.IOSXRDriver’>, ‘1.1.1.1’, ‘XXX’), {‘password’: ‘*******’, ‘timeout’: 60, ‘optional_args’: {}}
2020-12-16 17:41:57,047 - napalm - DEBUG - init - Successful
2020-12-16 17:41:57,047 - napalm - DEBUG - pre_connection_tests - Calling with args: (<napalm.iosxr.iosxr.IOSXRDriver object at 0x7f2115b556a0>,), {}
2020-12-16 17:41:57,047 - napalm - DEBUG - open - Calling with args: (<napalm.iosxr.iosxr.IOSXRDriver object at 0x7f2115b556a0>,), {}
2020-12-16 17:41:59,980 - napalm - DEBUG - open - Successful
2020-12-16 17:41:59,981 - napalm - DEBUG - connection_tests - Calling with args: (<napalm.iosxr.iosxr.IOSXRDriver object at 0x7f2115b556a0>,), {}
2020-12-16 17:41:59,981 - napalm - DEBUG - get_facts - Calling with args: (<napalm.iosxr.iosxr.IOSXRDriver object at 0x7f2115b556a0>,), {}
2020-12-16 17:42:00,175 - napalm.pyIOSXR.iosxr - DEBUG - <Element Request at 0x7f21162e8a40>
2020-12-16 17:42:00,177 - napalm.base.helpers - ERROR - ‘list’ object has no attribute ‘xpath’
2020-12-16 17:42:00,177 - napalm.base.helpers - ERROR - ‘list’ object has no attribute ‘xpath’
2020-12-16 17:42:00,177 - napalm.base.helpers - ERROR - ‘list’ object has no attribute ‘xpath’
2020-12-16 17:42:00,177 - napalm.base.helpers - ERROR - ‘list’ object has no attribute ‘xpath’
2020-12-16 17:42:00,177 - napalm.base.helpers - ERROR - ‘list’ object has no attribute ‘xpath’
2020-12-16 17:42:02,886 - napalm.pyIOSXR.iosxr - DEBUG - <Element Response at 0x7f21179acbc0>
2020-12-16 17:42:02,926 - napalm - DEBUG - Gathered facts:
{
“vendor”: “Cisco”,
“os_version”: “”,
“hostname”: “”,
“uptime”: -1,
“serial_number”: “”,
“fqdn”: “”,
“model”: “”,
“interface_list”: [
“Bundle-Ether1”,
“Bundle-Ether1.10”,
“Bundle-Ether1.20”,
“HundredGigE0/0/0/0”,
“HundredGigE0/0/0/1”,
“HundredGigE0/0/0/2”,
“HundredGigE0/0/0/3”,
“HundredGigE0/0/0/4”,
“HundredGigE0/0/0/5”,
“HundredGigE0/0/0/6”,
“HundredGigE0/0/0/7”,
“HundredGigE0/0/0/8”,
“HundredGigE0/0/0/9”,
“Loopback0”,
“Loopback11”,
“Loopback12”,
“Loopback13”,
“Loopback14”,
“Loopback15”,
“MgmtEth0/RP0/CPU0/0”,
“MgmtEth0/RP1/CPU0/0”,
“Null0”,
“TenGigE0/2/0/0”,
“TenGigE0/2/0/1”,
“TenGigE0/2/0/10”,
“TenGigE0/2/0/11”,
“TenGigE0/2/0/12”,
“TenGigE0/2/0/13”,
“TenGigE0/2/0/14”,
“TenGigE0/2/0/15”,
“TenGigE0/2/0/16”,
“TenGigE0/2/0/17”,
“TenGigE0/2/0/18”,
“TenGigE0/2/0/19”,
“TenGigE0/2/0/2”,
“TenGigE0/2/0/20”,
“TenGigE0/2/0/21”,
“TenGigE0/2/0/22”,
“TenGigE0/2/0/23”,
“TenGigE0/2/0/24”,
“TenGigE0/2/0/25”,
“TenGigE0/2/0/26”,
“TenGigE0/2/0/27”,
“TenGigE0/2/0/28”,
“TenGigE0/2/0/29”,
“TenGigE0/2/0/3”,
“TenGigE0/2/0/30”,
“TenGigE0/2/0/31”,
“TenGigE0/2/0/32”,
“TenGigE0/2/0/33”,
“TenGigE0/2/0/34”,
“TenGigE0/2/0/35”,
“TenGigE0/2/0/36”,
“TenGigE0/2/0/37”,
“TenGigE0/2/0/38”,
“TenGigE0/2/0/39”,
“TenGigE0/2/0/4”,
“TenGigE0/2/0/40”,
“TenGigE0/2/0/41”,
“TenGigE0/2/0/42”,
“TenGigE0/2/0/43”,
“TenGigE0/2/0/44”,
“TenGigE0/2/0/45”,
“TenGigE0/2/0/46”,
“TenGigE0/2/0/47”,
“TenGigE0/2/0/48”,
“TenGigE0/2/0/49”,
“TenGigE0/2/0/5”,
“TenGigE0/2/0/50”,
“TenGigE0/2/0/51”,
“TenGigE0/2/0/52”,
“TenGigE0/2/0/53”,
“TenGigE0/2/0/54”,
“TenGigE0/2/0/55”,
“TenGigE0/2/0/56”,
“TenGigE0/2/0/57”,
“TenGigE0/2/0/58”,
“TenGigE0/2/0/59”,
“TenGigE0/2/0/6”,
“TenGigE0/2/0/7”,
“TenGigE0/2/0/8”,
“TenGigE0/2/0/9”
]
}
{
“vendor”: “Cisco”,
“os_version”: “”,
“hostname”: “”,
“uptime”: -1,
“serial_number”: “”,
“fqdn”: “”,
“model”: “”,
“interface_list”: [
“Bundle-Ether1”,
“Bundle-Ether1.10”,
“Bundle-Ether1.20”,
“HundredGigE0/0/0/0”,
“HundredGigE0/0/0/1”,
“HundredGigE0/0/0/2”,
“HundredGigE0/0/0/3”,
“HundredGigE0/0/0/4”,
“HundredGigE0/0/0/5”,
“HundredGigE0/0/0/6”,
“HundredGigE0/0/0/7”,
“HundredGigE0/0/0/8”,
“HundredGigE0/0/0/9”,
“Loopback0”,
“Loopback11”,
“Loopback12”,
“Loopback13”,
“Loopback14”,
“Loopback15”,
“MgmtEth0/RP0/CPU0/0”,
“MgmtEth0/RP1/CPU0/0”,
“Null0”,
“TenGigE0/2/0/0”,
“TenGigE0/2/0/1”,
“TenGigE0/2/0/10”,
“TenGigE0/2/0/11”,
“TenGigE0/2/0/12”,
“TenGigE0/2/0/13”,
“TenGigE0/2/0/14”,
“TenGigE0/2/0/15”,
“TenGigE0/2/0/16”,
“TenGigE0/2/0/17”,
“TenGigE0/2/0/18”,
“TenGigE0/2/0/19”,
“TenGigE0/2/0/2”,
“TenGigE0/2/0/20”,
“TenGigE0/2/0/21”,
“TenGigE0/2/0/22”,
“TenGigE0/2/0/23”,
“TenGigE0/2/0/24”,
“TenGigE0/2/0/25”,
“TenGigE0/2/0/26”,
“TenGigE0/2/0/27”,
“TenGigE0/2/0/28”,
“TenGigE0/2/0/29”,
“TenGigE0/2/0/3”,
“TenGigE0/2/0/30”,
“TenGigE0/2/0/31”,
“TenGigE0/2/0/32”,
“TenGigE0/2/0/33”,
“TenGigE0/2/0/34”,
“TenGigE0/2/0/35”,
“TenGigE0/2/0/36”,
“TenGigE0/2/0/37”,
“TenGigE0/2/0/38”,
“TenGigE0/2/0/39”,
“TenGigE0/2/0/4”,
“TenGigE0/2/0/40”,
“TenGigE0/2/0/41”,
“TenGigE0/2/0/42”,
“TenGigE0/2/0/43”,
“TenGigE0/2/0/44”,
“TenGigE0/2/0/45”,
“TenGigE0/2/0/46”,
“TenGigE0/2/0/47”,
“TenGigE0/2/0/48”,
“TenGigE0/2/0/49”,
“TenGigE0/2/0/5”,
“TenGigE0/2/0/50”,
“TenGigE0/2/0/51”,
“TenGigE0/2/0/52”,
“TenGigE0/2/0/53”,
“TenGigE0/2/0/54”,
“TenGigE0/2/0/55”,
“TenGigE0/2/0/56”,
“TenGigE0/2/0/57”,
“TenGigE0/2/0/58”,
“TenGigE0/2/0/59”,
“TenGigE0/2/0/6”,
“TenGigE0/2/0/7”,
“TenGigE0/2/0/8”,
“TenGigE0/2/0/9”
]
}
2020-12-16 17:42:02,927 - napalm - DEBUG - get_facts - Successful
2020-12-16 17:42:02,927 - napalm - DEBUG - method - Calling with args: (<napalm.iosxr.iosxr.IOSXRDriver object at 0x7f2115b556a0>, ‘cli’), {‘commands’: [‘show platform’]}
2020-12-16 17:42:02,927 - napalm - DEBUG - cli - Attempting to resolve method
2020-12-16 17:42:02,927 - napalm - DEBUG - cli - Attempting to call method with kwargs: {‘commands’: [‘show platform’]}
2020-12-16 17:42:03,290 - napalm - DEBUG - cli - Response
{
“show platform”: “Node Type State Config state\n--------------------------------------------------------------------------------\n0/0/CPU0 NC6-10X100G-L-K IOS XR RUN NSHUT\n0/0/NPU0 Slice UP \n0/0/NPU1 Slice UP \n0/0/NPU2 Slice UP \n0/0/NPU3 Slice UP \n0/0/NPU4 Slice UP \n0/2/CPU0 NC6-60X10GE-L-S IOS XR RUN NSHUT\n0/2/NPU0 Slice UP \n0/2/NPU1 Slice UP \n0/2/NPU2 Slice UP \n0/2/NPU3 Slice UP \n0/RP0/CPU0 NC6-RP(Active) IOS XR RUN NSHUT\n0/RP1/CPU0 NC6-RP(Standby) IOS XR RUN NSHUT\n0/FC0 NC6-FC OPERATIONAL NSHUT\n0/FC1 NC6-FC OPERATIONAL NSHUT\n0/FC2 NC6-FC OPERATIONAL NSHUT\n0/FC3 NC6-FC OPERATIONAL NSHUT\n0/FC4 NC6-FC OPERATIONAL NSHUT\n0/FC5 NC6-FC OPERATIONAL NSHUT\n0/CI0 NCS-CRFT OPERATIONAL NSHUT\n0/FT0 NC6-FANTRAY OPERATIONAL NSHUT\n0/FT1 NC6-FANTRAY OPERATIONAL NSHUT\n0/PT0 NCS-DC-PWRTRAY OPERATIONAL NSHUT\n0/PT1 NCS-DC-PWRTRAY OPERATIONAL NSHUT\n0/PT2 NCS-DC-PWRTRAY OPERATIONAL NSHUT\n0/PT3 NCS-DC-PWRTRAY OPERATIONAL NSHUT\n0/PT4 NCS-DC-PWRTRAY OPERATIONAL NSHUT\n0/PT5 NCS-DC-PWRTRAY OPERATIONAL NSHUT”
}
2020-12-16 17:42:03,290 - napalm - DEBUG - method - Successful
2020-12-16 17:42:03,291 - napalm - DEBUG - close - Calling with args: (<napalm.iosxr.iosxr.IOSXRDriver object at 0x7f2115b556a0>,), {}
2020-12-16 17:42:03,291 - napalm.iosxr.iosxr - DEBUG - Closed connection with device 1.1.1.1
2020-12-16 17:42:03,291 - napalm - DEBUG - close - Successful
2020-12-16 17:42:03,292 - napalm - DEBUG - post_connection_tests - Calling with args: (<napalm.iosxr.iosxr.IOSXRDriver object at 0x7f2115b556a0>,), {}
2020-12-16 17:42:03,292 - napalm.iosxr.iosxr - DEBUG - Closed connection with device 1.1.1.1

Some advice can be help for me.

Is weird, because if I run the rpc in the router I can get the info, but if I use the Nornir or Napalm script it fails

facts_rpc_request = "
"

and if I apply the xpath like the code, I get the expected result

.//SystemTime/Uptime

Element=
NCS_1
15868051

.//RackTable/Rack/Attributes/BasicInfo

Element=’
Rack 0
NCS 6008 - 8-Slot Chassis
NCS-6008
V02
XXXXX
6.4.2
1.3.6.1.4.1.9.12.3.1.3.1304
true

I really appreciate some help

Maybe a bug in IOSXR code?

Always on IOS-XR running 6.5.3 work fine. Can you verify it works for you?

from napalm import get_network_driver

driver = get_network_driver('iosxr')
device = driver(hostname='sbx-iosxr-mgmt.cisco.com', 
                username='admin', 
                password='C1sco12345', 
                timeout=60, 
                optional_args={'port':8181,
                               'global_delay_factor': 2})

device.open()
commands = ['show ver']
#res = device.cli(commands)
res = device.get_facts()
device.close()
print(res)

And if you want to try with nornir, hosts.yaml

sbx-iosxr-mgmt:
  hostname: sbx-iosxr-mgmt.cisco.com
  username: admin
  password: C1sco12345
  port: 8181
  platform: iosxr
  connection_options:
        napalm:
            extras:
                optional_args:
                  global_delay_factor: 2

Hi no-such-anthony.

I hope you’re very well, I changed my code as you posted and it worked as expected, let me said that the error was on the groups.yaml file, in my case, It’s dynamically generated by a java code and I skipped that review thinking it was correct but the file had a typo, It had conection_options and should be connection_options, after changing the typo It worked fine.

Thank you for your help.
Cheers.

1 Like