diff --git a/sonic-thermalctld/scripts/thermalctld b/sonic-thermalctld/scripts/thermalctld index fbea42022280..a746b218d08e 100644 --- a/sonic-thermalctld/scripts/thermalctld +++ b/sonic-thermalctld/scripts/thermalctld @@ -23,6 +23,7 @@ except ImportError as e: SYSLOG_IDENTIFIER = 'thermalctld' NOT_AVAILABLE = 'N/A' +INVALID_SLOT = -1 # utility functions @@ -462,6 +463,15 @@ class TemperatureUpdater(logger.Logger): self.temperature_status_dict = {} state_db = daemon_base.db_connect("STATE_DB") self.table = swsscommon.Table(state_db, TemperatureUpdater.TEMPER_INFO_TABLE_NAME) + self.chassis_table = None + + self.is_chassis_system = chassis.is_modular_chassis() + if self.is_chassis_system: + my_slot = try_get(chassis.get_my_slot, INVALID_SLOT) + if my_slot != INVALID_SLOT: + table_name = TemperatureUpdater.TEMPER_INFO_TABLE_NAME+'_'+str(my_slot) + chassis_state_db = daemon_base.db_connect("CHASSIS_STATE_DB") + self.chassis_table = swsscommon.Table(chassis_state_db, table_name) def deinit(self): """ @@ -470,6 +480,8 @@ class TemperatureUpdater(logger.Logger): """ for name in self.temperature_status_dict.keys(): self.table._del(name) + if self.is_chassis_system and self.chassis_table is not None: + self.chassis_table._del(name) def _log_on_status_changed(self, normal_status, normal_log, abnormal_log): """ @@ -515,9 +527,13 @@ class TemperatureUpdater(logger.Logger): low_threshold = NOT_AVAILABLE high_critical_threshold = NOT_AVAILABLE low_critical_threshold = NOT_AVAILABLE + maximum_temperature = NOT_AVAILABLE + minimum_temperature = NOT_AVAILABLE temperature = try_get(thermal.get_temperature) if temperature != NOT_AVAILABLE: temperature_status.set_temperature(name, temperature) + minimum_temperature = try_get(thermal.get_minimum_recorded) + maximum_temperature = try_get(thermal.get_maximum_recorded) high_threshold = try_get(thermal.get_high_threshold) low_threshold = try_get(thermal.get_low_threshold) high_critical_threshold = try_get(thermal.get_high_critical_threshold) @@ -544,6 +560,8 @@ class TemperatureUpdater(logger.Logger): fvs = swsscommon.FieldValuePairs( [('temperature', str(temperature)), + ('minimum_temperature', str(minimum_temperature)), + ('maximum_temperature', str(maximum_temperature)), ('high_threshold', str(high_threshold)), ('low_threshold', str(low_threshold)), ('warning_status', str(warning)), @@ -553,6 +571,8 @@ class TemperatureUpdater(logger.Logger): ]) self.table.set(name, fvs) + if self.is_chassis_system and self.chassis_table is not None: + self.chassis_table.set(name, fvs) class ThermalMonitor(ProcessTaskBase): diff --git a/sonic-thermalctld/tests/mock_platform.py b/sonic-thermalctld/tests/mock_platform.py index b6fae1eaf0d4..a35ea9cc997b 100644 --- a/sonic-thermalctld/tests/mock_platform.py +++ b/sonic-thermalctld/tests/mock_platform.py @@ -104,6 +104,8 @@ class MockThermal: def __init__(self): self.name = None self.temperature = 2 + self.minimum_temperature = 1 + self.maximum_temperature = 5 self.high_threshold = 3 self.low_threshold = 1 self.high_critical_threshold = 4 @@ -115,6 +117,12 @@ def get_name(self): def get_temperature(self): return self.temperature + def get_minimum_recorded(self): + return self.minimum_temperature + + def get_maximum_recorded(self): + return self.maximum_temperature + def get_high_threshold(self): return self.high_threshold @@ -154,6 +162,7 @@ def __init__(self): self.psu_list = [] self.thermal_list = [] self.fan_drawer_list = [] + self.is_chassis_system = False def get_all_fans(self): return self.fan_list @@ -167,6 +176,9 @@ def get_all_thermals(self): def get_all_fan_drawers(self): return self.fan_drawer_list + def get_num_thermals(self): + return len(self.thermal_list) + def make_absence_fan(self): fan = MockFan() fan.presence = False @@ -220,3 +232,14 @@ def make_error_thermal(self): thermal = MockErrorThermal() self.thermal_list.append(thermal) + def is_modular_chassis(self): + return self.is_chassis_system + + def set_modular_chassis(self, is_true): + self.is_chassis_system = is_true + + def set_my_slot(self, my_slot): + self.my_slot = my_slot + + def get_my_slot(self): + return self.my_slot diff --git a/sonic-thermalctld/tests/mock_swsscommon.py b/sonic-thermalctld/tests/mock_swsscommon.py index 174e4935b1cf..5907316f210c 100644 --- a/sonic-thermalctld/tests/mock_swsscommon.py +++ b/sonic-thermalctld/tests/mock_swsscommon.py @@ -1,17 +1,28 @@ STATE_DB = '' - +CHASSIS_STATE_DB = '' class Table: def __init__(self, db, table_name): self.table_name = table_name + self.mock_dict = {} def _del(self, key): + del self.mock_dict[key] pass def set(self, key, fvs): + self.mock_dict[key] = fvs.fv_dict pass + def get(self, key): + if key in self.mock_dict: + return self.mock_dict[key] + return None + + def get_size(self): + return (len(self.mock_dict)) class FieldValuePairs: - def __init__(self, fvs): - pass + def __init__(self, fvs): + self.fv_dict = dict(fvs) + pass diff --git a/sonic-thermalctld/tests/test_thermalctld.py b/sonic-thermalctld/tests/test_thermalctld.py index fbfcf3c7ed21..15344bdea5a9 100644 --- a/sonic-thermalctld/tests/test_thermalctld.py +++ b/sonic-thermalctld/tests/test_thermalctld.py @@ -21,6 +21,7 @@ load_source('thermalctld', scripts_path + '/thermalctld') from thermalctld import * +TEMPER_INFO_TABLE_NAME = 'TEMPERATURE_INFO' def setup_function(): FanStatus.log_notice = MagicMock() @@ -283,3 +284,58 @@ def test_update_thermal_with_exception(): temperature_updater = TemperatureUpdater(SYSLOG_IDENTIFIER, chassis) temperature_updater.update() temperature_updater.log_warning.assert_called() + +#Modular chassis related tests +def test_updater_thermal_check_modular_chassis(): + chassis = MockChassis() + assert chassis.is_modular_chassis() == False + + temperature_updater = TemperatureUpdater(SYSLOG_IDENTIFIER, chassis) + assert temperature_updater.chassis_table == None + + chassis.set_modular_chassis(True) + chassis.set_my_slot(-1) + temperature_updater = TemperatureUpdater(SYSLOG_IDENTIFIER, chassis) + assert temperature_updater.chassis_table == None + + my_slot = 1 + chassis.set_my_slot(my_slot) + temperature_updater = TemperatureUpdater(SYSLOG_IDENTIFIER, chassis) + assert temperature_updater.chassis_table != None + assert temperature_updater.chassis_table.table_name == TEMPER_INFO_TABLE_NAME+'_'+str(my_slot) + +def test_updater_thermal_check_chassis_table(): + chassis = MockChassis() + + thermal1 = MockThermal() + chassis.get_all_thermals().append(thermal1) + + chassis.set_modular_chassis(True) + chassis.set_my_slot(1) + temperature_updater = TemperatureUpdater(SYSLOG_IDENTIFIER, chassis) + + temperature_updater.update() + assert temperature_updater.chassis_table.get_size() == chassis.get_num_thermals() + + thermal2 = MockThermal() + chassis.get_all_thermals().append(thermal2) + temperature_updater.update() + assert temperature_updater.chassis_table.get_size() == chassis.get_num_thermals() + + temperature_updater.deinit() + assert temperature_updater.chassis_table.get_size() == 0 + +def test_updater_thermal_check_min_max(): + chassis = MockChassis() + + thermal = MockThermal() + chassis.get_all_thermals().append(thermal) + + chassis.set_modular_chassis(True) + chassis.set_my_slot(1) + temperature_updater = TemperatureUpdater(SYSLOG_IDENTIFIER, chassis) + + temperature_updater.update() + slot_dict = temperature_updater.chassis_table.get('Thermal 1') + assert slot_dict['minimum_temperature'] == str(thermal.get_minimum_recorded()) + assert slot_dict['maximum_temperature'] == str(thermal.get_maximum_recorded())