diff --git a/show/muxcable.py b/show/muxcable.py index 07443080efeb..8df8dc11d87c 100644 --- a/show/muxcable.py +++ b/show/muxcable.py @@ -381,3 +381,34 @@ def eyeinfo(port, target): lane_data.append(res) click.echo(tabulate(lane_data, headers=headers)) sys.exit(EXIT_SUCCESS) + + +@muxcable.command() +@click.argument('port', required=True, default=None) +def cableinfo(port): + """Show muxcable cable information""" + + 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): + click.echo("ERR: Unable to get a port on muxcable port") + sys.exit(EXIT_FAIL) + if len(physical_port_list) != 1: + click.echo("ERR: Unable to get a single port on muxcable") + sys.exit(EXIT_FAIL) + + physical_port = physical_port_list[0] + import sonic_y_cable.y_cable + part_num = sonic_y_cable.y_cable.get_part_number(physical_port) + if part_num == False or part_num == -1: + click.echo("ERR: Unable to get cable info part number") + sys.exit(EXIT_FAIL) + vendor = sonic_y_cable.y_cable.get_vendor(physical_port) + if vendor == False or vendor == -1: + click.echo("ERR: Unable to get cable info vendor name") + sys.exit(EXIT_FAIL) + headers = ['Vendor', 'Model'] + + body = [[vendor, part_num]] + click.echo(tabulate(body, headers=headers)) diff --git a/tests/muxcable_test.py b/tests/muxcable_test.py index f6f35e7b8cc7..80968ec574bd 100644 --- a/tests/muxcable_test.py +++ b/tests/muxcable_test.py @@ -13,6 +13,9 @@ sys.modules['sonic_y_cable'] = mock.Mock() sys.modules['y_cable'] = mock.Mock() sys.modules['sonic_y_cable.y_cable'] = mock.Mock() +sys.modules['platform_sfputil'] = mock.Mock() +sys.modules['platform_sfputil_helper'] = mock.Mock() +sys.modules['utilities_common.platform_sfputil_helper'] = mock.Mock() #sys.modules['os'] = mock.Mock() #sys.modules['os.geteuid'] = mock.Mock() #sys.modules['platform_sfputil'] = mock.Mock() @@ -153,6 +156,12 @@ } """ +expected_muxcable_cableinfo_output = """\ +Vendor Model +-------- --------------- +Credo CACL1X321P2PA1M +""" + class TestMuxcable(object): @classmethod @@ -487,6 +496,56 @@ def test_config_muxcable_disable_loopback(self): assert result.exit_code == 100 + @mock.patch('sonic_y_cable.y_cable.get_part_number', mock.MagicMock(return_value=("CACL1X321P2PA1M"))) + @mock.patch('sonic_y_cable.y_cable.get_vendor', mock.MagicMock(return_value=("Credo "))) + @mock.patch('show.muxcable.platform_sfputil', mock.MagicMock(return_value=1)) + @mock.patch('utilities_common.platform_sfputil_helper.logical_port_name_to_physical_port_list', mock.MagicMock(return_value=[0])) + def test_show_muxcable_cableinfo(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(show.cli.commands["muxcable"].commands["cableinfo"], + ["Ethernet0"], obj=db) + + assert result.exit_code == 0 + assert result.output == expected_muxcable_cableinfo_output + + @mock.patch('sonic_y_cable.y_cable.get_part_number', mock.MagicMock(return_value=(False))) + @mock.patch('sonic_y_cable.y_cable.get_vendor', mock.MagicMock(return_value=(False))) + @mock.patch('show.muxcable.platform_sfputil', mock.MagicMock(return_value=1)) + @mock.patch('utilities_common.platform_sfputil_helper.logical_port_name_to_physical_port_list', mock.MagicMock(return_value=[0])) + def test_show_muxcable_cableinfo_incorrect_port(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(show.cli.commands["muxcable"].commands["cableinfo"], + ["Ethernet0"], obj=db) + assert result.exit_code == 1 + + @mock.patch('sonic_y_cable.y_cable.get_part_number', mock.MagicMock(return_value=(False))) + @mock.patch('sonic_y_cable.y_cable.get_vendor', mock.MagicMock(return_value=(False))) + @mock.patch('show.muxcable.platform_sfputil', mock.MagicMock(return_value=1)) + @mock.patch('utilities_common.platform_sfputil_helper.logical_port_name_to_physical_port_list', mock.MagicMock(return_value=0)) + def test_show_muxcable_cableinfo_incorrect_port_return_value(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(show.cli.commands["muxcable"].commands["cableinfo"], + ["Ethernet0"], obj=db) + assert result.exit_code == 1 + + @mock.patch('sonic_y_cable.y_cable.get_part_number', mock.MagicMock(return_value=(False))) + @mock.patch('sonic_y_cable.y_cable.get_vendor', mock.MagicMock(return_value=(False))) + @mock.patch('show.muxcable.platform_sfputil', mock.MagicMock(return_value=1)) + @mock.patch('utilities_common.platform_sfputil_helper.logical_port_name_to_physical_port_list', mock.MagicMock(return_value=[0, 1])) + def test_show_muxcable_cableinfo_incorrect_logical_port_return_value(self): + runner = CliRunner() + db = Db() + + result = runner.invoke(show.cli.commands["muxcable"].commands["cableinfo"], + ["Ethernet0"], obj=db) + assert result.exit_code == 1 + @classmethod def teardown_class(cls): os.environ['UTILITIES_UNIT_TESTING'] = "0" diff --git a/utilities_common/platform_sfputil_helper.py b/utilities_common/platform_sfputil_helper.py index 87f0863e9a63..fbacdd4126dc 100644 --- a/utilities_common/platform_sfputil_helper.py +++ b/utilities_common/platform_sfputil_helper.py @@ -37,3 +37,13 @@ def platform_sfputil_read_porttab_mappings(): sys.exit(1) return 0 + +def logical_port_name_to_physical_port_list(port_name): + if port_name.startswith("Ethernet"): + if platform_sfputil.is_logical_port(port_name): + return platform_sfputil.get_logical_to_physical(port_name) + else: + click.echo("Invalid port '{}'".format(port_name)) + return None + else: + return [int(port_name)]