From 09daeb2081e001a2906c1676daf44bdbebaa80fa Mon Sep 17 00:00:00 2001 From: mihirpat1 <112018033+mihirpat1@users.noreply.github.com> Date: Tue, 29 Aug 2023 19:19:07 -0700 Subject: [PATCH 1/8] [sfputil] Retrieve error-status for transceiver using sfp API (#2953) * [sfputil] Retrieve error-status for transceiver using sfp API Signed-off-by: Mihir Patel * Resolved testcase failures * Improved code coverage --------- Signed-off-by: Mihir Patel --- sfputil/main.py | 56 +++++++------------------------------------ tests/sfputil_test.py | 26 +++++++++++++++++--- 2 files changed, 31 insertions(+), 51 deletions(-) diff --git a/sfputil/main.py b/sfputil/main.py index c19f8bdfda..51d5af4895 100644 --- a/sfputil/main.py +++ b/sfputil/main.py @@ -882,62 +882,22 @@ def fetch_error_status_from_platform_api(port): """ if port is None: logical_port_list = natsort.natsorted(platform_sfputil.logical) - # Create a list containing the logical port names of all ports we're interested in - generate_sfp_list_code = \ - "sfp_list = chassis.get_all_sfps()\n" else: - physical_port_list = logical_port_name_to_physical_port_list(port) logical_port_list = [port] - # Create a list containing the logical port names of all ports we're interested in - generate_sfp_list_code = \ - "sfp_list = [chassis.get_sfp(x) for x in {}]\n".format(physical_port_list) - - # Code to initialize chassis object - init_chassis_code = \ - "import sonic_platform.platform\n" \ - "platform = sonic_platform.platform.Platform()\n" \ - "chassis = platform.get_chassis()\n" - - # Code to fetch the error status - get_error_status_code = \ - "try:\n"\ - " errors=['{}:{}'.format(sfp.index, sfp.get_error_description()) for sfp in sfp_list]\n" \ - "except NotImplementedError as e:\n"\ - " errors=['{}:{}'.format(sfp.index, 'OK (Not implemented)') for sfp in sfp_list]\n" \ - "print(errors)\n" - - get_error_status_command = ["docker", "exec", "pmon", "python3", "-c", "{}{}{}".format( - init_chassis_code, generate_sfp_list_code, get_error_status_code)] - # Fetch error status from pmon docker - try: - output = subprocess.check_output(get_error_status_command, universal_newlines=True) - except subprocess.CalledProcessError as e: - click.Abort("Error! Unable to fetch error status for SPF modules. Error code = {}, error messages: {}".format(e.returncode, e.output)) - return None - - output_list = output.split('\n') - for output_str in output_list: - # The output of all SFP error status are a list consisting of element with convention of ':' - # Besides, there can be some logs captured during the platform API executing - # So, first of all, we need to skip all the logs until find the output list of SFP error status - if output_str[0] == '[' and output_str[-1] == ']': - output_list = ast.literal_eval(output_str) - break - - output_dict = {} - for output in output_list: - sfp_index, error_status = output.split(':') - output_dict[int(sfp_index)] = error_status output = [] for logical_port_name in logical_port_list: - physical_port_list = logical_port_name_to_physical_port_list(logical_port_name) - port_name = get_physical_port_name(logical_port_name, 1, False) + physical_port = logical_port_to_physical_port_index(logical_port_name) if is_port_type_rj45(logical_port_name): - output.append([port_name, "N/A"]) + output.append([logical_port_name, "N/A"]) else: - output.append([port_name, output_dict.get(physical_port_list[0])]) + try: + error_description = platform_chassis.get_sfp(physical_port).get_error_description() + output.append([logical_port_name, error_description]) + except NotImplementedError: + click.echo("get_error_description NOT implemented for port {}".format(logical_port_name)) + sys.exit(ERROR_NOT_IMPLEMENTED) return output diff --git a/tests/sfputil_test.py b/tests/sfputil_test.py index f50acdc441..f8917d9c44 100644 --- a/tests/sfputil_test.py +++ b/tests/sfputil_test.py @@ -424,13 +424,17 @@ def test_error_status_from_db_RJ45(self): output = sfputil.fetch_error_status_from_state_db('Ethernet0', db.db) assert output == expected_output_ethernet0 + @patch('sfputil.main.platform_chassis') @patch('sfputil.main.logical_port_name_to_physical_port_list', MagicMock(return_value=[1])) @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=False)) - @patch('subprocess.check_output', MagicMock(return_value="['0:OK']")) - def test_fetch_error_status_from_platform_api(self): + def test_fetch_error_status_from_platform_api(self, mock_chassis): + mock_sfp = MagicMock() + mock_chassis.get_sfp = MagicMock(return_value=mock_sfp) + mock_sfp.get_error_description = MagicMock(return_value='OK') + output = sfputil.fetch_error_status_from_platform_api('Ethernet0') - assert output == [['Ethernet0', None]] + assert output == [['Ethernet0', 'OK']] @patch('sfputil.main.logical_port_name_to_physical_port_list', MagicMock(return_value=[1])) @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) @@ -440,6 +444,22 @@ def test_fetch_error_status_from_platform_api_RJ45(self): output = sfputil.fetch_error_status_from_platform_api('Ethernet0') assert output == [['Ethernet0', 'N/A']] + @patch('sfputil.main.platform_chassis') + @patch('sfputil.main.platform_sfputil', MagicMock(is_logical_port=MagicMock(return_value=1))) + @patch('sfputil.main.logical_port_name_to_physical_port_list', MagicMock(return_value=[1])) + @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) + @patch('sfputil.main.is_port_type_rj45', MagicMock(return_value=False)) + def test_fetch_error_status_from_platform_api_exception(self, mock_chassis): + mock_sfp = MagicMock() + mock_chassis.get_sfp = MagicMock(return_value=mock_sfp) + mock_sfp.get_error_description = MagicMock(side_effect=NotImplementedError) + + runner = CliRunner() + result = runner.invoke(sfputil.cli.commands['show'].commands['error-status'], ["-hw", "-p", "Ethernet0"]) + assert result.exit_code == ERROR_NOT_IMPLEMENTED + expected_output = "get_error_description NOT implemented for port Ethernet0\n" + assert result.output == expected_output + @patch('sfputil.main.platform_chassis') @patch('sfputil.main.logical_port_to_physical_port_index', MagicMock(return_value=1)) def test_show_firmware_version(self, mock_chassis): From 832ecf0fe574fed8c7ef0f7c52df7f8e5f521d2f Mon Sep 17 00:00:00 2001 From: guangyao6 <107662061+guangyao6@users.noreply.github.com> Date: Wed, 30 Aug 2023 15:50:10 +0800 Subject: [PATCH 2/8] [GCU] Add BGPSentinel to CreateOnlyFilter (#2955) #### What I did BGPSentinel is the same as BGP_PEER_RANGE (create only). In order to support GCU for BGPSentinel, add BGPSentinel to GCU create only filter. #### How I did it Add BGPSentinel to CreateOnlyFilter and add related testcases. #### How to verify it Unit Test. And corresponding sonic-mgmt case: https://github.com/sonic-net/sonic-mgmt/pull/9735 --- generic_config_updater/patch_sorter.py | 1 + .../files/change_applier_test.data.json | 30 ++++++++++++++++++- .../patch_sorter_test.py | 23 ++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/generic_config_updater/patch_sorter.py b/generic_config_updater/patch_sorter.py index 528e3d5151..829c3c2b68 100644 --- a/generic_config_updater/patch_sorter.py +++ b/generic_config_updater/patch_sorter.py @@ -562,6 +562,7 @@ def __init__(self, path_addressing): ["BGP_NEIGHBOR", "*", "nhopself"], ["BGP_NEIGHBOR", "*", "rrclient"], ["BGP_PEER_RANGE", "*", "*"], + ["BGP_SENTINELS", "*", "*"], ["BGP_MONITORS", "*", "holdtime"], ["BGP_MONITORS", "*", "keepalive"], ["BGP_MONITORS", "*", "name"], diff --git a/tests/generic_config_updater/files/change_applier_test.data.json b/tests/generic_config_updater/files/change_applier_test.data.json index d75541a5de..bb3af93e0f 100644 --- a/tests/generic_config_updater/files/change_applier_test.data.json +++ b/tests/generic_config_updater/files/change_applier_test.data.json @@ -73,6 +73,23 @@ "src_address": "10.1.0.32" } }, + "BGP_SENTINELS": { + "BGPSentinelV6": { + "ip_range": [ + "2603:10a0:321:82f9::/64", + "2603:10a1:30a:8000::/59" + ], + "name": "BGPSentinelV6", + "src_address": "fc00:1::32" + }, + "BGPSentinel": { + "ip_range": [ + "10.1.0.0/24" + ], + "name": "BGPSentinel", + "src_address": "10.1.0.32" + } + }, "BUFFER_PG": { "Ethernet0|3-4": { "profile": "[BUFFER_PROFILE|pg_lossless_40000_300m_profile]" @@ -253,7 +270,8 @@ }, "remove": { "BGP_NEIGHBOR": { "10.0.0.57": {} }, - "BGP_PEER_RANGE": { "BGPSLBPassive": {} } + "BGP_PEER_RANGE": { "BGPSLBPassive": {} }, + "BGP_SENTINELS": { "BGPSentinelV6": {} } }, "services_validated": [ "vlan_validate", "acl_validate" ] }, @@ -297,6 +315,16 @@ "name": "BGPSLBPassive", "src_address": "10.1.0.32" } + }, + "BGP_SENTINELS": { + "BGPSentinelV6": { + "ip_range": [ + "2603:10a0:321:82f9::/64", + "2603:10a1:30a:8000::/59" + ], + "name": "BGPSentinelV6", + "src_address": "fc00:1::32" + } } }, "remove": { diff --git a/tests/generic_config_updater/patch_sorter_test.py b/tests/generic_config_updater/patch_sorter_test.py index 900538dd6e..baeab6fddb 100644 --- a/tests/generic_config_updater/patch_sorter_test.py +++ b/tests/generic_config_updater/patch_sorter_test.py @@ -1097,6 +1097,23 @@ def test_hard_coded_create_only_paths(self): "src_address": "10.1.0.32" } }, + "BGP_SENTINELS": { + "BGPSentinelV6": { + "ip_range": [ + "2603:10a0:321:82f9::/64", + "2603:10a1:30a:8000::/59" + ], + "name": "BGPSentinelV6", + "src_address": "fc00:1::32" + }, + "BGPSentinel": { + "ip_range": [ + "10.1.0.0/24" + ], + "name": "BGPSentinel", + "src_address": "10.1.0.32" + } + }, "BGP_MONITORS": { "5.6.7.8": { "admin_status": "up", @@ -1135,6 +1152,12 @@ def test_hard_coded_create_only_paths(self): "/BGP_PEER_RANGE/BGPSLBPassive/name", "/BGP_PEER_RANGE/BGPSLBPassive/peer_asn", "/BGP_PEER_RANGE/BGPSLBPassive/src_address", + "/BGP_SENTINELS/BGPSentinelV6/ip_range", + "/BGP_SENTINELS/BGPSentinelV6/name", + "/BGP_SENTINELS/BGPSentinelV6/src_address", + "/BGP_SENTINELS/BGPSentinel/ip_range", + "/BGP_SENTINELS/BGPSentinel/name", + "/BGP_SENTINELS/BGPSentinel/src_address", "/BGP_MONITORS/5.6.7.8/asn", "/BGP_MONITORS/5.6.7.8/holdtime", "/BGP_MONITORS/5.6.7.8/keepalive", From d8a04d8b2ee6b0c51c578c49bc0e626ade619158 Mon Sep 17 00:00:00 2001 From: isabelmsft <67024108+isabelmsft@users.noreply.github.com> Date: Wed, 30 Aug 2023 14:04:12 -0700 Subject: [PATCH 3/8] add Mellanox-SN4700-O8C48 hwsku (#2951) #### What I did Add Mellanox-SN4700-O8C48 HwSKU to GCU RDMA platform validator conf file --- generic_config_updater/gcu_field_operation_validators.conf.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic_config_updater/gcu_field_operation_validators.conf.json b/generic_config_updater/gcu_field_operation_validators.conf.json index 28f4dc0508..4398f96abd 100644 --- a/generic_config_updater/gcu_field_operation_validators.conf.json +++ b/generic_config_updater/gcu_field_operation_validators.conf.json @@ -19,7 +19,7 @@ "mellanox_asics": { "spc1": [ "ACS-MSN2700", "ACS-MSN2740", "ACS-MSN2100", "ACS-MSN2410", "ACS-MSN2010", "Mellanox-SN2700", "Mellanox-SN2700-D48C8" ], "spc2": [ "ACS-MSN3800", "Mellanox-SN3800-D112C8" ], - "spc3": [ "ACS-MSN4700", "ACS-MSN4600", "ACS-MSN4600C", "ACS-MSN4410", "Mellanox-SN4600C-D112C8", "Mellanox-SN4600C-C64" ] + "spc3": [ "ACS-MSN4700", "ACS-MSN4600", "ACS-MSN4600C", "ACS-MSN4410", "Mellanox-SN4600C-D112C8", "Mellanox-SN4600C-C64", "Mellanox-SN4700-O8C48" ] }, "broadcom_asics": { "th": [ "Force10-S6100", "Arista-7060CX-32S-C32", "Arista-7060CX-32S-C32-T1", "Arista-7060CX-32S-D48C8", "Celestica-DX010-C32", "Seastone-DX010" ], From c7c4831baf2f60c7f63166244eb07c6ab7fe8b8a Mon Sep 17 00:00:00 2001 From: Junchao-Mellanox <57339448+Junchao-Mellanox@users.noreply.github.com> Date: Fri, 1 Sep 2023 00:50:55 +0800 Subject: [PATCH 4/8] [db_migrator.py] Fix issue while upgrading from 202205 to 202211 via fast reboot (#2948) - What I did Fix issue while upgrading from 202205 to 202211 via fast reboot. This issue is caused by a mismatch version handling for fast reboot in db_migrator. This mismatch causes an incorrect sequence like this: 1. User issue fast-reboot under 202205 2. fast-reboot script set fast reboot flag by command "sonic-db-cli STATE_DB HSET "FAST_RESTART_ENABLE_TABLE|system" "enable" "true" &>/dev/null" 3. system boot to 202211 4. db_migrator found the database version is 3_0_6, it will run 4_0_0, however, it found FAST_REBOOT|system does not exist, and it set FAST_RESTART_ENABLE_TABLE|system enable to false 5. system incorrectly performs cold reboot - How I did it in db migrator if we see there is FAST_RESTART_ENABLE_TABLE already, we should skip fast reboot flag migration - How to verify it unit test manual test --- scripts/db_migrator.py | 17 ++++++++------- .../fast_reboot_upgrade_from_202205.json | 5 +++++ tests/db_migrator_test.py | 21 ++++++++++++++++++- 3 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 tests/db_migrator_input/state_db/fast_reboot_upgrade_from_202205.json diff --git a/scripts/db_migrator.py b/scripts/db_migrator.py index c2d0fd837a..d8d1ec24c5 100755 --- a/scripts/db_migrator.py +++ b/scripts/db_migrator.py @@ -691,7 +691,7 @@ def migrate_routing_config_mode(self): # overwrite the routing-config-mode as per minigraph parser # Criteria for update: # if config mode is missing in base OS or if base and target modes are not same - # Eg. in 201811 mode is "unified", and in newer branches mode is "separated" + # Eg. in 201811 mode is "unified", and in newer branches mode is "separated" if ('docker_routing_config_mode' not in device_metadata_old and 'docker_routing_config_mode' in device_metadata_new) or \ (device_metadata_old.get('docker_routing_config_mode') != device_metadata_new.get('docker_routing_config_mode')): device_metadata_old['docker_routing_config_mode'] = device_metadata_new.get('docker_routing_config_mode') @@ -1033,12 +1033,14 @@ def version_4_0_0(self): # reading FAST_REBOOT table can't be done with stateDB.get as it uses hget behind the scenes and the table structure is # not using hash and won't work. # FAST_REBOOT table exists only if fast-reboot was triggered. - keys = self.stateDB.keys(self.stateDB.STATE_DB, "FAST_REBOOT|system") - if keys: - enable_state = 'true' - else: - enable_state = 'false' - self.stateDB.set(self.stateDB.STATE_DB, 'FAST_RESTART_ENABLE_TABLE|system', 'enable', enable_state) + keys = self.stateDB.keys(self.stateDB.STATE_DB, "FAST_RESTART_ENABLE_TABLE|system") + if not keys: + keys = self.stateDB.keys(self.stateDB.STATE_DB, "FAST_REBOOT|system") + if keys: + enable_state = 'true' + else: + enable_state = 'false' + self.stateDB.set(self.stateDB.STATE_DB, 'FAST_RESTART_ENABLE_TABLE|system', 'enable', enable_state) self.set_version('version_4_0_1') return 'version_4_0_1' @@ -1057,7 +1059,6 @@ def version_4_0_2(self): Version 4_0_2. """ log.log_info('Handling version_4_0_2') - if self.stateDB.keys(self.stateDB.STATE_DB, "FAST_REBOOT|system"): self.migrate_config_db_flex_counter_delay_status() diff --git a/tests/db_migrator_input/state_db/fast_reboot_upgrade_from_202205.json b/tests/db_migrator_input/state_db/fast_reboot_upgrade_from_202205.json new file mode 100644 index 0000000000..b2e3169d4b --- /dev/null +++ b/tests/db_migrator_input/state_db/fast_reboot_upgrade_from_202205.json @@ -0,0 +1,5 @@ +{ + "FAST_RESTART_ENABLE_TABLE|system": { + "enable": "true" + } +} \ No newline at end of file diff --git a/tests/db_migrator_test.py b/tests/db_migrator_test.py index 7b4f842463..3f15f2c2e0 100644 --- a/tests/db_migrator_test.py +++ b/tests/db_migrator_test.py @@ -538,6 +538,25 @@ def test_rename_fast_reboot_table_check_enable(self): diff = DeepDiff(resulting_table, expected_table, ignore_order=True) assert not diff + def test_ignore_rename_fast_reboot_table(self): + device_info.get_sonic_version_info = get_sonic_version_info_mlnx + dbconnector.dedicated_dbs['STATE_DB'] = os.path.join(mock_db_path, 'state_db', 'fast_reboot_upgrade_from_202205') + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'config_db', 'empty-config-input') + + import db_migrator + dbmgtr = db_migrator.DBMigrator(None) + dbmgtr.migrate() + + dbconnector.dedicated_dbs['STATE_DB'] = os.path.join(mock_db_path, 'state_db', 'fast_reboot_upgrade_from_202205') + expected_db = SonicV2Connector(host='127.0.0.1') + expected_db.connect(expected_db.STATE_DB) + + resulting_table = dbmgtr.stateDB.get_all(dbmgtr.stateDB.STATE_DB, 'FAST_RESTART_ENABLE_TABLE|system') + expected_table = expected_db.get_all(expected_db.STATE_DB, 'FAST_RESTART_ENABLE_TABLE|system') + + diff = DeepDiff(resulting_table, expected_table, ignore_order=True) + assert not diff + class TestWarmUpgrade_to_2_0_2(object): @classmethod def setup_class(cls): @@ -744,4 +763,4 @@ def test_fast_reboot_upgrade_to_4_0_3(self): expected_db = self.mock_dedicated_config_db(db_after_migrate) advance_version_for_expected_database(dbmgtr.configDB, expected_db.cfgdb, 'version_4_0_3') assert not self.check_config_db(dbmgtr.configDB, expected_db.cfgdb) - assert dbmgtr.CURRENT_VERSION == expected_db.cfgdb.get_entry('VERSIONS', 'DATABASE')['VERSION'] \ No newline at end of file + assert dbmgtr.CURRENT_VERSION == expected_db.cfgdb.get_entry('VERSIONS', 'DATABASE')['VERSION'] From 3a4ebb6569f3f8ff894dd0eac7c00dc753354844 Mon Sep 17 00:00:00 2001 From: Mridul Bajpai <30709399+bmridul@users.noreply.github.com> Date: Thu, 7 Sep 2023 15:27:28 -0700 Subject: [PATCH 5/8] Voltage and Current Sensors CLI (#2941) Added support for voltage and current sensor monitoring CLIs as mentioned in the feature HLD for PMON Voltage/Current Sensor Monitoring Enhancement. sonic-net/SONiC#1394 * Addressed review comments * Fix review comment * UT file * Fixed dependency for running unit test on platform common changes * Fixed standalone unit test failure * Addressed review comment --- scripts/sensorshow | 88 +++++++++++++++++++++++++++++++++ setup.py | 1 + show/platform.py | 17 +++++++ tests/mock_tables/state_db.json | 52 +++++++++++++++++++ tests/sensor_test.py | 50 +++++++++++++++++++ 5 files changed, 208 insertions(+) create mode 100755 scripts/sensorshow create mode 100644 tests/sensor_test.py diff --git a/scripts/sensorshow b/scripts/sensorshow new file mode 100755 index 0000000000..54c37619d6 --- /dev/null +++ b/scripts/sensorshow @@ -0,0 +1,88 @@ +#!/usr/bin/python3 + +''' + Script to show Voltage and Current Sensor status. +''' +from tabulate import tabulate +from natsort import natsorted +import argparse +import os +import sys + +# mock the redis for unit test purposes # +try: + if os.environ["UTILITIES_UNIT_TESTING"] == "1": + modules_path = os.path.join(os.path.dirname(__file__), "..") + test_path = os.path.join(modules_path, "tests") + sys.path.insert(0, modules_path) + sys.path.insert(0, test_path) + import mock_tables.dbconnector +except KeyError: + pass + +from swsscommon.swsscommon import SonicV2Connector + +header = ['Sensor', '', 'High TH', 'Low TH', 'Crit High TH', 'Crit Low TH', 'Warning', 'Timestamp'] + +TIMESTAMP_FIELD_NAME = 'timestamp' +UNIT_FIELD_NAME = 'unit' +HIGH_THRESH_FIELD_NAME = 'high_threshold' +LOW_THRESH_FIELD_NAME = 'low_threshold' +CRIT_HIGH_THRESH_FIELD_NAME = 'critical_high_threshold' +CRIT_LOW_THRESH_FIELD_NAME = 'critical_low_threshold' +WARNING_STATUS_FIELD_NAME = 'warning_status' +VOLTAGE_INFO_TABLE_NAME = 'VOLTAGE_INFO' +CURRENT_INFO_TABLE_NAME = 'CURRENT_INFO' + + +class SensorShow(object): + def __init__(self, type): + self.db = SonicV2Connector(use_unix_socket_path=True) + self.db.connect(self.db.STATE_DB) + self.field_name = type + header[1] = type.capitalize() + + if type == "voltage": + self.table_name = VOLTAGE_INFO_TABLE_NAME + else: + self.table_name = CURRENT_INFO_TABLE_NAME + + def show(self): + keys = self.db.keys(self.db.STATE_DB, self.table_name + '*') + if not keys: + print('Sensor not detected') + return + + table = [] + for key in natsorted(keys): + key_list = key.split('|') + if len(key_list) != 2: # error data in DB, log it and ignore + print('Warn: Invalid key in table {}: {}'.format(self.table_name, key)) + continue + + name = key_list[1] + data_dict = self.db.get_all(self.db.STATE_DB, key) + #print(name, data_dict) + table.append((name, + "{} {}".format(data_dict[self.field_name], data_dict[UNIT_FIELD_NAME]), + data_dict[HIGH_THRESH_FIELD_NAME], + data_dict[LOW_THRESH_FIELD_NAME], + data_dict[CRIT_HIGH_THRESH_FIELD_NAME], + data_dict[CRIT_LOW_THRESH_FIELD_NAME], + data_dict[WARNING_STATUS_FIELD_NAME], + data_dict[TIMESTAMP_FIELD_NAME] + )) + + if table: + print(tabulate(table, header, tablefmt='simple', stralign='right')) + else: + print('No sensor data available') + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-t", "--type", help="sensor type", required=True, choices=['voltage', 'current']) + args = parser.parse_args() + + sensor_show = SensorShow(args.type) + sensor_show.show() diff --git a/setup.py b/setup.py index ac069267f0..6888d3405d 100644 --- a/setup.py +++ b/setup.py @@ -170,6 +170,7 @@ 'scripts/tempershow', 'scripts/tunnelstat', 'scripts/update_json.py', + 'scripts/sensorshow', 'scripts/voqutil', 'scripts/warm-reboot', 'scripts/watermarkstat', diff --git a/show/platform.py b/show/platform.py index c4f2c3a29c..d3e9fa098a 100644 --- a/show/platform.py +++ b/show/platform.py @@ -137,6 +137,23 @@ def temperature(): cmd = ['tempershow'] clicommon.run_command(cmd) + +# 'voltage' subcommand ("show platform voltage") +@platform.command() +def voltage(): + """Show device voltage information""" + cmd = ["sensorshow", "-t", "voltage"] + clicommon.run_command(cmd) + + +# 'current' subcommand ("show platform current") +@platform.command() +def current(): + """Show device current information""" + cmd = ["sensorshow", "-t", "current"] + clicommon.run_command(cmd) + + # 'firmware' subcommand ("show platform firmware") @platform.command( context_settings=dict( diff --git a/tests/mock_tables/state_db.json b/tests/mock_tables/state_db.json index f98de518b8..8d7f27f7ca 100644 --- a/tests/mock_tables/state_db.json +++ b/tests/mock_tables/state_db.json @@ -1620,5 +1620,57 @@ }, "ACL_RULE_TABLE|DATAACL_5|RULE_1" : { "status": "Active" + }, + "VOLTAGE_INFO|VSENSOR0": { + "critical_high_threshold": "872", + "critical_low_threshold": "664", + "high_threshold": "852", + "is_replaceable": "False", + "low_threshold": "684", + "maximum_voltage": "760", + "minimum_voltage": "759", + "timestamp": "20230704 17:38:04", + "voltage": "760", + "unit": "mV", + "warning_status": "False" + }, + "VOLTAGE_INFO|VSENSOR1": { + "critical_high_threshold": "872", + "critical_low_threshold": "664", + "high_threshold": "852", + "is_replaceable": "False", + "low_threshold": "684", + "maximum_voltage": "760", + "minimum_voltage": "759", + "timestamp": "20230704 17:38:04", + "voltage": "759", + "unit": "mV", + "warning_status": "False" + }, + "CURRENT_INFO|ISENSOR0": { + "critical_high_threshold": "460", + "critical_low_threshold": "300", + "current": "410", + "unit": "mA", + "high_threshold": "440", + "is_replaceable": "False", + "low_threshold": "320", + "maximum_current": "431", + "minimum_current": "402", + "timestamp": "20230704 17:38:04", + "warning_status": "False" + }, + "CURRENT_INFO|ISENSOR1": { + "critical_high_threshold": "460", + "critical_low_threshold": "300", + "current": "360", + "unit": "mA", + "high_threshold": "440", + "is_replaceable": "False", + "low_threshold": "320", + "maximum_current": "367", + "minimum_current": "339", + "timestamp": "20230704 17:38:04", + "warning_status": "False" } } diff --git a/tests/sensor_test.py b/tests/sensor_test.py new file mode 100644 index 0000000000..d97ce5c74e --- /dev/null +++ b/tests/sensor_test.py @@ -0,0 +1,50 @@ +import sys +import os +from click.testing import CliRunner + +test_path = os.path.dirname(os.path.abspath(__file__)) +modules_path = os.path.dirname(test_path) +scripts_path = os.path.join(modules_path, "scripts") +sys.path.insert(0, modules_path) + +import show.main as show + +class TestVoltage(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["PATH"] += os.pathsep + scripts_path + os.environ["UTILITIES_UNIT_TESTING"] = "1" + + def test_show_platform_voltage(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["platform"].commands["voltage"]) + print(result.output) + expected = """\ + Sensor Voltage High TH Low TH Crit High TH Crit Low TH Warning Timestamp +-------- --------- --------- -------- -------------- ------------- --------- ----------------- +VSENSOR0 760 mV 852 684 872 664 False 20230704 17:38:04 +VSENSOR1 759 mV 852 684 872 664 False 20230704 17:38:04 +""" + + assert result.output == expected + + def test_show_platform_current(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["platform"].commands["current"]) + print(result.output) + expected = """\ + Sensor Current High TH Low TH Crit High TH Crit Low TH Warning Timestamp +-------- --------- --------- -------- -------------- ------------- --------- ----------------- +ISENSOR0 410 mA 440 320 460 300 False 20230704 17:38:04 +ISENSOR1 360 mA 440 320 460 300 False 20230704 17:38:04 +""" + + 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" + From 57b3b313b0ab272a04ef7553c15eddf780e7e8b0 Mon Sep 17 00:00:00 2001 From: Vivek Date: Sun, 10 Sep 2023 08:31:29 -0700 Subject: [PATCH 6/8] Remove the CONFIG_DB_INIT flag dependency on db_migrator (#2959) - What I did db_migrator should not depend on CONFIG_DB_INITIALIZED flag. get_hwsku api call busy waits on that flag - How I did it Replace get_hwsku call with get_localhost_info call which takes in a custom config_db object Signed-off-by: Vivek Reddy Karri --- scripts/db_migrator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/db_migrator.py b/scripts/db_migrator.py index d8d1ec24c5..8df892b2d7 100755 --- a/scripts/db_migrator.py +++ b/scripts/db_migrator.py @@ -91,7 +91,8 @@ def __init__(self, namespace, socket=None): self.asic_type = version_info.get('asic_type') if not self.asic_type: log.log_error("ASIC type information not obtained. DB migration will not be reliable") - self.hwsku = device_info.get_hwsku() + + self.hwsku = device_info.get_localhost_info('hwsku', self.configDB) if not self.hwsku: log.log_error("HWSKU information not obtained. DB migration will not be reliable") From b1ac2ef1c5ca4d3724603d813413ae98a768a5e5 Mon Sep 17 00:00:00 2001 From: Yaqiang Zhu Date: Mon, 11 Sep 2023 01:12:00 -0400 Subject: [PATCH 7/8] [sonic-package-manager] Increate timeout for sonic-package-manager migrate (#2973) What I did When we migrate package via sonic-package-manager in some low-performance device, getting docker image from old image via docker socket may timeout by default timeout setting (60s) client.py. This PR is to increase timeout to 120s. How I did it Increase docker client timeout from 60s to 120s. How to verify it ut passed. Build image with INCLUDE_MACSEC, and install it, macsec image was not include. And the build image with this PR, install it. Migrate package successfully. Signed-off-by: Yaqiang Zhu --- sonic_package_manager/manager.py | 7 +++++- tests/sonic_package_manager/test_manager.py | 28 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/sonic_package_manager/manager.py b/sonic_package_manager/manager.py index 7ed2be0a9e..d01ed9cb44 100644 --- a/sonic_package_manager/manager.py +++ b/sonic_package_manager/manager.py @@ -659,6 +659,10 @@ def reset(self, name: str, force: bool = False, skip_host_plugins: bool = False) allow_downgrade=True, skip_host_plugins=skip_host_plugins) + @under_lock + def get_docker_client(self, dockerd_sock:str): + return docker.DockerClient(base_url=f'unix://{dockerd_sock}', timeout=120) + @under_lock def migrate_packages(self, old_package_database: PackageDatabase, @@ -701,7 +705,8 @@ def migrate_package(old_package_entry, # dockerd_sock is defined, so use docked_sock to connect to # dockerd and fetch package image from it. log.info(f'installing {name} from old docker library') - docker_api = DockerApi(docker.DockerClient(base_url=f'unix://{dockerd_sock}')) + docker_client = self.get_docker_client(dockerd_sock) + docker_api = DockerApi(docker_client) image = docker_api.get_image(old_package_entry.image_id) diff --git a/tests/sonic_package_manager/test_manager.py b/tests/sonic_package_manager/test_manager.py index ad365f946d..db9a79b309 100644 --- a/tests/sonic_package_manager/test_manager.py +++ b/tests/sonic_package_manager/test_manager.py @@ -356,3 +356,31 @@ def test_manager_migration(package_manager, fake_db_for_migration): call('test-package-6=2.0.0')], any_order=True ) + + +def mock_get_docker_client(dockerd_sock): + class DockerClient: + def __init__(self, dockerd_sock): + class Image: + def __init__(self, image_id): + self.image_id = image_id + + def save(self, named): + return ["named: {}".format(named).encode()] + + image = Image("dummy_id") + self.images = { + "Azure/docker-test-3:1.6.0": image, + "Azure/docker-test-6:2.0.0": image + } + self.dockerd_sock = dockerd_sock + + return DockerClient(dockerd_sock) + + +def test_manager_migration_dockerd(package_manager, fake_db_for_migration, mock_docker_api): + package_manager.install = Mock() + package_manager.get_docker_client = Mock(side_effect=mock_get_docker_client) + package_manager.migrate_packages(fake_db_for_migration, '/var/run/docker.sock') + package_manager.get_docker_client.assert_has_calls([ + call('/var/run/docker.sock')], any_order=True) From 82a4d7163fe7fbf71e988d460f891cd683e75ee8 Mon Sep 17 00:00:00 2001 From: Saikrishna Arcot Date: Wed, 13 Sep 2023 14:11:33 -0700 Subject: [PATCH 8/8] Remove command to install libhiredis deb file (#2980) libhiredis is now used as-is from the slave container, since we're not making any changes to this package. See also sonic-net/sonic-buildimage#15633. Signed-off-by: Saikrishna Arcot --- azure-pipelines.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index eecf1c9e53..1f0f354436 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -52,12 +52,11 @@ stages: - script: | set -xe - sudo apt-get -y purge libhiredis-dev libnl-3-dev libnl-route-3-dev || true + sudo apt-get -y purge libnl-3-dev libnl-route-3-dev || true sudo dpkg -i libnl-3-200_*.deb sudo dpkg -i libnl-genl-3-200_*.deb sudo dpkg -i libnl-route-3-200_*.deb sudo dpkg -i libnl-nf-3-200_*.deb - sudo dpkg -i libhiredis0.14_*.deb sudo dpkg -i libyang_1.0.73_amd64.deb sudo dpkg -i libyang-cpp_1.0.73_amd64.deb sudo dpkg -i python3-yang_1.0.73_amd64.deb