From 41c16a0d343ea8f8db7b9678362e6584d078826e Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Fri, 28 Aug 2020 00:16:15 -0700 Subject: [PATCH 1/6] show_transceiver changes Rearranging of common functions in config/main.py yo py-common, utilities_common --- config/main.py | 75 +------------------- scripts/sfpshow | 102 ++++++++++++++++++--------- show/interfaces/__init__.py | 14 +++- tests/mock_tables/mock_multi_asic.py | 4 ++ tests/sfp_test.py | 47 ++++++++++++ utilities_common/multi_asic.py | 38 ++++++++++ 6 files changed, 171 insertions(+), 109 deletions(-) diff --git a/config/main.py b/config/main.py index cfb7e5a0c66..8ac1b8461fc 100755 --- a/config/main.py +++ b/config/main.py @@ -15,10 +15,11 @@ from minigraph import parse_device_desc_xml from portconfig import get_child_ports from sonic_py_common import device_info, multi_asic -from sonic_py_common.interface import front_panel_prefix, portchannel_prefix, vlan_prefix, loopback_prefix +from sonic_py_common.interface import get_interface_table_name from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig from utilities_common.db import Db from utilities_common.intf_filter import parse_interface_in_filter +from utilities_common.multi_asic import get_port_namespace import utilities_common.cli as clicommon from .utils import log @@ -371,25 +372,6 @@ def interface_name_to_alias(config_db, interface_name): return None -# TODO move to sonic-py-common package -def get_interface_table_name(interface_name): - """Get table name by interface_name prefix - """ - if interface_name.startswith(front_panel_prefix()): - if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: - return "VLAN_SUB_INTERFACE" - return "INTERFACE" - elif interface_name.startswith(portchannel_prefix()): - if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: - return "VLAN_SUB_INTERFACE" - return "PORTCHANNEL_INTERFACE" - elif interface_name.startswith(vlan_prefix()): - return "VLAN_INTERFACE" - elif interface_name.startswith(loopback_prefix()): - return "LOOPBACK_INTERFACE" - else: - return "" - def interface_ipaddr_dependent_on_interface(config_db, interface_name): """Get table keys including ipaddress """ @@ -414,59 +396,6 @@ def is_interface_bind_to_vrf(config_db, interface_name): return True return False -# TODO move to sonic-py-common package -# Get the table name based on the interface type -def get_port_table_name(interface_name): - """Get table name by port_name prefix - """ - if interface_name.startswith(front_panel_prefix()): - if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: - return "VLAN_SUB_INTERFACE" - return "PORT" - elif interface_name.startswith(portchannel_prefix()): - if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: - return "VLAN_SUB_INTERFACE" - return "PORTCHANNEL" - elif interface_name.startswith(vlan_prefix()): - return "VLAN_INTERFACE" - elif interface_name.startswith(loopback_prefix()): - return "LOOPBACK_INTERFACE" - else: - return "" - -# Return the namespace where an interface belongs -# The port name input could be in default mode or in alias mode. -def get_port_namespace(port): - # If it is a non multi-asic platform, or if the interface is management interface - # return DEFAULT_NAMESPACE - if not multi_asic.is_multi_asic() or port == 'eth0': - return DEFAULT_NAMESPACE - - # Get the table to check for interface presence - table_name = get_port_table_name(port) - if table_name == "": - return None - - ns_list = multi_asic.get_all_namespaces() - namespaces = ns_list['front_ns'] + ns_list['back_ns'] - for namespace in namespaces: - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() - - # If the interface naming mode is alias, search the tables for alias_name. - if clicommon.get_interface_naming_mode() == "alias": - port_dict = config_db.get_table(table_name) - if port_dict: - for port_name in port_dict.keys(): - if port == port_dict[port_name]['alias']: - return namespace - else: - entry = config_db.get_entry(table_name, port) - if entry: - return namespace - - return None - def del_interface_bind_to_vrf(config_db, vrf_name): """del interface bind to vrf """ diff --git a/scripts/sfpshow b/scripts/sfpshow index 188f21de83f..5437f579cdc 100755 --- a/scripts/sfpshow +++ b/scripts/sfpshow @@ -13,6 +13,9 @@ from natsort import natsorted from swsssdk import SonicV2Connector from tabulate import tabulate +from utilities_common import multi_asic as multi_asic_util +from sonic_py_common.interface import front_panel_prefix, backplane_prefix + # Mock the redis for unit test purposes # try: if os.environ["UTILITIES_UNIT_TESTING"] == "2": @@ -21,6 +24,9 @@ try: sys.path.insert(0, modules_path) sys.path.insert(0, test_path) import mock_tables.dbconnector + if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic": + import mock_tables.mock_multi_asic + mock_tables.dbconnector.load_namespace_config() except KeyError: pass @@ -130,14 +136,15 @@ dom_value_unit_map = {'rx1power': 'dBm', 'rx2power': 'dBm', class SFPShow(object): - def __init__(self): + def __init__(self, intf_name, namespace_option, dump_dom=False): super(SFPShow,self).__init__() - self.adb = SonicV2Connector(host="127.0.0.1") - self.adb.connect(self.adb.APPL_DB) - - self.sdb = SonicV2Connector(host="127.0.0.1") - self.sdb.connect(self.sdb.STATE_DB) - return + self.db = None + self.config_db = None + self.intf_name = intf_name + self.dump_dom = dump_dom + self.table = [] + self.output = '' + self.multi_asic = multi_asic_util.MultiAsic(namespace_option=namespace_option) # Convert dict values to cli output string def format_dict_value_to_string(self, sorted_key_table, @@ -291,53 +298,62 @@ class SFPShow(object): return out_put - def display_eeprom(self, interfacename, dump_dom): + @multi_asic_util.run_on_multi_asic + def get_eeprom(self): out_put = '' - if interfacename is not None: - presence = self.sdb.exists(self.sdb.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interfacename)) + if self.intf_name is not None: + presence = self.db.exists(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(self.intf_name)) if presence: - out_put = self.convert_interface_sfp_info_to_cli_output_string(self.sdb, interfacename, dump_dom) + out_put = self.convert_interface_sfp_info_to_cli_output_string(self.db, self.intf_name, self.dump_dom) else: - out_put = out_put + interfacename + ': ' + 'SFP EEPROM Not detected' + '\n' + out_put = out_put + self.intf_name + ': ' + 'SFP EEPROM Not detected' + '\n' else: - port_table_keys = self.adb.keys(self.adb.APPL_DB, "PORT_TABLE:*") + port_table_keys = self.db.keys(self.db.APPL_DB, "PORT_TABLE:*") sorted_table_keys = natsorted(port_table_keys) + print(self.multi_asic.current_namespace) for i in sorted_table_keys: interface = re.split(':', i, maxsplit=1)[-1].strip() - if interface and interface.startswith('Ethernet'): - presence = self.sdb.exists(self.sdb.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interface)) + if interface and interface.startswith(front_panel_prefix()) and not interface.startswith(backplane_prefix()): + presence = self.db.exists(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interface)) if presence: - out_put = out_put + self.convert_interface_sfp_info_to_cli_output_string(self.sdb, interface, dump_dom) + out_put = out_put + self.convert_interface_sfp_info_to_cli_output_string(self.db, interface, self.dump_dom) else: out_put = out_put + interface + ': ' + 'SFP EEPROM Not detected' + '\n' - out_put = out_put + '\n' + out_put = out_put + '\n' - click.echo(out_put) + self.output += out_put - def display_presence(self, interfacename): + @multi_asic_util.run_on_multi_asic + def get_presence(self): port_table = [] - header = ['Port', 'Presence'] - if interfacename is not None: - presence = self.sdb.exists(self.sdb.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(interfacename)) + if self.intf_name is not None: + presence = self.db.exists(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(self.intf_name)) if presence: - port_table.append((interfacename, 'Present')) + port_table.append((self.intf_name, 'Present')) else: - port_table.append((interfacename, 'Not present')) + port_table.append((self.intf_name, 'Not present')) else: - port_table_keys = self.adb.keys(self.adb.APPL_DB, "PORT_TABLE:*") + port_table_keys = self.db.keys(self.db.APPL_DB, "PORT_TABLE:*") for i in port_table_keys: key = re.split(':', i, maxsplit=1)[-1].strip() - if key and key.startswith('Ethernet'): - presence = self.sdb.exists(self.sdb.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(key)) + if key and key.startswith(front_panel_prefix()) and not key.startswith(backplane_prefix()): + presence = self.db.exists(self.db.STATE_DB, 'TRANSCEIVER_INFO|{}'.format(key)) if presence: port_table.append((key,'Present')) else: port_table.append((key,'Not present')) - sorted_port_table = natsorted(port_table) + self.table += port_table + + def display_eeprom(self): + click.echo(self.output) + + def display_presence(self): + header = ['Port', 'Presence'] + sorted_port_table = natsorted(self.table) click.echo(tabulate(sorted_port_table, header)) # This is our main entrypoint - the main 'sfpshow' command @@ -350,16 +366,34 @@ def cli(): @cli.command() @click.option('-p', '--port', metavar='', help="Display SFP EEPROM data for port only") @click.option('-d', '--dom', 'dump_dom', is_flag=True, help="Also display Digital Optical Monitoring (DOM) data") -def eeprom(port, dump_dom): - sfp = SFPShow() - sfp.display_eeprom(port, dump_dom) +@click.option('-n', '--namespace', default=None, help="Display interfaces for specific namespace") +def eeprom(port, dump_dom, namespace): + if port: + ns = multi_asic_util.get_port_namespace(port) + if namespace is not None and ns != namespace: + print("Error: Interface {} don't belong to this namespace {}".format(port, namespace)) + return + namespace=ns + + sfp = SFPShow(port, namespace, dump_dom) + sfp.get_eeprom() + sfp.display_eeprom() # 'presence' subcommand @cli.command() @click.option('-p', '--port', metavar='', help="Display SFP presence for port only") -def presence(port): - sfp = SFPShow() - sfp.display_presence(port) +@click.option('-n', '--namespace', default=None, help="Display interfaces for specific namespace") +def presence(port, namespace): + if port: + ns = multi_asic_util.get_port_namespace(port) + if namespace is not None and ns != namespace: + print("Error: Interface {} don't belong to this namespace {}".format(port, namespace)) + return + namespace=ns + + sfp = SFPShow(port, namespace) + sfp.get_presence() + sfp.display_presence() if __name__ == "__main__": cli() diff --git a/show/interfaces/__init__.py b/show/interfaces/__init__.py index 06c74b9b2ab..2892c2b6692 100644 --- a/show/interfaces/__init__.py +++ b/show/interfaces/__init__.py @@ -284,8 +284,10 @@ def transceiver(): @transceiver.command() @click.argument('interfacename', required=False) @click.option('-d', '--dom', 'dump_dom', is_flag=True, help="Also display Digital Optical Monitoring (DOM) data") +@click.option('--namespace', '-n', 'namespace', default=None, show_default=True, + type=click.Choice(multi_asic_util.multi_asic_ns_choices()), help='Namespace name or all') @click.option('--verbose', is_flag=True, help="Enable verbose output") -def eeprom(interfacename, dump_dom, verbose): +def eeprom(interfacename, dump_dom, namespace, verbose): """Show interface transceiver EEPROM information""" ctx = click.get_current_context() @@ -300,6 +302,9 @@ def eeprom(interfacename, dump_dom, verbose): cmd += " -p {}".format(interfacename) + if namespace is not None: + cmd += " -n {}".format(namespace) + clicommon.run_command(cmd, display_cmd=verbose) @transceiver.command() @@ -321,9 +326,11 @@ def lpmode(interfacename, verbose): @transceiver.command() @click.argument('interfacename', required=False) +@click.option('--namespace', '-n', 'namespace', default=None, show_default=True, + type=click.Choice(multi_asic_util.multi_asic_ns_choices()), help='Namespace name or all') @click.option('--verbose', is_flag=True, help="Enable verbose output") @clicommon.pass_db -def presence(db, interfacename, verbose): +def presence(db, interfacename, namespace, verbose): """Show interface transceiver presence""" ctx = click.get_current_context() @@ -335,6 +342,9 @@ def presence(db, interfacename, verbose): cmd += " -p {}".format(interfacename) + if namespace is not None: + cmd += " -n {}".format(namespace) + clicommon.run_command(cmd, display_cmd=verbose) diff --git a/tests/mock_tables/mock_multi_asic.py b/tests/mock_tables/mock_multi_asic.py index 79c8ebda1c7..a486e2ad479 100644 --- a/tests/mock_tables/mock_multi_asic.py +++ b/tests/mock_tables/mock_multi_asic.py @@ -1,6 +1,7 @@ # MONKEY PATCH!!! import mock from sonic_py_common import multi_asic +from utilities_common import multi_asic as multi_asic_util def mock_get_num_asics(): @@ -14,7 +15,10 @@ def mock_is_multi_asic(): def mock_get_namespace_list(namespace=None): return ['asic0', 'asic1'] +def mock_get_port_namespace(port): + return 'asic0' multi_asic.get_num_asics = mock_get_num_asics multi_asic.is_multi_asic = mock_is_multi_asic multi_asic.get_namespace_list = mock_get_namespace_list +multi_asic.get_port_namespace = mock_get_port_namespace diff --git a/tests/sfp_test.py b/tests/sfp_test.py index d7140968082..ae85c34fac9 100644 --- a/tests/sfp_test.py +++ b/tests/sfp_test.py @@ -86,6 +86,7 @@ def setup_class(cls): print("SETUP") os.environ["PATH"] += os.pathsep + scripts_path os.environ["UTILITIES_UNIT_TESTING"] = "2" + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic" def test_sfp_presence(self): runner = CliRunner() @@ -122,6 +123,52 @@ def test_sfp_eeprom(self): expected = "Ethernet200: SFP EEPROM Not detected" assert result_lines == expected + def test_sfp_presence_with_ns(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["presence"], ["Ethernet0 -n asic0"]) + expected = """Port Presence +--------- ---------- +Ethernet0 Present +""" + assert result.exit_code == 0 + assert result.output == expected + + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["presence"], ["Ethernet200 -n asic0"]) + expected = """Port Presence +----------- ----------- +Ethernet200 Not present +""" + assert result.exit_code == 0 + assert result.output == expected + + def test_sfp_eeprom_with_dom_with_ns(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"], ["Ethernet0 -d -n asic0"]) + assert result.exit_code == 0 + assert "\n".join([ l.rstrip() for l in result.output.split('\n')]) == test_sfp_eeprom_with_dom_output + + def test_sfp_eeprom_with_ns(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"], ["Ethernet0 -n asic0"]) + assert result.exit_code == 0 + assert "\n".join([ l.rstrip() for l in result.output.split('\n')]) == test_sfp_eeprom_output + + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"], ["Ethernet200 -n asic0"]) + result_lines = result.output.strip('\n') + expected = "Ethernet200: SFP EEPROM Not detected" + assert result_lines == expected + + def test_sfp_eeprom_with_ns(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"], ["Ethernet0 -n asic0"]) + assert result.exit_code == 0 + assert "\n".join([ l.rstrip() for l in result.output.split('\n')]) == test_sfp_eeprom_output + + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"], ["Ethernet200 -n asic0"]) + result_lines = result.output.strip('\n') + expected = "Ethernet200: SFP EEPROM Not detected" + assert result_lines == expected + @classmethod def teardown_class(cls): print("TEARDOWN") diff --git a/utilities_common/multi_asic.py b/utilities_common/multi_asic.py index 99096bb0b74..2174091c37d 100644 --- a/utilities_common/multi_asic.py +++ b/utilities_common/multi_asic.py @@ -3,8 +3,46 @@ import click from sonic_py_common import multi_asic +from swsssdk import ConfigDBConnector +from sonic_py_common.interface import get_port_table_name from utilities_common import constants +import utilities_common.cli as clicommon +def get_port_namespace(port): + ''' + Return the namespace where an interface belongs + The port name input could be in default mode or in alias mode. + ''' + + # In a non multi-asic platform, or it is mgmt interface, + # return DEFAULT_NAMESPACE + if not multi_asic.is_multi_asic() or port == 'eth0': + return DEFAULT_NAMESPACE + + # Get the table to check for interface presence + table_name = get_port_table_name(port) + if table_name == "": + return None + + ns_list = multi_asic.get_all_namespaces() + namespaces = ns_list['front_ns'] + ns_list['back_ns'] + for namespace in namespaces: + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + + # If the interface naming mode is alias, search the tables for alias_name. + if clicommon.get_interface_naming_mode() == "alias": + port_dict = config_db.get_table(table_name) + if port_dict: + for port_name in port_dict.keys(): + if port == port_dict[port_name]['alias']: + return namespace + else: + entry = config_db.get_entry(table_name, port) + if entry: + return namespace + + return None class MultiAsic(object): From 4de1197acc91903d2f62f552fe71da7bab34fd7f Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Sun, 30 Aug 2020 17:56:55 -0700 Subject: [PATCH 2/6] Updates to show command and testcases --- config/main.py | 34 ++++- scripts/sfpshow | 9 +- tests/mock_tables/asic0/state_db.json | 207 ++++++++++++++++++++++++++ tests/mock_tables/mock_multi_asic.py | 6 +- tests/multi_asic_intfutil_test.py | 58 ++++---- tests/sfp_test.py | 35 ++++- utilities_common/multi_asic.py | 39 ----- 7 files changed, 310 insertions(+), 78 deletions(-) create mode 100644 tests/mock_tables/asic0/state_db.json diff --git a/config/main.py b/config/main.py index 8ac1b8461fc..6f19f4de1a8 100755 --- a/config/main.py +++ b/config/main.py @@ -19,7 +19,6 @@ from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig from utilities_common.db import Db from utilities_common.intf_filter import parse_interface_in_filter -from utilities_common.multi_asic import get_port_namespace import utilities_common.cli as clicommon from .utils import log @@ -396,6 +395,39 @@ def is_interface_bind_to_vrf(config_db, interface_name): return True return False +# Return the namespace where an interface belongs +# The port name input could be in default mode or in alias mode. +def get_port_namespace(port): + # If it is a non multi-asic platform, or if the interface is management interface + # return DEFAULT_NAMESPACE + if not multi_asic.is_multi_asic() or port == 'eth0': + return DEFAULT_NAMESPACE + + # Get the table to check for interface presence + table_name = get_port_table_name(port) + if table_name == "": + return None + + ns_list = multi_asic.get_all_namespaces() + namespaces = ns_list['front_ns'] + ns_list['back_ns'] + for namespace in namespaces: + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + + # If the interface naming mode is alias, search the tables for alias_name. + if clicommon.get_interface_naming_mode() == "alias": + port_dict = config_db.get_table(table_name) + if port_dict: + for port_name in port_dict.keys(): + if port == port_dict[port_name]['alias']: + return namespace + else: + entry = config_db.get_entry(table_name, port) + if entry: + return namespace + + return None + def del_interface_bind_to_vrf(config_db, vrf_name): """del interface bind to vrf """ diff --git a/scripts/sfpshow b/scripts/sfpshow index 5437f579cdc..a5cfebbd140 100755 --- a/scripts/sfpshow +++ b/scripts/sfpshow @@ -15,6 +15,7 @@ from tabulate import tabulate from utilities_common import multi_asic as multi_asic_util from sonic_py_common.interface import front_panel_prefix, backplane_prefix +from sonic_py_common import multi_asic # Mock the redis for unit test purposes # try: @@ -368,8 +369,8 @@ def cli(): @click.option('-d', '--dom', 'dump_dom', is_flag=True, help="Also display Digital Optical Monitoring (DOM) data") @click.option('-n', '--namespace', default=None, help="Display interfaces for specific namespace") def eeprom(port, dump_dom, namespace): - if port: - ns = multi_asic_util.get_port_namespace(port) + if port and multi_asic.is_multi_asic(): + ns = multi_asic.get_namespace_for_port(port) if namespace is not None and ns != namespace: print("Error: Interface {} don't belong to this namespace {}".format(port, namespace)) return @@ -384,8 +385,8 @@ def eeprom(port, dump_dom, namespace): @click.option('-p', '--port', metavar='', help="Display SFP presence for port only") @click.option('-n', '--namespace', default=None, help="Display interfaces for specific namespace") def presence(port, namespace): - if port: - ns = multi_asic_util.get_port_namespace(port) + if port and multi_asic.is_multi_asic(): + ns = multi_asic.get_namespace_for_port(port) if namespace is not None and ns != namespace: print("Error: Interface {} don't belong to this namespace {}".format(port, namespace)) return diff --git a/tests/mock_tables/asic0/state_db.json b/tests/mock_tables/asic0/state_db.json new file mode 100644 index 00000000000..07939bc0078 --- /dev/null +++ b/tests/mock_tables/asic0/state_db.json @@ -0,0 +1,207 @@ +{ + "TRANSCEIVER_INFO|Ethernet0": { + "type": "QSFP28 or later", + "hardware_rev": "AC", + "serial": "MT1706FT02064", + "manufacturer": "Mellanox", + "model": "MFA1A00-C003", + "vendor_oui": "00-02-c9", + "vendor_date": "2017-01-13 ", + "connector": "No separable connector", + "encoding": "64B66B", + "ext_identifier": "Power Class 3(2.5W max), CDR present in Rx Tx", + "ext_rateselect_compliance": "QSFP+ Rate Select Version 1", + "cable_type": "Length Cable Assembly(m)", + "cable_length": "3", + "specification_compliance": "{'10/40G Ethernet Compliance Code': '40G Active Cable (XLPPI)'}", + "nominal_bit_rate": "255", + "application_advertisement": "N/A" + }, + "TRANSCEIVER_DOM_SENSOR|Ethernet0": { + "temperature": "30.9258", + "voltage": "3.2824", + "rx1power": "0.3802", + "rx2power": "-0.4871", + "rx3power": "-0.0860", + "rx4power": "0.3830", + "tx1bias": "6.7500", + "tx2bias": "6.7500", + "tx3bias": "6.7500", + "tx4bias": "6.7500", + "tx1power": "N/A", + "tx2power": "N/A", + "tx3power": "N/A", + "tx4power": "N/A", + "rxpowerhighalarm": "3.4001", + "rxpowerhighwarning": "2.4000", + "rxpowerlowalarm": "-13.5067", + "rxpowerlowwarning": "-9.5001", + "txbiashighalarm": "10.0000", + "txbiashighwarning": "9.5000", + "txbiaslowalarm": "0.5000", + "txbiaslowwarning": "1.0000", + "temphighalarm": "75.0000", + "temphighwarning": "70.0000", + "templowalarm": "-5.0000", + "templowwarning": "0.0000", + "vcchighalarm": "3.6300", + "vcchighwarning": "3.4650", + "vcclowalarm": "2.9700", + "vcclowwarning": "3.1349" + }, + "CHASSIS_INFO|chassis 1": { + "psu_num": "2" + }, + "PSU_INFO|PSU 1": { + "presence": "true", + "status": "true", + "led_status": "green" + }, + "PSU_INFO|PSU 2": { + "presence": "true", + "status": "true", + "led_status": "green" + }, + "SWITCH_CAPABILITY|switch": { + "MIRROR": "true", + "MIRRORV6": "true", + "ACL_ACTIONS|INGRESS": "PACKET_ACTION,REDIRECT_ACTION,MIRROR_INGRESS_ACTION", + "ACL_ACTIONS|EGRESS": "PACKET_ACTION,MIRROR_EGRESS_ACTION", + "ACL_ACTION|PACKET_ACTION": "FORWARD" + }, + "DEBUG_COUNTER_CAPABILITIES|PORT_INGRESS_DROPS": { + "reasons": "[IP_HEADER_ERROR,NO_L3_HEADER]", + "count": "4" + }, + "DEBUG_COUNTER_CAPABILITIES|SWITCH_EGRESS_DROPS": { + "reasons": "[ACL_ANY,L2_ANY,L3_ANY]", + "count": "2" + }, + "LAG_MEMBER_TABLE|PortChannel0001|Ethernet112": { + "runner.actor_lacpdu_info.state": "5", + "runner.state": "disabled", + "runner.partner_lacpdu_info.port": "0", + "runner.actor_lacpdu_info.port": "113", + "runner.selected": "false", + "runner.partner_lacpdu_info.state": "0", + "ifinfo.dev_addr": "52:54:00:f2:e1:23", + "runner.partner_lacpdu_info.system": "00:00:00:00:00:00", + "link_watches.list.link_watch_0.up": "false", + "runner.actor_lacpdu_info.system": "52:54:00:f2:e1:23", + "runner.aggregator.selected": "false", + "runner.aggregator.id": "0", + "link.up": "false", + "ifinfo.ifindex": "98" + }, + "LAG_MEMBER_TABLE|PortChannel0002|Ethernet116": { + "runner.actor_lacpdu_info.state": "61", + "runner.state": "current", + "runner.partner_lacpdu_info.port": "1", + "runner.actor_lacpdu_info.port": "117", + "runner.selected": "true", + "runner.partner_lacpdu_info.state": "61", + "ifinfo.dev_addr": "52:54:00:f2:e1:23", + "runner.partner_lacpdu_info.system": "1e:af:77:fc:79:ee", + "link_watches.list.link_watch_0.up": "false", + "runner.actor_lacpdu_info.system": "52:54:00:f2:e1:23", + "runner.aggregator.selected": "true", + "runner.aggregator.id": "97", + "link.up": "true", + "ifinfo.ifindex": "97" + }, + "LAG_MEMBER_TABLE|PortChannel0003|Ethernet120": { + "runner.actor_lacpdu_info.state": "61", + "runner.state": "current", + "runner.partner_lacpdu_info.port": "1", + "runner.actor_lacpdu_info.port": "121", + "runner.selected": "true", + "runner.partner_lacpdu_info.state": "61", + "ifinfo.dev_addr": "52:54:00:f2:e1:23", + "runner.partner_lacpdu_info.system": "16:0e:58:6f:3c:dd", + "link_watches.list.link_watch_0.up": "false", + "runner.actor_lacpdu_info.system": "52:54:00:f2:e1:23", + "runner.aggregator.selected": "true", + "runner.aggregator.id": "100", + "link.up": "true", + "ifinfo.ifindex": "100" + }, + "LAG_TABLE|PortChannel0001": { + "runner.fallback": "false", + "team_device.ifinfo.dev_addr": "52:54:00:f2:e1:23", + "team_device.ifinfo.ifindex": "71", + "setup.pid": "32", + "state": "ok", + "runner.fast_rate": "false", + "setup.kernel_team_mode_name": "loadbalance", + "runner.active": "true" + }, + "LAG_TABLE|PortChannel0002": { + "runner.fallback": "false", + "team_device.ifinfo.dev_addr": "52:54:00:f2:e1:23", + "team_device.ifinfo.ifindex": "72", + "setup.pid": "40", + "state": "ok", + "runner.fast_rate": "false", + "setup.kernel_team_mode_name": "loadbalance", + "runner.active": "true" + }, + "LAG_TABLE|PortChannel0003": { + "runner.fallback": "false", + "team_device.ifinfo.dev_addr": "52:54:00:f2:e1:23", + "team_device.ifinfo.ifindex": "73", + "setup.pid": "48", + "state": "ok", + "runner.fast_rate": "false", + "setup.kernel_team_mode_name": "loadbalance", + "runner.active": "true" + }, + "LAG_TABLE|PortChannel0004": { + "runner.fallback": "false", + "team_device.ifinfo.dev_addr": "52:54:00:f2:e1:23", + "team_device.ifinfo.ifindex": "74", + "setup.pid": "56", + "state": "ok", + "runner.fast_rate": "false", + "setup.kernel_team_mode_name": "loadbalance", + "runner.active": "true" + }, + "FAN_INFO|fan1": { + "drawer_name": "drawer1", + "presence": "True", + "model": "N/A", + "serial": "N/A", + "status": "True", + "direction": "intake", + "speed": "30", + "speed_tolerance": "50", + "speed_target": "20", + "led_status": "red", + "timestamp": "20200813 01:32:30" + }, + "FAN_INFO|fan2": { + "drawer_name": "drawer2", + "presence": "True", + "model": "N/A", + "serial": "N/A", + "status": "False", + "direction": "intake", + "speed": "50", + "speed_tolerance": "50", + "speed_target": "50", + "led_status": "green", + "timestamp": "20200813 01:32:30" + }, + "FAN_INFO|fan3": { + "drawer_name": "drawer3", + "presence": "True", + "model": "N/A", + "serial": "N/A", + "status": "Updating", + "direction": "intake", + "speed": "50", + "speed_tolerance": "50", + "speed_target": "50", + "led_status": "green", + "timestamp": "20200813 01:32:30" + } +} diff --git a/tests/mock_tables/mock_multi_asic.py b/tests/mock_tables/mock_multi_asic.py index a486e2ad479..17d836f56f8 100644 --- a/tests/mock_tables/mock_multi_asic.py +++ b/tests/mock_tables/mock_multi_asic.py @@ -1,8 +1,6 @@ # MONKEY PATCH!!! import mock from sonic_py_common import multi_asic -from utilities_common import multi_asic as multi_asic_util - def mock_get_num_asics(): return 2 @@ -15,10 +13,10 @@ def mock_is_multi_asic(): def mock_get_namespace_list(namespace=None): return ['asic0', 'asic1'] -def mock_get_port_namespace(port): +def mock_get_namespace_for_port(port): return 'asic0' multi_asic.get_num_asics = mock_get_num_asics multi_asic.is_multi_asic = mock_is_multi_asic multi_asic.get_namespace_list = mock_get_namespace_list -multi_asic.get_port_namespace = mock_get_port_namespace +multi_asic.get_namespace_for_port = mock_get_namespace_for_port diff --git a/tests/multi_asic_intfutil_test.py b/tests/multi_asic_intfutil_test.py index da1875e7dd6..52870dd316f 100644 --- a/tests/multi_asic_intfutil_test.py +++ b/tests/multi_asic_intfutil_test.py @@ -10,43 +10,43 @@ scripts_path = os.path.join(modules_path, "scripts") intf_status_all = """\ - Interface Lanes Speed MTU FEC Alias Vlan Oper Admin Type Asym PFC ---------------- ------------ ------- ----- ----- -------------- --------------- ------ ------- ------ ---------- - Ethernet0 33,34,35,36 40G 9100 N/A Ethernet1/1 PortChannel1002 up up N/A off - Ethernet4 29,30,31,32 40G 9100 N/A Ethernet1/2 PortChannel1002 up up N/A off - Ethernet-BP0 93,94,95,96 40G 9100 N/A Ethernet-BP0 PortChannel4001 up up N/A off - Ethernet-BP4 97,98,99,100 40G 9100 N/A Ethernet-BP4 PortChannel4001 up up N/A off - Ethernet-BP256 61,62,63,64 40G 9100 N/A Ethernet-BP256 PortChannel4009 up up N/A off - Ethernet-BP260 57,58,59,60 40G 9100 N/A Ethernet-BP260 PortChannel4009 up up N/A off -PortChannel1002 N/A 80G 9100 N/A N/A routed up up N/A N/A -PortChannel4001 N/A 80G 9100 N/A N/A routed up up N/A N/A -PortChannel4009 N/A 80G 9100 N/A N/A routed up up N/A N/A + Interface Lanes Speed MTU FEC Alias Vlan Oper Admin Type Asym PFC +--------------- ------------ ------- ----- ----- -------------- --------------- ------ ------- --------------- ---------- + Ethernet0 33,34,35,36 40G 9100 N/A Ethernet1/1 PortChannel1002 up up QSFP28 or later off + Ethernet4 29,30,31,32 40G 9100 N/A Ethernet1/2 PortChannel1002 up up N/A off + Ethernet-BP0 93,94,95,96 40G 9100 N/A Ethernet-BP0 PortChannel4001 up up N/A off + Ethernet-BP4 97,98,99,100 40G 9100 N/A Ethernet-BP4 PortChannel4001 up up N/A off + Ethernet-BP256 61,62,63,64 40G 9100 N/A Ethernet-BP256 PortChannel4009 up up N/A off + Ethernet-BP260 57,58,59,60 40G 9100 N/A Ethernet-BP260 PortChannel4009 up up N/A off +PortChannel1002 N/A 80G 9100 N/A N/A routed up up N/A N/A +PortChannel4001 N/A 80G 9100 N/A N/A routed up up N/A N/A +PortChannel4009 N/A 80G 9100 N/A N/A routed up up N/A N/A """ intf_status = """\ - Interface Lanes Speed MTU FEC Alias Vlan Oper Admin Type Asym PFC ---------------- ----------- ------- ----- ----- ----------- --------------- ------ ------- ------ ---------- - Ethernet0 33,34,35,36 40G 9100 N/A Ethernet1/1 PortChannel1002 up up N/A off - Ethernet4 29,30,31,32 40G 9100 N/A Ethernet1/2 PortChannel1002 up up N/A off -PortChannel1002 N/A 80G 9100 N/A N/A routed up up N/A N/A + Interface Lanes Speed MTU FEC Alias Vlan Oper Admin Type Asym PFC +--------------- ----------- ------- ----- ----- ----------- --------------- ------ ------- --------------- ---------- + Ethernet0 33,34,35,36 40G 9100 N/A Ethernet1/1 PortChannel1002 up up QSFP28 or later off + Ethernet4 29,30,31,32 40G 9100 N/A Ethernet1/2 PortChannel1002 up up N/A off +PortChannel1002 N/A 80G 9100 N/A N/A routed up up N/A N/A """ intf_status_asic0 = """\ - Interface Lanes Speed MTU FEC Alias Vlan Oper Admin Type Asym PFC ---------------- ----------- ------- ----- ----- ----------- --------------- ------ ------- ------ ---------- - Ethernet0 33,34,35,36 40G 9100 N/A Ethernet1/1 PortChannel1002 up up N/A off - Ethernet4 29,30,31,32 40G 9100 N/A Ethernet1/2 PortChannel1002 up up N/A off -PortChannel1002 N/A 80G 9100 N/A N/A routed up up N/A N/A + Interface Lanes Speed MTU FEC Alias Vlan Oper Admin Type Asym PFC +--------------- ----------- ------- ----- ----- ----------- --------------- ------ ------- --------------- ---------- + Ethernet0 33,34,35,36 40G 9100 N/A Ethernet1/1 PortChannel1002 up up QSFP28 or later off + Ethernet4 29,30,31,32 40G 9100 N/A Ethernet1/2 PortChannel1002 up up N/A off +PortChannel1002 N/A 80G 9100 N/A N/A routed up up N/A N/A """ intf_status_asic0_all = """\ - Interface Lanes Speed MTU FEC Alias Vlan Oper Admin Type Asym PFC ---------------- ------------ ------- ----- ----- ------------ --------------- ------ ------- ------ ---------- - Ethernet0 33,34,35,36 40G 9100 N/A Ethernet1/1 PortChannel1002 up up N/A off - Ethernet4 29,30,31,32 40G 9100 N/A Ethernet1/2 PortChannel1002 up up N/A off - Ethernet-BP0 93,94,95,96 40G 9100 N/A Ethernet-BP0 PortChannel4001 up up N/A off - Ethernet-BP4 97,98,99,100 40G 9100 N/A Ethernet-BP4 PortChannel4001 up up N/A off -PortChannel1002 N/A 80G 9100 N/A N/A routed up up N/A N/A -PortChannel4001 N/A 80G 9100 N/A N/A routed up up N/A N/A + Interface Lanes Speed MTU FEC Alias Vlan Oper Admin Type Asym PFC +--------------- ------------ ------- ----- ----- ------------ --------------- ------ ------- --------------- ---------- + Ethernet0 33,34,35,36 40G 9100 N/A Ethernet1/1 PortChannel1002 up up QSFP28 or later off + Ethernet4 29,30,31,32 40G 9100 N/A Ethernet1/2 PortChannel1002 up up N/A off + Ethernet-BP0 93,94,95,96 40G 9100 N/A Ethernet-BP0 PortChannel4001 up up N/A off + Ethernet-BP4 97,98,99,100 40G 9100 N/A Ethernet-BP4 PortChannel4001 up up N/A off +PortChannel1002 N/A 80G 9100 N/A N/A routed up up N/A N/A +PortChannel4001 N/A 80G 9100 N/A N/A routed up up N/A N/A """ intf_description = """\ Interface Oper Admin Alias Description diff --git a/tests/sfp_test.py b/tests/sfp_test.py index ae85c34fac9..6ad611f3821 100644 --- a/tests/sfp_test.py +++ b/tests/sfp_test.py @@ -86,7 +86,6 @@ def setup_class(cls): print("SETUP") os.environ["PATH"] += os.pathsep + scripts_path os.environ["UTILITIES_UNIT_TESTING"] = "2" - os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic" def test_sfp_presence(self): runner = CliRunner() @@ -137,6 +136,39 @@ def test_sfp_presence_with_ns(self): expected = """Port Presence ----------- ----------- Ethernet200 Not present +""" + assert result.exit_code == 0 + assert result.output == expected + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1]) + os.environ["UTILITIES_UNIT_TESTING"] = "0" + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "" + +class Test_multiAsic_SFP(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["PATH"] += os.pathsep + scripts_path + os.environ["UTILITIES_UNIT_TESTING"] = "2" + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic" + + def test_sfp_presence_with_ns(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["presence"], ["Ethernet0 -n asic0"]) + expected = """Port Presence +--------- ---------- +Ethernet0 Present +""" + assert result.exit_code == 0 + assert result.output == expected + + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["presence"], ["Ethernet200 -n asic0"]) + expected = """Port Presence +----------- ----------- +Ethernet200 Not present """ assert result.exit_code == 0 assert result.output == expected @@ -174,3 +206,4 @@ def teardown_class(cls): print("TEARDOWN") os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1]) os.environ["UTILITIES_UNIT_TESTING"] = "0" + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "" diff --git a/utilities_common/multi_asic.py b/utilities_common/multi_asic.py index 2174091c37d..55e7f342770 100644 --- a/utilities_common/multi_asic.py +++ b/utilities_common/multi_asic.py @@ -3,46 +3,7 @@ import click from sonic_py_common import multi_asic -from swsssdk import ConfigDBConnector -from sonic_py_common.interface import get_port_table_name from utilities_common import constants -import utilities_common.cli as clicommon - -def get_port_namespace(port): - ''' - Return the namespace where an interface belongs - The port name input could be in default mode or in alias mode. - ''' - - # In a non multi-asic platform, or it is mgmt interface, - # return DEFAULT_NAMESPACE - if not multi_asic.is_multi_asic() or port == 'eth0': - return DEFAULT_NAMESPACE - - # Get the table to check for interface presence - table_name = get_port_table_name(port) - if table_name == "": - return None - - ns_list = multi_asic.get_all_namespaces() - namespaces = ns_list['front_ns'] + ns_list['back_ns'] - for namespace in namespaces: - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() - - # If the interface naming mode is alias, search the tables for alias_name. - if clicommon.get_interface_naming_mode() == "alias": - port_dict = config_db.get_table(table_name) - if port_dict: - for port_name in port_dict.keys(): - if port == port_dict[port_name]['alias']: - return namespace - else: - entry = config_db.get_entry(table_name, port) - if entry: - return namespace - - return None class MultiAsic(object): From 98f145f40cd3c995229b26549bb5b6ce39002023 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Sun, 30 Aug 2020 18:07:48 -0700 Subject: [PATCH 3/6] Remove unused import --- scripts/sfpshow | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/sfpshow b/scripts/sfpshow index a5cfebbd140..15cf2aa0876 100755 --- a/scripts/sfpshow +++ b/scripts/sfpshow @@ -10,7 +10,6 @@ import operator import os from natsort import natsorted -from swsssdk import SonicV2Connector from tabulate import tabulate from utilities_common import multi_asic as multi_asic_util From 83d583263fd5020a3a18c2348543bf84e162b25a Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Mon, 31 Aug 2020 08:42:14 -0700 Subject: [PATCH 4/6] Updates to take care of API relocation to sonic-py-common --- config/main.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/config/main.py b/config/main.py index 6f19f4de1a8..b62f0e35c9d 100755 --- a/config/main.py +++ b/config/main.py @@ -15,7 +15,7 @@ from minigraph import parse_device_desc_xml from portconfig import get_child_ports from sonic_py_common import device_info, multi_asic -from sonic_py_common.interface import get_interface_table_name +from sonic_py_common.interface import get_interface_table_name, get_port_table_name from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig from utilities_common.db import Db from utilities_common.intf_filter import parse_interface_in_filter @@ -264,18 +264,6 @@ def _get_device_type(): return device_type -# TODO move to sonic-py-common package -# Validate whether a given namespace name is valid in the device. -def validate_namespace(namespace): - if not multi_asic.is_multi_asic(): - return True - - namespaces = multi_asic.get_all_namespaces() - if namespace in namespaces['front_ns'] + namespaces['back_ns']: - return True - else: - return False - def interface_alias_to_name(config_db, interface_alias): """Return default interface name if alias name is given as argument """ From 82e9b7b54495f393641b7129b4e379411d7d8ff6 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Wed, 2 Sep 2020 14:39:15 -0700 Subject: [PATCH 5/6] Updates to tests to cover more scenario's and take care of review comments. --- scripts/sfpshow | 35 +++-- tests/mock_tables/asic1/appl_db.json | 14 +- tests/mock_tables/asic1/config_db.json | 13 +- tests/mock_tables/mock_multi_asic.py | 4 - tests/multi_asic_intfutil_test.py | 2 + tests/sfp_test.py | 184 ++++++++++++++++++++++--- utilities_common/multi_asic.py | 1 + 7 files changed, 216 insertions(+), 37 deletions(-) diff --git a/scripts/sfpshow b/scripts/sfpshow index 15cf2aa0876..1875e832c5b 100755 --- a/scripts/sfpshow +++ b/scripts/sfpshow @@ -132,7 +132,15 @@ dom_value_unit_map = {'rx1power': 'dBm', 'rx2power': 'dBm', 'tx3power': 'dBm', 'tx4power': 'dBm', 'temperature': 'C', 'voltage': 'Volts'} +def display_invalid_intf_eeprom(intf_name): + output = intf_name + ': ' + 'SFP EEPROM Not detected' + '\n' + click.echo(output) +def display_invalid_intf_presence(intf_name): + header = ['Port', 'Presence'] + port_table = [] + port_table.append((intf_name, 'Not present')) + click.echo(tabulate(port_table, header)) class SFPShow(object): @@ -311,7 +319,6 @@ class SFPShow(object): else: port_table_keys = self.db.keys(self.db.APPL_DB, "PORT_TABLE:*") sorted_table_keys = natsorted(port_table_keys) - print(self.multi_asic.current_namespace) for i in sorted_table_keys: interface = re.split(':', i, maxsplit=1)[-1].strip() if interface and interface.startswith(front_panel_prefix()) and not interface.startswith(backplane_prefix()): @@ -368,12 +375,13 @@ def cli(): @click.option('-d', '--dom', 'dump_dom', is_flag=True, help="Also display Digital Optical Monitoring (DOM) data") @click.option('-n', '--namespace', default=None, help="Display interfaces for specific namespace") def eeprom(port, dump_dom, namespace): - if port and multi_asic.is_multi_asic(): - ns = multi_asic.get_namespace_for_port(port) - if namespace is not None and ns != namespace: - print("Error: Interface {} don't belong to this namespace {}".format(port, namespace)) - return - namespace=ns + if port and multi_asic.is_multi_asic() and namespace is None: + try: + ns = multi_asic.get_namespace_for_port(port) + namespace=ns + except Exception: + display_invalid_intf_eeprom(port) + sys.exit(1) sfp = SFPShow(port, namespace, dump_dom) sfp.get_eeprom() @@ -384,12 +392,13 @@ def eeprom(port, dump_dom, namespace): @click.option('-p', '--port', metavar='', help="Display SFP presence for port only") @click.option('-n', '--namespace', default=None, help="Display interfaces for specific namespace") def presence(port, namespace): - if port and multi_asic.is_multi_asic(): - ns = multi_asic.get_namespace_for_port(port) - if namespace is not None and ns != namespace: - print("Error: Interface {} don't belong to this namespace {}".format(port, namespace)) - return - namespace=ns + if port and multi_asic.is_multi_asic() and namespace is None: + try: + ns = multi_asic.get_namespace_for_port(port) + namespace=ns + except Exception: + display_invalid_intf_presence(port) + sys.exit(1) sfp = SFPShow(port, namespace) sfp.get_presence() diff --git a/tests/mock_tables/asic1/appl_db.json b/tests/mock_tables/asic1/appl_db.json index f5f67b26ce9..3ac977cb02e 100644 --- a/tests/mock_tables/asic1/appl_db.json +++ b/tests/mock_tables/asic1/appl_db.json @@ -1,4 +1,16 @@ { + "PORT_TABLE:Ethernet64": { + "oper_status": "up", + "lanes": "29,30,31,32", + "description": "ARISTA01T2:Ethernet3/2/1", + "pfc_asym": "off", + "mtu": "9100", + "alias": "Ethernet1/17", + "admin_status": "up", + "role": "Ext", + "speed": "40000", + "asic_port_name": "Eth0-ASIC1" + }, "PORT_TABLE:Ethernet-BP256": { "oper_status": "up", "lanes": "61,62,63,64", @@ -32,4 +44,4 @@ "LAG_MEMBER_TABLE:PortChannel4009:Ethernet-BP260": { "status": "enabled" } -} \ No newline at end of file +} diff --git a/tests/mock_tables/asic1/config_db.json b/tests/mock_tables/asic1/config_db.json index c8f97c5df19..bdcca2dcfe3 100644 --- a/tests/mock_tables/asic1/config_db.json +++ b/tests/mock_tables/asic1/config_db.json @@ -16,6 +16,17 @@ "sub_role": "BackEnd", "type": "LeafRouter" }, + "PORT|Ethernet64": { + "admin_status": "up", + "alias": "Ethernet1/17", + "asic_port_name": "Eth0-ASIC1", + "description": "ARISTA01T2:Ethernet3/1/1", + "lanes": "33,34,35,36", + "mtu": "9100", + "pfc_asym": "off", + "role": "Ext", + "speed": "40000" + }, "PORT|Ethernet-BP256": { "admin_status": "up", "alias": "Ethernet-BP256", @@ -52,4 +63,4 @@ "PORTCHANNEL_MEMBER|PortChannel4009|Ethernet-BP260" : { "NULL": "NULL" } -} \ No newline at end of file +} diff --git a/tests/mock_tables/mock_multi_asic.py b/tests/mock_tables/mock_multi_asic.py index 17d836f56f8..80102482165 100644 --- a/tests/mock_tables/mock_multi_asic.py +++ b/tests/mock_tables/mock_multi_asic.py @@ -13,10 +13,6 @@ def mock_is_multi_asic(): def mock_get_namespace_list(namespace=None): return ['asic0', 'asic1'] -def mock_get_namespace_for_port(port): - return 'asic0' - multi_asic.get_num_asics = mock_get_num_asics multi_asic.is_multi_asic = mock_is_multi_asic multi_asic.get_namespace_list = mock_get_namespace_list -multi_asic.get_namespace_for_port = mock_get_namespace_for_port diff --git a/tests/multi_asic_intfutil_test.py b/tests/multi_asic_intfutil_test.py index 52870dd316f..2abe4663f49 100644 --- a/tests/multi_asic_intfutil_test.py +++ b/tests/multi_asic_intfutil_test.py @@ -14,6 +14,7 @@ --------------- ------------ ------- ----- ----- -------------- --------------- ------ ------- --------------- ---------- Ethernet0 33,34,35,36 40G 9100 N/A Ethernet1/1 PortChannel1002 up up QSFP28 or later off Ethernet4 29,30,31,32 40G 9100 N/A Ethernet1/2 PortChannel1002 up up N/A off + Ethernet64 29,30,31,32 40G 9100 N/A Ethernet1/17 routed up up QSFP28 or later off Ethernet-BP0 93,94,95,96 40G 9100 N/A Ethernet-BP0 PortChannel4001 up up N/A off Ethernet-BP4 97,98,99,100 40G 9100 N/A Ethernet-BP4 PortChannel4001 up up N/A off Ethernet-BP256 61,62,63,64 40G 9100 N/A Ethernet-BP256 PortChannel4009 up up N/A off @@ -60,6 +61,7 @@ -------------- ------ ------- -------------- ------------------------ Ethernet0 up up Ethernet1/1 ARISTA01T2:Ethernet3/1/1 Ethernet4 up up Ethernet1/2 ARISTA01T2:Ethernet3/2/1 + Ethernet64 up up Ethernet1/17 ARISTA01T2:Ethernet3/2/1 Ethernet-BP0 up up Ethernet-BP0 ASIC1:Eth0-ASIC1 Ethernet-BP4 up up Ethernet-BP4 ASIC1:Eth1-ASIC1 Ethernet-BP256 up up Ethernet-BP256 ASIC0:Eth16-ASIC0 diff --git a/tests/sfp_test.py b/tests/sfp_test.py index 6ad611f3821..1c81ad5051e 100644 --- a/tests/sfp_test.py +++ b/tests/sfp_test.py @@ -80,6 +80,154 @@ Vendor SN: MT1706FT02064 """ +test_sfp_eeprom_dom_all_output = """\ +Ethernet0: SFP EEPROM detected + Application Advertisement: N/A + Connector: No separable connector + Encoding: 64B66B + Extended Identifier: Power Class 3(2.5W max), CDR present in Rx Tx + Extended RateSelect Compliance: QSFP+ Rate Select Version 1 + Identifier: QSFP28 or later + Length Cable Assembly(m): 3 + Nominal Bit Rate(100Mbs): 255 + Specification compliance: + 10/40G Ethernet Compliance Code: 40G Active Cable (XLPPI) + Vendor Date Code(YYYY-MM-DD Lot): 2017-01-13 + Vendor Name: Mellanox + Vendor OUI: 00-02-c9 + Vendor PN: MFA1A00-C003 + Vendor Rev: AC + Vendor SN: MT1706FT02064 + ChannelMonitorValues: + RX1Power: 0.3802dBm + RX2Power: -0.4871dBm + RX3Power: -0.0860dBm + RX4Power: 0.3830dBm + TX1Bias: 6.7500mA + TX2Bias: 6.7500mA + TX3Bias: 6.7500mA + TX4Bias: 6.7500mA + ChannelThresholdValues: + RxPowerHighAlarm : 3.4001dBm + RxPowerHighWarning: 2.4000dBm + RxPowerLowAlarm : -13.5067dBm + RxPowerLowWarning : -9.5001dBm + TxBiasHighAlarm : 10.0000mA + TxBiasHighWarning : 9.5000mA + TxBiasLowAlarm : 0.5000mA + TxBiasLowWarning : 1.0000mA + ModuleMonitorValues: + Temperature: 30.9258C + Vcc: 3.2824Volts + ModuleThresholdValues: + TempHighAlarm : 75.0000C + TempHighWarning: 70.0000C + TempLowAlarm : -5.0000C + TempLowWarning : 0.0000C + VccHighAlarm : 3.6300Volts + VccHighWarning : 3.4650Volts + VccLowAlarm : 2.9700Volts + VccLowWarning : 3.1349Volts + +Ethernet4: SFP EEPROM Not detected + +Ethernet64: SFP EEPROM detected + Application Advertisement: N/A + Connector: No separable connector + Encoding: 64B66B + Extended Identifier: Power Class 3(2.5W max), CDR present in Rx Tx + Extended RateSelect Compliance: QSFP+ Rate Select Version 1 + Identifier: QSFP28 or later + Length Cable Assembly(m): 3 + Nominal Bit Rate(100Mbs): 255 + Specification compliance: + 10/40G Ethernet Compliance Code: 40G Active Cable (XLPPI) + Vendor Date Code(YYYY-MM-DD Lot): 2017-01-13 + Vendor Name: Mellanox + Vendor OUI: 00-02-c9 + Vendor PN: MFA1A00-C003 + Vendor Rev: AC + Vendor SN: MT1706FT02064 + ChannelMonitorValues: + RX1Power: 0.3802dBm + RX2Power: -0.4871dBm + RX3Power: -0.0860dBm + RX4Power: 0.3830dBm + TX1Bias: 6.7500mA + TX2Bias: 6.7500mA + TX3Bias: 6.7500mA + TX4Bias: 6.7500mA + ChannelThresholdValues: + RxPowerHighAlarm : 3.4001dBm + RxPowerHighWarning: 2.4000dBm + RxPowerLowAlarm : -13.5067dBm + RxPowerLowWarning : -9.5001dBm + TxBiasHighAlarm : 10.0000mA + TxBiasHighWarning : 9.5000mA + TxBiasLowAlarm : 0.5000mA + TxBiasLowWarning : 1.0000mA + ModuleMonitorValues: + Temperature: 30.9258C + Vcc: 3.2824Volts + ModuleThresholdValues: + TempHighAlarm : 75.0000C + TempHighWarning: 70.0000C + TempLowAlarm : -5.0000C + TempLowWarning : 0.0000C + VccHighAlarm : 3.6300Volts + VccHighWarning : 3.4650Volts + VccLowAlarm : 2.9700Volts + VccLowWarning : 3.1349Volts +""" + +test_sfp_eeprom_all_output = """\ +Ethernet0: SFP EEPROM detected + Application Advertisement: N/A + Connector: No separable connector + Encoding: 64B66B + Extended Identifier: Power Class 3(2.5W max), CDR present in Rx Tx + Extended RateSelect Compliance: QSFP+ Rate Select Version 1 + Identifier: QSFP28 or later + Length Cable Assembly(m): 3 + Nominal Bit Rate(100Mbs): 255 + Specification compliance: + 10/40G Ethernet Compliance Code: 40G Active Cable (XLPPI) + Vendor Date Code(YYYY-MM-DD Lot): 2017-01-13 + Vendor Name: Mellanox + Vendor OUI: 00-02-c9 + Vendor PN: MFA1A00-C003 + Vendor Rev: AC + Vendor SN: MT1706FT02064 + +Ethernet4: SFP EEPROM Not detected + +Ethernet64: SFP EEPROM detected + Application Advertisement: N/A + Connector: No separable connector + Encoding: 64B66B + Extended Identifier: Power Class 3(2.5W max), CDR present in Rx Tx + Extended RateSelect Compliance: QSFP+ Rate Select Version 1 + Identifier: QSFP28 or later + Length Cable Assembly(m): 3 + Nominal Bit Rate(100Mbs): 255 + Specification compliance: + 10/40G Ethernet Compliance Code: 40G Active Cable (XLPPI) + Vendor Date Code(YYYY-MM-DD Lot): 2017-01-13 + Vendor Name: Mellanox + Vendor OUI: 00-02-c9 + Vendor PN: MFA1A00-C003 + Vendor Rev: AC + Vendor SN: MT1706FT02064 +""" + +test_sfp_presence_all_output = """\ +Port Presence +---------- ----------- +Ethernet0 Present +Ethernet4 Not present +Ethernet64 Present +""" + class TestSFP(object): @classmethod def setup_class(cls): @@ -122,24 +270,6 @@ def test_sfp_eeprom(self): expected = "Ethernet200: SFP EEPROM Not detected" assert result_lines == expected - def test_sfp_presence_with_ns(self): - runner = CliRunner() - result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["presence"], ["Ethernet0 -n asic0"]) - expected = """Port Presence ---------- ---------- -Ethernet0 Present -""" - assert result.exit_code == 0 - assert result.output == expected - - result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["presence"], ["Ethernet200 -n asic0"]) - expected = """Port Presence ------------ ----------- -Ethernet200 Not present -""" - assert result.exit_code == 0 - assert result.output == expected - @classmethod def teardown_class(cls): print("TEARDOWN") @@ -173,6 +303,12 @@ def test_sfp_presence_with_ns(self): assert result.exit_code == 0 assert result.output == expected + def test_sfp_presence_all(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["presence"]) + assert result.exit_code == 0 + assert "\n".join([ l.rstrip() for l in result.output.split('\n')]) == test_sfp_presence_all_output + def test_sfp_eeprom_with_dom_with_ns(self): runner = CliRunner() result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"], ["Ethernet0 -d -n asic0"]) @@ -201,6 +337,18 @@ def test_sfp_eeprom_with_ns(self): expected = "Ethernet200: SFP EEPROM Not detected" assert result_lines == expected + def test_sfp_eeprom_all(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"]) + assert result.exit_code == 0 + assert "\n".join([ l.rstrip() for l in result.output.split('\n')]) == test_sfp_eeprom_all_output + + def test_sfp_eeprom_dom_all(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["interfaces"].commands["transceiver"].commands["eeprom"], ["-d"]) + assert result.exit_code == 0 + assert "\n".join([ l.rstrip() for l in result.output.split('\n')]) == test_sfp_eeprom_dom_all_output + @classmethod def teardown_class(cls): print("TEARDOWN") diff --git a/utilities_common/multi_asic.py b/utilities_common/multi_asic.py index 55e7f342770..99096bb0b74 100644 --- a/utilities_common/multi_asic.py +++ b/utilities_common/multi_asic.py @@ -5,6 +5,7 @@ from sonic_py_common import multi_asic from utilities_common import constants + class MultiAsic(object): def __init__(self, display_option=constants.DISPLAY_ALL, From c93ebc398b826eb915ce7f3cf8091ba7ce24a2cb Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Wed, 2 Sep 2020 14:46:26 -0700 Subject: [PATCH 6/6] Adding a missed test json file created newly. --- tests/mock_tables/asic1/state_db.json | 207 ++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 tests/mock_tables/asic1/state_db.json diff --git a/tests/mock_tables/asic1/state_db.json b/tests/mock_tables/asic1/state_db.json new file mode 100644 index 00000000000..1e748a539d8 --- /dev/null +++ b/tests/mock_tables/asic1/state_db.json @@ -0,0 +1,207 @@ +{ + "TRANSCEIVER_INFO|Ethernet64": { + "type": "QSFP28 or later", + "hardware_rev": "AC", + "serial": "MT1706FT02064", + "manufacturer": "Mellanox", + "model": "MFA1A00-C003", + "vendor_oui": "00-02-c9", + "vendor_date": "2017-01-13 ", + "connector": "No separable connector", + "encoding": "64B66B", + "ext_identifier": "Power Class 3(2.5W max), CDR present in Rx Tx", + "ext_rateselect_compliance": "QSFP+ Rate Select Version 1", + "cable_type": "Length Cable Assembly(m)", + "cable_length": "3", + "specification_compliance": "{'10/40G Ethernet Compliance Code': '40G Active Cable (XLPPI)'}", + "nominal_bit_rate": "255", + "application_advertisement": "N/A" + }, + "TRANSCEIVER_DOM_SENSOR|Ethernet64": { + "temperature": "30.9258", + "voltage": "3.2824", + "rx1power": "0.3802", + "rx2power": "-0.4871", + "rx3power": "-0.0860", + "rx4power": "0.3830", + "tx1bias": "6.7500", + "tx2bias": "6.7500", + "tx3bias": "6.7500", + "tx4bias": "6.7500", + "tx1power": "N/A", + "tx2power": "N/A", + "tx3power": "N/A", + "tx4power": "N/A", + "rxpowerhighalarm": "3.4001", + "rxpowerhighwarning": "2.4000", + "rxpowerlowalarm": "-13.5067", + "rxpowerlowwarning": "-9.5001", + "txbiashighalarm": "10.0000", + "txbiashighwarning": "9.5000", + "txbiaslowalarm": "0.5000", + "txbiaslowwarning": "1.0000", + "temphighalarm": "75.0000", + "temphighwarning": "70.0000", + "templowalarm": "-5.0000", + "templowwarning": "0.0000", + "vcchighalarm": "3.6300", + "vcchighwarning": "3.4650", + "vcclowalarm": "2.9700", + "vcclowwarning": "3.1349" + }, + "CHASSIS_INFO|chassis 1": { + "psu_num": "2" + }, + "PSU_INFO|PSU 1": { + "presence": "true", + "status": "true", + "led_status": "green" + }, + "PSU_INFO|PSU 2": { + "presence": "true", + "status": "true", + "led_status": "green" + }, + "SWITCH_CAPABILITY|switch": { + "MIRROR": "true", + "MIRRORV6": "true", + "ACL_ACTIONS|INGRESS": "PACKET_ACTION,REDIRECT_ACTION,MIRROR_INGRESS_ACTION", + "ACL_ACTIONS|EGRESS": "PACKET_ACTION,MIRROR_EGRESS_ACTION", + "ACL_ACTION|PACKET_ACTION": "FORWARD" + }, + "DEBUG_COUNTER_CAPABILITIES|PORT_INGRESS_DROPS": { + "reasons": "[IP_HEADER_ERROR,NO_L3_HEADER]", + "count": "4" + }, + "DEBUG_COUNTER_CAPABILITIES|SWITCH_EGRESS_DROPS": { + "reasons": "[ACL_ANY,L2_ANY,L3_ANY]", + "count": "2" + }, + "LAG_MEMBER_TABLE|PortChannel0001|Ethernet112": { + "runner.actor_lacpdu_info.state": "5", + "runner.state": "disabled", + "runner.partner_lacpdu_info.port": "0", + "runner.actor_lacpdu_info.port": "113", + "runner.selected": "false", + "runner.partner_lacpdu_info.state": "0", + "ifinfo.dev_addr": "52:54:00:f2:e1:23", + "runner.partner_lacpdu_info.system": "00:00:00:00:00:00", + "link_watches.list.link_watch_0.up": "false", + "runner.actor_lacpdu_info.system": "52:54:00:f2:e1:23", + "runner.aggregator.selected": "false", + "runner.aggregator.id": "0", + "link.up": "false", + "ifinfo.ifindex": "98" + }, + "LAG_MEMBER_TABLE|PortChannel0002|Ethernet116": { + "runner.actor_lacpdu_info.state": "61", + "runner.state": "current", + "runner.partner_lacpdu_info.port": "1", + "runner.actor_lacpdu_info.port": "117", + "runner.selected": "true", + "runner.partner_lacpdu_info.state": "61", + "ifinfo.dev_addr": "52:54:00:f2:e1:23", + "runner.partner_lacpdu_info.system": "1e:af:77:fc:79:ee", + "link_watches.list.link_watch_0.up": "false", + "runner.actor_lacpdu_info.system": "52:54:00:f2:e1:23", + "runner.aggregator.selected": "true", + "runner.aggregator.id": "97", + "link.up": "true", + "ifinfo.ifindex": "97" + }, + "LAG_MEMBER_TABLE|PortChannel0003|Ethernet120": { + "runner.actor_lacpdu_info.state": "61", + "runner.state": "current", + "runner.partner_lacpdu_info.port": "1", + "runner.actor_lacpdu_info.port": "121", + "runner.selected": "true", + "runner.partner_lacpdu_info.state": "61", + "ifinfo.dev_addr": "52:54:00:f2:e1:23", + "runner.partner_lacpdu_info.system": "16:0e:58:6f:3c:dd", + "link_watches.list.link_watch_0.up": "false", + "runner.actor_lacpdu_info.system": "52:54:00:f2:e1:23", + "runner.aggregator.selected": "true", + "runner.aggregator.id": "100", + "link.up": "true", + "ifinfo.ifindex": "100" + }, + "LAG_TABLE|PortChannel0001": { + "runner.fallback": "false", + "team_device.ifinfo.dev_addr": "52:54:00:f2:e1:23", + "team_device.ifinfo.ifindex": "71", + "setup.pid": "32", + "state": "ok", + "runner.fast_rate": "false", + "setup.kernel_team_mode_name": "loadbalance", + "runner.active": "true" + }, + "LAG_TABLE|PortChannel0002": { + "runner.fallback": "false", + "team_device.ifinfo.dev_addr": "52:54:00:f2:e1:23", + "team_device.ifinfo.ifindex": "72", + "setup.pid": "40", + "state": "ok", + "runner.fast_rate": "false", + "setup.kernel_team_mode_name": "loadbalance", + "runner.active": "true" + }, + "LAG_TABLE|PortChannel0003": { + "runner.fallback": "false", + "team_device.ifinfo.dev_addr": "52:54:00:f2:e1:23", + "team_device.ifinfo.ifindex": "73", + "setup.pid": "48", + "state": "ok", + "runner.fast_rate": "false", + "setup.kernel_team_mode_name": "loadbalance", + "runner.active": "true" + }, + "LAG_TABLE|PortChannel0004": { + "runner.fallback": "false", + "team_device.ifinfo.dev_addr": "52:54:00:f2:e1:23", + "team_device.ifinfo.ifindex": "74", + "setup.pid": "56", + "state": "ok", + "runner.fast_rate": "false", + "setup.kernel_team_mode_name": "loadbalance", + "runner.active": "true" + }, + "FAN_INFO|fan1": { + "drawer_name": "drawer1", + "presence": "True", + "model": "N/A", + "serial": "N/A", + "status": "True", + "direction": "intake", + "speed": "30", + "speed_tolerance": "50", + "speed_target": "20", + "led_status": "red", + "timestamp": "20200813 01:32:30" + }, + "FAN_INFO|fan2": { + "drawer_name": "drawer2", + "presence": "True", + "model": "N/A", + "serial": "N/A", + "status": "False", + "direction": "intake", + "speed": "50", + "speed_tolerance": "50", + "speed_target": "50", + "led_status": "green", + "timestamp": "20200813 01:32:30" + }, + "FAN_INFO|fan3": { + "drawer_name": "drawer3", + "presence": "True", + "model": "N/A", + "serial": "N/A", + "status": "Updating", + "direction": "intake", + "speed": "50", + "speed_tolerance": "50", + "speed_target": "50", + "led_status": "green", + "timestamp": "20200813 01:32:30" + } +}