diff --git a/napalm/nxos/nxos.py b/napalm/nxos/nxos.py index d4ceebfec..9ae058c00 100644 --- a/napalm/nxos/nxos.py +++ b/napalm/nxos/nxos.py @@ -31,6 +31,7 @@ from netmiko import file_transfer from nxapi_plumbing import Device as NXOSDevice from nxapi_plumbing import NXAPIAuthError, NXAPIConnectionError, NXAPICommandError +import json # import NAPALM Base import napalm.base.helpers @@ -601,6 +602,37 @@ def get_lldp_neighbors_detail(self, interface=""): return lldp + @staticmethod + def _get_table_rows(parent_table, table_name, row_name): + """ + Inconsistent behavior: + {'TABLE_intf': [{'ROW_intf': { + vs + {'TABLE_mac_address': {'ROW_mac_address': [{ + vs + {'TABLE_vrf': {'ROW_vrf': {'TABLE_adj': {'ROW_adj': { + """ + if parent_table is None: + return [] + _table = parent_table.get(table_name) + _table_rows = [] + if isinstance(_table, list): + _table_rows = [_table_row.get(row_name) for _table_row in _table] + elif isinstance(_table, dict): + _table_rows = _table.get(row_name) + if not isinstance(_table_rows, list): + _table_rows = [_table_rows] + return _table_rows + + def _get_reply_table(self, result, table_name, row_name): + return self._get_table_rows(result, table_name, row_name) + + def _get_command_table(self, command, table_name, row_name): + json_output = self._send_command(command) + if type(json_output) is not dict: + json_output = json.loads(json_output) + return self._get_reply_table(json_output, table_name, row_name) + class NXOSDriver(NXOSDriverBase): def __init__(self, hostname, username, password, timeout=60, optional_args=None): @@ -701,35 +733,6 @@ def _compute_timestamp(stupid_cisco_output): ) return time.time() - delta - @staticmethod - def _get_table_rows(parent_table, table_name, row_name): - """ - Inconsistent behavior: - {'TABLE_intf': [{'ROW_intf': { - vs - {'TABLE_mac_address': {'ROW_mac_address': [{ - vs - {'TABLE_vrf': {'ROW_vrf': {'TABLE_adj': {'ROW_adj': { - """ - if parent_table is None: - return [] - _table = parent_table.get(table_name) - _table_rows = [] - if isinstance(_table, list): - _table_rows = [_table_row.get(row_name) for _table_row in _table] - elif isinstance(_table, dict): - _table_rows = _table.get(row_name) - if not isinstance(_table_rows, list): - _table_rows = [_table_rows] - return _table_rows - - def _get_reply_table(self, result, table_name, row_name): - return self._get_table_rows(result, table_name, row_name) - - def _get_command_table(self, command, table_name, row_name): - json_output = self._send_command(command) - return self._get_reply_table(json_output, table_name, row_name) - def is_alive(self): if self.device: return {"is_alive": True} @@ -781,10 +784,22 @@ def get_facts(self): facts = {} facts["vendor"] = "Cisco" + show_inventory_table = self._get_command_table( + "show inventory", "TABLE_inv", "ROW_inv" + ) + if isinstance(show_inventory_table, dict): + show_inventory_table = [show_inventory_table] + + facts["serial_number"] = None + + for row in show_inventory_table: + if row["name"] == "Chassis": + facts["serial_number"] = row.get("serialnum", "") + break + show_version = self._send_command("show version") facts["model"] = show_version.get("chassis_id", "") facts["hostname"] = show_version.get("host_name", "") - facts["serial_number"] = show_version.get("proc_board_id", "") facts["os_version"] = show_version.get("sys_ver_str", "") uptime_days = show_version.get("kern_uptm_days", 0) diff --git a/napalm/nxos_ssh/nxos_ssh.py b/napalm/nxos_ssh/nxos_ssh.py index 1eec8e6d7..fe2b81bd3 100644 --- a/napalm/nxos_ssh/nxos_ssh.py +++ b/napalm/nxos_ssh/nxos_ssh.py @@ -584,16 +584,23 @@ def get_facts(self): show_int_status = self._send_command("show interface status") show_hostname = self._send_command("show hostname") + show_inventory_table = self._get_command_table( + "show inventory | json", "TABLE_inv", "ROW_inv" + ) + if isinstance(show_inventory_table, dict): + show_inventory_table = [show_inventory_table] + + for row in show_inventory_table: + if row["name"] == "Chassis": + serial_number = row.get("serialnum", "") + break + # uptime/serial_number/IOS version for line in show_ver.splitlines(): if " uptime is " in line: _, uptime_str = line.split(" uptime is ") uptime = self.parse_uptime(uptime_str) - if "Processor Board ID" in line: - _, serial_number = line.split("Processor Board ID ") - serial_number = serial_number.strip() - if "system: " in line or "NXOS: " in line: line = line.strip() os_version = line.split()[2] diff --git a/test/nxos/mocked_data/test_get_facts/normal/show_inventory.json b/test/nxos/mocked_data/test_get_facts/normal/show_inventory.json new file mode 100644 index 000000000..a6de22b65 --- /dev/null +++ b/test/nxos/mocked_data/test_get_facts/normal/show_inventory.json @@ -0,0 +1,34 @@ +{ + "TABLE_inv": { + "ROW_inv": [ + { + "name": "Chassis", + "desc": "Nexus 6001 Chassis", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "TM6017D760B" + }, + { + "name": "Module 1", + "desc": "Nexus 64 Supervisor", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Module 2", + "desc": "Nexus 4xQSFP Ethernet Module", + "productid": "N6K-C6001-M4Q", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Fan 1", + "desc": "Chassis fan module", + "productid": "N6K-C6001-FAN-B", + "vendorid": "N/A", + "serialnum": "N/A" + } + ] + } +} diff --git a/test/nxos_ssh/mocked_data/test_get_facts/7009_6_2_14/show_inventory___json.txt b/test/nxos_ssh/mocked_data/test_get_facts/7009_6_2_14/show_inventory___json.txt new file mode 100644 index 000000000..6e63466de --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_facts/7009_6_2_14/show_inventory___json.txt @@ -0,0 +1,34 @@ +{ + "TABLE_inv": { + "ROW_inv": [ + { + "name": "Chassis", + "desc": "Nexus 6001 Chassis", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "JAF1602BKEN" + }, + { + "name": "Module 1", + "desc": "Nexus 64 Supervisor", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Module 2", + "desc": "Nexus 4xQSFP Ethernet Module", + "productid": "N6K-C6001-M4Q", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Fan 1", + "desc": "Chassis fan module", + "productid": "N6K-C6001-FAN-B", + "vendorid": "N/A", + "serialnum": "N/A" + } + ] + } +} diff --git a/test/nxos_ssh/mocked_data/test_get_facts/N93180/show_inventory___json.txt b/test/nxos_ssh/mocked_data/test_get_facts/N93180/show_inventory___json.txt new file mode 100644 index 000000000..ad54a014c --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_facts/N93180/show_inventory___json.txt @@ -0,0 +1,34 @@ +{ + "TABLE_inv": { + "ROW_inv": [ + { + "name": "Chassis", + "desc": "Nexus 6001 Chassis", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "FDO21270U84" + }, + { + "name": "Module 1", + "desc": "Nexus 64 Supervisor", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Module 2", + "desc": "Nexus 4xQSFP Ethernet Module", + "productid": "N6K-C6001-M4Q", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Fan 1", + "desc": "Chassis fan module", + "productid": "N6K-C6001-FAN-B", + "vendorid": "N/A", + "serialnum": "N/A" + } + ] + } +} diff --git a/test/nxos_ssh/mocked_data/test_get_facts/missing_domain/show_inventory___json.txt b/test/nxos_ssh/mocked_data/test_get_facts/missing_domain/show_inventory___json.txt new file mode 100644 index 000000000..15cbe724c --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_facts/missing_domain/show_inventory___json.txt @@ -0,0 +1,34 @@ +{ + "TABLE_inv": { + "ROW_inv": [ + { + "name": "Chassis", + "desc": "Nexus 6001 Chassis", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "TM6012EC74B" + }, + { + "name": "Module 1", + "desc": "Nexus 64 Supervisor", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Module 2", + "desc": "Nexus 4xQSFP Ethernet Module", + "productid": "N6K-C6001-M4Q", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Fan 1", + "desc": "Chassis fan module", + "productid": "N6K-C6001-FAN-B", + "vendorid": "N/A", + "serialnum": "N/A" + } + ] + } +} diff --git a/test/nxos_ssh/mocked_data/test_get_facts/newer_version/show_inventory___json.txt b/test/nxos_ssh/mocked_data/test_get_facts/newer_version/show_inventory___json.txt new file mode 100644 index 000000000..15cbe724c --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_facts/newer_version/show_inventory___json.txt @@ -0,0 +1,34 @@ +{ + "TABLE_inv": { + "ROW_inv": [ + { + "name": "Chassis", + "desc": "Nexus 6001 Chassis", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "TM6012EC74B" + }, + { + "name": "Module 1", + "desc": "Nexus 64 Supervisor", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Module 2", + "desc": "Nexus 4xQSFP Ethernet Module", + "productid": "N6K-C6001-M4Q", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Fan 1", + "desc": "Chassis fan module", + "productid": "N6K-C6001-FAN-B", + "vendorid": "N/A", + "serialnum": "N/A" + } + ] + } +} diff --git a/test/nxos_ssh/mocked_data/test_get_facts/normal/show_inventory___json.txt b/test/nxos_ssh/mocked_data/test_get_facts/normal/show_inventory___json.txt new file mode 100644 index 000000000..15cbe724c --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_facts/normal/show_inventory___json.txt @@ -0,0 +1,34 @@ +{ + "TABLE_inv": { + "ROW_inv": [ + { + "name": "Chassis", + "desc": "Nexus 6001 Chassis", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "TM6012EC74B" + }, + { + "name": "Module 1", + "desc": "Nexus 64 Supervisor", + "productid": "N6K-C6001-64P", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Module 2", + "desc": "Nexus 4xQSFP Ethernet Module", + "productid": "N6K-C6001-M4Q", + "vendorid": "V01", + "serialnum": "FOC11111111" + }, + { + "name": "Fan 1", + "desc": "Chassis fan module", + "productid": "N6K-C6001-FAN-B", + "vendorid": "N/A", + "serialnum": "N/A" + } + ] + } +}