diff --git a/show/muxcable.py b/show/muxcable.py index e639890ce9..9e56514c30 100644 --- a/show/muxcable.py +++ b/show/muxcable.py @@ -1,3 +1,4 @@ + import json import sys import time @@ -97,6 +98,51 @@ def check_port_in_mux_cable_table(port): return False + +def get_per_port_firmware(port): + + state_db = {} + mux_info_dict = {} + mux_info_full_dict = {} + + # Getting all front asic namespace and correspding config and state DB connector + + namespaces = multi_asic.get_front_end_namespaces() + for namespace in namespaces: + asic_id = multi_asic.get_asic_index_from_namespace(namespace) + state_db[asic_id] = swsscommon.SonicV2Connector(use_unix_socket_path=False, namespace=namespace) + state_db[asic_id].connect(state_db[asic_id].STATE_DB) + + if platform_sfputil is not None: + asic_index = platform_sfputil_helper.get_asic_id_for_logical_port(port) + + if asic_index is None: + # TODO this import is only for unit test purposes, and should be removed once sonic_platform_base + # is fully mocked + import sonic_platform_base.sonic_sfp.sfputilhelper + asic_index = sonic_platform_base.sonic_sfp.sfputilhelper.SfpUtilHelper().get_asic_id_for_logical_port(port) + if asic_index is None: + click.echo("Got invalid asic index for port {}, cant retrieve mux cable table entries".format(port)) + return False + + + mux_info_full_dict[asic_index] = state_db[asic_index].get_all( + state_db[asic_index].STATE_DB, 'MUX_CABLE_INFO|{}'.format(port)) + + res_dir = {} + res_dir = mux_info_full_dict[asic_index] + mux_info_dict["version_nic_active"] = res_dir.get("version_nic_active", None) + mux_info_dict["version_nic_inactive"] = res_dir.get("version_nic_inactive", None) + mux_info_dict["version_nic_next"] = res_dir.get("version_nic_next", None) + mux_info_dict["version_peer_active"] = res_dir.get("version_peer_active", None) + mux_info_dict["version_peer_inactive"] = res_dir.get("version_peer_inactive", None) + mux_info_dict["version_peer_next"] = res_dir.get("version_peer_next", None) + mux_info_dict["version_self_active"] = res_dir.get("version_self_active", None) + mux_info_dict["version_self_inactive"] = res_dir.get("version_self_inactive", None) + mux_info_dict["version_self_next"] = res_dir.get("version_self_next", None) + + return mux_info_dict + def get_response_for_version(port, mux_info_dict): state_db = {} xcvrd_show_fw_res_tbl = {} @@ -1528,7 +1574,7 @@ def version(db, port, active): delete_all_keys_in_db_table("STATE_DB", "XCVRD_SHOW_FW_RSP") delete_all_keys_in_db_table("STATE_DB", "XCVRD_SHOW_FW_RES") - if port is not None: + if port is not None and port != "all": res_dict = {} mux_info_dict, mux_info_active_dict = {}, {} @@ -1561,6 +1607,65 @@ def version(db, port, active): click.echo("{}".format(json.dumps(mux_info_active_dict, indent=4))) else: click.echo("{}".format(json.dumps(mux_info_dict, indent=4))) + + elif port == "all" and port is not None: + + logical_port_list = platform_sfputil_helper.get_logical_list() + + rc_exit = True + + for port in logical_port_list: + + if platform_sfputil is not None: + physical_port_list = platform_sfputil_helper.logical_port_name_to_physical_port_list(port) + + if not isinstance(physical_port_list, list): + continue + if len(physical_port_list) != 1: + continue + + if not check_port_in_mux_cable_table(port): + continue + + physical_port = physical_port_list[0] + + logical_port_list_for_physical_port = platform_sfputil_helper.get_physical_to_logical() + + logical_port_list_per_port = logical_port_list_for_physical_port.get(physical_port, None) + + """ This check is required for checking whether or not this logical port is the one which is + actually mapped to physical port and by convention it is always the first port. + TODO: this should be removed with more logic to check which logical port maps to actual physical port + being used""" + + if port != logical_port_list_per_port[0]: + continue + + + port = platform_sfputil_helper.get_interface_alias(port, db) + + mux_info_dict = get_per_port_firmware(port) + if not isinstance(mux_info_dict, dict): + mux_info_dict = {} + rc_exit = False + + mux_info = {} + mux_info_active_dict = {} + if active is True: + for key in mux_info_dict: + if key.endswith("_active"): + mux_info_active_dict[key] = mux_info_dict[key] + mux_info[port] = mux_info_active_dict + click.echo("{}".format(json.dumps(mux_info, indent=4))) + else: + mux_info[port] = mux_info_dict + click.echo("{}".format(json.dumps(mux_info, indent=4))) + + if rc_exit == False: + sys.exit(EXIT_FAIL) + + sys.exit(CONFIG_SUCCESSFUL) + else: port_name = platform_sfputil_helper.get_interface_name(port, db) click.echo("Did not get a valid Port for mux firmware version".format(port_name)) @@ -1640,6 +1745,7 @@ def metrics(db, port, json_output): def event_log(db, port, json_output): """Show muxcable event log """ + click.confirm(('Muxcable at port {} will retreive cable logs from MCU, Caution: approx wait time could be ~2 minutes Continue?'.format(port)), abort=True) port = platform_sfputil_helper.get_interface_name(port, db) delete_all_keys_in_db_table("APPL_DB", "XCVRD_EVENT_LOG_CMD") delete_all_keys_in_db_table("STATE_DB", "XCVRD_EVENT_LOG_RSP") @@ -1735,7 +1841,7 @@ def packetloss(db, port, json_output): for namespace in namespaces: asic_id = multi_asic.get_asic_index_from_namespace(namespace) - per_npu_statedb[asic_id] = swsscommon.SonicV2Connector(use_unix_socket_path=True, namespace=namespace) + per_npu_statedb[asic_id] = swsscommon.SonicV2Connector(use_unix_socket_path=False, namespace=namespace) per_npu_statedb[asic_id].connect(per_npu_statedb[asic_id].STATE_DB) pckloss_table_keys[asic_id] = per_npu_statedb[asic_id].keys( diff --git a/tests/mock_tables/state_db.json b/tests/mock_tables/state_db.json index 5e66e5b7d7..a042c3e85f 100644 --- a/tests/mock_tables/state_db.json +++ b/tests/mock_tables/state_db.json @@ -365,6 +365,30 @@ "Name": "CRC-32", "Value": "0xAC518FB3" }, + "MUX_CABLE_INFO|Ethernet0": { + "version_peer_next": "0.2MS", + "version_peer_active": "0.2MS", + "version_peer_inactive": "0.2MS", + "version_nic_next": "0.2MS", + "version_nic_active": "0.2MS", + "version_nic_inactive": "0.2MS", + "version_self_next": "0.2MS", + "version_self_active": "0.2MS", + "version_self_inactive": "0.2MS", + "Value": "AABB" + }, + "MUX_CABLE_INFO|Ethernet12": { + "version_peer_next": "0.1MS", + "version_peer_active": "0.1MS", + "version_peer_inactive": "0.1MS", + "version_nic_next": "0.1MS", + "version_nic_active": "0.1MS", + "version_nic_inactive": "0.1MS", + "version_self_next": "0.1MS", + "version_self_active": "0.1MS", + "version_self_inactive": "0.1MS", + "Value": "AABB" + }, "SWITCH_CAPABILITY|switch": { "MIRROR": "true", "MIRRORV6": "true", diff --git a/tests/muxcable_test.py b/tests/muxcable_test.py index 965ae91ea8..8e6b924c28 100644 --- a/tests/muxcable_test.py +++ b/tests/muxcable_test.py @@ -422,6 +422,34 @@ } """ +show_muxcable_firmware_version_all_expected_output = """\ +{ + "Ethernet12": { + "version_nic_active": "0.1MS", + "version_nic_inactive": "0.1MS", + "version_nic_next": "0.1MS", + "version_peer_active": "0.1MS", + "version_peer_inactive": "0.1MS", + "version_peer_next": "0.1MS", + "version_self_active": "0.1MS", + "version_self_inactive": "0.1MS", + "version_self_next": "0.1MS" + } +} +""" + +show_muxcable_firmware_version_all_active_expected_output = """\ +{ + "Ethernet12": { + "version_nic_active": "0.1MS", + "version_peer_active": "0.1MS", + "version_self_active": "0.1MS" + } +} +""" + + + show_muxcable_firmware_version_active_expected_output = """\ { "version_self_active": "0.6MS", @@ -980,6 +1008,7 @@ def test_show_mux_fecstatistics(self): assert result.exit_code == 0 + @mock.patch('click.confirm', mock.MagicMock(return_value=("y"))) @mock.patch('show.muxcable.delete_all_keys_in_db_table', mock.MagicMock(return_value=0)) @mock.patch('show.muxcable.update_and_get_response_for_xcvr_cmd', mock.MagicMock(return_value={0: 0, 1: "True"})) @@ -1428,6 +1457,66 @@ def test_show_muxcable_firmware_version(self): assert result.exit_code == 0 assert result.output == show_muxcable_firmware_version_expected_output + + @mock.patch('show.muxcable.delete_all_keys_in_db_table', mock.MagicMock(return_value=0)) + @mock.patch('show.muxcable.update_and_get_response_for_xcvr_cmd', mock.MagicMock(return_value={0: 0, + 1: "True"})) + @mock.patch('utilities_common.platform_sfputil_helper.get_logical_list', mock.MagicMock(return_value=["Ethernet0", "Ethernet12"])) + @mock.patch('utilities_common.platform_sfputil_helper.get_asic_id_for_logical_port', mock.MagicMock(return_value=0)) + @mock.patch('show.muxcable.platform_sfputil', mock.MagicMock(return_value={0: ["Ethernet12", "Ethernet0"]})) + @mock.patch('utilities_common.platform_sfputil_helper.get_logical_list', mock.MagicMock(return_value=["Ethernet0", "Ethernet12"])) + @mock.patch('utilities_common.platform_sfputil_helper.get_physical_to_logical', mock.MagicMock(return_value={0: ["Ethernet12", "Ethernet0"]})) + @mock.patch('utilities_common.platform_sfputil_helper.logical_port_name_to_physical_port_list', mock.MagicMock(return_value=[0])) + def test_show_muxcable_firmware_version_all(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(show.cli.commands["muxcable"].commands["firmware"].commands["version"], [ + "all"], obj=db) + assert result.exit_code == 0 + f = open("newfile", "w") + f.write(result.output) + assert result.output == show_muxcable_firmware_version_all_expected_output + + + @mock.patch('show.muxcable.delete_all_keys_in_db_table', mock.MagicMock(return_value=0)) + @mock.patch('show.muxcable.update_and_get_response_for_xcvr_cmd', mock.MagicMock(return_value={0: 0, + 1: "True"})) + @mock.patch('utilities_common.platform_sfputil_helper.get_logical_list', mock.MagicMock(return_value=["Ethernet0", "Ethernet12"])) + @mock.patch('utilities_common.platform_sfputil_helper.get_asic_id_for_logical_port', mock.MagicMock(return_value=0)) + @mock.patch('show.muxcable.platform_sfputil', mock.MagicMock(return_value={0: ["Ethernet12", "Ethernet0"]})) + @mock.patch('utilities_common.platform_sfputil_helper.get_logical_list', mock.MagicMock(return_value=["Ethernet0", "Ethernet12"])) + @mock.patch('utilities_common.platform_sfputil_helper.get_physical_to_logical', mock.MagicMock(return_value={0: ["Ethernet12", "Ethernet0"]})) + @mock.patch('utilities_common.platform_sfputil_helper.logical_port_name_to_physical_port_list', mock.MagicMock(return_value=[0])) + def test_show_muxcable_firmware_version_all_active(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(show.cli.commands["muxcable"].commands["firmware"].commands["version"], [ + "all", "--active"], obj=db) + assert result.exit_code == 0 + f = open("newfile", "w") + f.write(result.output) + assert result.output == show_muxcable_firmware_version_all_active_expected_output + + @mock.patch('show.muxcable.delete_all_keys_in_db_table', mock.MagicMock(return_value=0)) + @mock.patch('show.muxcable.update_and_get_response_for_xcvr_cmd', mock.MagicMock(return_value={0: 0, + 1: "True"})) + @mock.patch('utilities_common.platform_sfputil_helper.get_logical_list', mock.MagicMock(return_value=["Ethernet0", "Ethernet12"])) + @mock.patch('utilities_common.platform_sfputil_helper.get_asic_id_for_logical_port', mock.MagicMock(return_value=1)) + @mock.patch('show.muxcable.platform_sfputil', mock.MagicMock(return_value={0: ["Ethernet12", "Ethernet0"]})) + @mock.patch('utilities_common.platform_sfputil_helper.get_logical_list', mock.MagicMock(return_value=["Ethernet0", "Ethernet12"])) + @mock.patch('utilities_common.platform_sfputil_helper.get_physical_to_logical', mock.MagicMock(return_value={0: ["Ethernet12", "Ethernet0"]})) + @mock.patch('utilities_common.platform_sfputil_helper.logical_port_name_to_physical_port_list', mock.MagicMock(return_value=[0])) + def test_show_muxcable_firmware_version_all_bad_asic_index(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(show.cli.commands["muxcable"].commands["firmware"].commands["version"], [ + "all"], obj=db) + assert result.exit_code == 1 + + @mock.patch('config.muxcable.delete_all_keys_in_db_table', mock.MagicMock(return_value=0)) @mock.patch('config.muxcable.update_and_get_response_for_xcvr_cmd', mock.MagicMock(return_value={0: 0, 1: "sucess"}))