diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/thermal_policy.json b/device/mellanox/x86_64-mlnx_msn2700-r0/thermal_policy.json index 1e23d6c8b2bd..f93e4212708e 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/thermal_policy.json +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/thermal_policy.json @@ -1,80 +1,12 @@ -{ +{ "thermal_control_algorithm": { "run_at_boot_up": "true", "fan_speed_when_suspend": "60" }, "info_types": [ - { - "type": "fan_info" - }, - { - "type": "psu_info" - }, - { - "type": "chassis_info" - } + ], "policies": [ - { - "name": "any fan absence", - "conditions": [ - { - "type": "fan.any.absence" - } - ], - "actions": [ - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] - }, - { - "name": "any psu absence", - "conditions": [ - { - "type": "psu.any.absence" - } - ], - "actions": [ - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] - }, - { - "name": "any fan broken", - "conditions": [ - { - "type": "fan.any.fault" - } - ], - "actions": [ - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] - }, - { - "name": "all fan and psu presence", - "conditions": [ - { - "type": "fan.all.presence" - }, - { - "type": "psu.all.presence" - }, - { - "type": "fan.all.good" - } - ], - "actions": [ - { - "type": "thermal.recover" - } - ] - } + ] -} \ No newline at end of file +} diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/device_data.py b/platform/mellanox/mlnx-platform-api/sonic_platform/device_data.py index 4b4eed5bbb6f..5ace26efdc94 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/device_data.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/device_data.py @@ -23,10 +23,6 @@ DEVICE_DATA = { 'x86_64-mlnx_msn2700-r0': { 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:30":13, "31:40":14 , "41:120":15}, - "unk_untrust": {"-127:25":13, "26:30":14 , "31:35":15, "36:120":16} - }, "capability": { "comex_amb": False } @@ -34,10 +30,6 @@ }, 'x86_64-mlnx_msn2740-r0': { 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:120":13}, - "unk_untrust": {"-127:15":13, "16:25":14 , "26:30":15, "31:120":17}, - }, "capability": { "cpu_pack": False, "comex_amb": False @@ -46,10 +38,6 @@ }, 'x86_64-mlnx_msn2100-r0': { 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:40":12, "41:120":13}, - "unk_untrust": {"-127:15":12, "16:25":13, "26:30":14, "31:35":15, "36:120":16} - }, "capability": { "cpu_pack": False, "comex_amb": False @@ -58,10 +46,6 @@ }, 'x86_64-mlnx_msn2410-r0': { 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:30":13, "31:40":14 , "41:120":15}, - "unk_untrust": {"-127:25":13, "26:30":14 , "31:35":15, "36:120":16} - }, "capability": { "comex_amb": False } @@ -69,10 +53,6 @@ }, 'x86_64-mlnx_msn2010-r0': { 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:120":12}, - "unk_untrust": {"-127:15":12, "16:20":13 , "21:30":14, "31:35":15, "36:120":16} - }, "capability": { "cpu_pack": False, "comex_amb": False @@ -80,75 +60,26 @@ } }, 'x86_64-mlnx_msn3700-r0': { - 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:25":12, "26:40":13 , "41:120":14}, - "unk_untrust": {"-127:15":12, "16:30":13 , "31:35":14, "36:40":15, "41:120":16}, - } - } }, 'x86_64-mlnx_msn3700c-r0': { - 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:40":12, "41:120":13}, - "unk_untrust": {"-127:10":12, "11:20":13 , "21:30":14, "31:35":15, "36:120":16}, - } - } }, 'x86_64-mlnx_msn3800-r0': { - 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:30":12, "31:40":13 , "41:120":14}, - "unk_untrust": {"-127:0":12, "1:10":13 , "11:15":14, "16:20":15, "21:35":16, "36:120":17}, - } - } }, 'x86_64-mlnx_msn4700-r0': { - 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:35":14, "36:120":15}, - "unk_untrust": {"-127:35":14, "36:120":15}, - } - } }, 'x86_64-mlnx_msn4410-r0': { - 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:40":12, "41:120":13}, - "unk_untrust": {"-127:10":12, "11:20":13, "21:30":14, "31:35":15, "36:120":16}, - } - } }, 'x86_64-mlnx_msn3420-r0': { - 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:120":12}, - "unk_untrust": {"-127:25":12, "26:35":13, "36:40":14, "41:120":16}, - } - } }, 'x86_64-mlnx_msn4600c-r0': { - 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:40":12, "41:120":13}, - "unk_untrust": {"-127:5":12, "6:20":13, "21:30":14, "31:35":15, "36:40":16, "41:120":17}, - } - } }, 'x86_64-mlnx_msn4600-r0': { - 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:40": 12, "41:120": 13}, - "unk_untrust": {"-127:5": 12, "6:20": 13, "21:30": 14, "31:35": 15, "36:40": 16, "41:120": 17}, - } - } }, 'x86_64-nvidia_sn4800-r0': { 'thermal': { "capability": { "comex_amb": False - }, - 'cpu_threshold': (80, 95) # min=80, max=95 + } }, 'sfp': { 'max_port_per_line_card': 16 @@ -156,10 +87,6 @@ }, 'x86_64-nvidia_sn2201-r0': { 'thermal': { - 'minimum_table': { - "unk_trust": {"-127:30": 13, "31:35": 14, "36:40": 15, "41:120": 16}, - "unk_untrust": {"-127:15": 13, "16:20": 14, "21:25": 15, "26:30": 16, "31:35": 17, "36:40": 18, "41:120": 19}, - }, "capability": { "comex_amb": False, "cpu_amb": True @@ -242,19 +169,6 @@ def get_cpu_thermal_count(cls): def get_sodimm_thermal_count(cls): return len(glob.glob('/run/hw-management/thermal/sodimm*_temp_input')) - @classmethod - @utils.read_only_cache() - def get_minimum_table(cls): - platform_data = DEVICE_DATA.get(cls.get_platform_name(), None) - if not platform_data: - return None - - thermal_data = platform_data.get('thermal', None) - if not thermal_data: - return None - - return thermal_data.get('minimum_table', None) - @classmethod @utils.read_only_cache() def get_thermal_capability(cls): @@ -285,23 +199,6 @@ def get_linecard_max_port_count(cls): return 0 return sfp_data.get('max_port_per_line_card', 0) - @classmethod - def is_cpu_thermal_control_supported(cls): - return cls.get_cpu_thermal_threshold() != (None, None) - - @classmethod - @utils.read_only_cache() - def get_cpu_thermal_threshold(cls): - platform_data = DEVICE_DATA.get(cls.get_platform_name(), None) - if not platform_data: - return None, None - - thermal_data = platform_data.get('thermal', None) - if not thermal_data: - return None, None - - return thermal_data.get('cpu_threshold', (None, None)) - @classmethod def get_bios_component(cls): from .component import ComponentBIOS, ComponentBIOSSN2201 diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py b/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py index c53abf6af9c1..0ba71b6a417a 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/fan.py @@ -216,7 +216,7 @@ def get_target_speed(self): """ try: # Get PSU fan target speed according to current system cooling level - cooling_level = Thermal.get_cooling_level() + cooling_level = utils.read_int_from_file('/run/hw-management/thermal/cooling_cur_state', log_func=None) return int(self.PSU_FAN_SPEED[cooling_level], 16) except Exception: return self.get_speed() @@ -250,6 +250,7 @@ def set_speed(self, speed): logger.log_error('Failed to set PSU FAN speed - {}'.format(e)) return False + class Fan(MlnxFan): """Platform-specific Fan class""" def __init__(self, fan_index, fan_drawer, position): diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py index 1a603e183116..6aa69d7b9224 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py @@ -27,12 +27,11 @@ from sonic_py_common.logger import Logger import copy import os - import glob from .device_data import DeviceDataManager from . import utils except ImportError as e: - raise ImportError (str(e) + "- required module not found") + raise ImportError(str(e) + "- required module not found") # Global logger class instance logger = Logger() @@ -143,23 +142,6 @@ } CHASSIS_THERMAL_SYSFS_FOLDER = '/run/hw-management/thermal' -COOLING_STATE_PATH = "/var/run/hw-management/thermal/cooling_cur_state" -THERMAL_ZONE_ASIC_PATH = '/var/run/hw-management/thermal/mlxsw/' -THERMAL_ZONE_FOLDER_WILDCARD = '/run/hw-management/thermal/mlxsw*' -THERMAL_ZONE_HIGH_THRESHOLD = 'temp_trip_high' -THERMAL_ZONE_HOT_THRESHOLD = 'temp_trip_hot' -THERMAL_ZONE_NORMAL_THRESHOLD = 'temp_trip_norm' -THERMAL_ZONE_MODE_FILE = 'thermal_zone_mode' -THERMAL_ZONE_POLICY_FILE = 'thermal_zone_policy' -THERMAL_ZONE_TEMP_FILE = 'thermal_zone_temp' -THERMAL_ZONE_HYSTERESIS = 5000 -MODULE_TEMP_FAULT_WILDCARRD = '/run/hw-management/thermal/module*_temp_fault' -MAX_AMBIENT_TEMP = 120 -# Min allowed cooling level when all thermal zones are in normal state -MIN_COOLING_LEVEL_FOR_NORMAL = 2 -# Min allowed cooling level when any thermal zone is in high state but no thermal zone is in emergency state -MIN_COOLING_LEVEL_FOR_HIGH = 4 -MAX_COOLING_LEVEL = 10 def initialize_chassis_thermals(): @@ -369,175 +351,6 @@ def is_replaceable(self): """ return False - @classmethod - def set_thermal_algorithm_status(cls, status, force=True): - """ - Enable/disable kernel thermal algorithm. - When enable kernel thermal algorithm, kernel will adjust fan speed - according to thermal zones temperature. Please note that kernel will - only adjust fan speed when temperature across some "edge", e.g temperature - changes to exceed high threshold. - When disable kernel thermal algorithm, kernel no longer adjust fan speed. - We usually disable the algorithm when we want to set a fix speed. E.g, when - a fan unit is removed from system, we will set fan speed to 100% and disable - the algorithm to avoid it adjust the speed. - - Returns: - True if thermal algorithm status changed. - """ - if not force and cls.thermal_algorithm_status == status: - return False - - cls.thermal_algorithm_status = status - mode = "enabled" if status else "disabled" - policy = "step_wise" if status else "user_space" - for thermal_zone_folder in glob.iglob(THERMAL_ZONE_FOLDER_WILDCARD): - policy_file = os.path.join(thermal_zone_folder, THERMAL_ZONE_POLICY_FILE) - utils.write_file(policy_file, policy) - mode_file = os.path.join(thermal_zone_folder, THERMAL_ZONE_MODE_FILE) - utils.write_file(mode_file, mode) - - return True - - @classmethod - def get_min_allowed_cooling_level_by_thermal_zone(cls): - """Get min allowed cooling level according to thermal zone status: - 1. If temperature of all thermal zones is less than normal threshold, min allowed cooling level is - $MIN_COOLING_LEVEL_FOR_NORMAL = 2 - 2. If temperature of any thermal zone is greater than normal threshold, but no thermal zone temperature - is greater than high threshold, min allowed cooling level is $MIN_COOLING_LEVEL_FOR_HIGH = 4 - 3. Otherwise, there is no minimum allowed value and policy should not adjust cooling level - Returns: - int: minimum allowed cooling level - """ - min_allowed = MIN_COOLING_LEVEL_FOR_NORMAL - thermal_zone_present = False - try: - for thermal_zone_folder in glob.iglob(THERMAL_ZONE_FOLDER_WILDCARD): - current = utils.read_int_from_file(os.path.join(thermal_zone_folder, THERMAL_ZONE_TEMP_FILE)) - if current == 0: - # Temperature value 0 means that this thermal zone has no - # sensor and it should be ignored in this loop - continue - - thermal_zone_present = True - normal_thresh = utils.read_int_from_file(os.path.join(thermal_zone_folder, THERMAL_ZONE_NORMAL_THRESHOLD)) - if current < normal_thresh - THERMAL_ZONE_HYSTERESIS: - continue - - hot_thresh = utils.read_int_from_file(os.path.join(thermal_zone_folder, THERMAL_ZONE_HIGH_THRESHOLD)) - if current < hot_thresh - THERMAL_ZONE_HYSTERESIS: - min_allowed = MIN_COOLING_LEVEL_FOR_HIGH - else: - min_allowed = None - break - except Exception as e: - logger.log_error('Failed to get thermal zone status for {} - {}'.format(thermal_zone_folder, repr(e))) - return None - - return min_allowed if thermal_zone_present else None - - @classmethod - def check_module_temperature_trustable(cls): - for file_path in glob.iglob(MODULE_TEMP_FAULT_WILDCARRD): - fault = utils.read_int_from_file(file_path) - if fault != 0: - return 'untrust' - return 'trust' - - @classmethod - def get_min_amb_temperature(cls): - fan_ambient_path = os.path.join(CHASSIS_THERMAL_SYSFS_FOLDER, 'fan_amb') - port_ambient_path = os.path.join(CHASSIS_THERMAL_SYSFS_FOLDER, 'port_amb') - - try: - fan_ambient_temp = utils.read_int_from_file(fan_ambient_path, raise_exception=True) - port_ambient_temp = utils.read_int_from_file(port_ambient_path, raise_exception=True) - return fan_ambient_temp if fan_ambient_temp < port_ambient_temp else port_ambient_temp - except Exception as e: - # Can't get ambient temperature, return maximum - logger.log_error('Failed to get minimum ambient temperature, use pessimistic instead') - return MAX_AMBIENT_TEMP - - @classmethod - def set_cooling_level(cls, level): - """ - Change cooling level. The input level should be an integer value [1, 10]. - 1 means 10%, 2 means 20%, 10 means 100%. - """ - if cls.last_set_cooling_level != level: - utils.write_file(COOLING_STATE_PATH, level + 10, raise_exception=True) - cls.last_set_cooling_level = level - - @classmethod - def set_cooling_state(cls, state): - """Change cooling state. - Args: - state (int): cooling state - """ - if cls.last_set_cooling_state != state: - utils.write_file(COOLING_STATE_PATH, state, raise_exception=True) - cls.last_set_cooling_state = state - - @classmethod - def get_cooling_level(cls): - try: - return utils.read_int_from_file(COOLING_STATE_PATH, raise_exception=True) - except (ValueError, IOError) as e: - raise RuntimeError("Failed to get cooling level - {}".format(e)) - - @classmethod - def set_expect_cooling_level(cls, expect_value): - """During thermal policy running, cache the expect cooling level generated by policies. The max expect - cooling level will be committed to hardware. - Args: - expect_value (int): Expected cooling level value - """ - if cls.expect_cooling_level is None or cls.expect_cooling_level < expect_value: - cls.expect_cooling_level = int(expect_value) - - @classmethod - def commit_cooling_level(cls, thermal_info_dict): - """Commit cooling level to hardware. This will affect system fan and PSU fan speed. - Args: - thermal_info_dict (dict): Thermal information dictionary - """ - if cls.expect_cooling_level is not None: - cls.set_cooling_level(cls.expect_cooling_level) - - if cls.expect_cooling_state is not None: - cls.set_cooling_state(cls.expect_cooling_state) - elif cls.expect_cooling_level is not None: - cls.set_cooling_state(cls.expect_cooling_level) - - cls.expect_cooling_level = None - # We need to set system fan speed here because kernel will automaticlly adjust fan speed according to cooling level and cooling state - - # Commit PSU fan speed with current state - from .thermal_infos import ChassisInfo - if ChassisInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ChassisInfo.INFO_NAME], ChassisInfo): - cooling_level = cls.get_cooling_level() - if cls.last_set_psu_cooling_level == cooling_level: - return - speed = cooling_level * 10 - chassis = thermal_info_dict[ChassisInfo.INFO_NAME].get_chassis() - for psu in chassis.get_all_psus(): - for psu_fan in psu.get_all_fans(): - psu_fan.set_speed(speed) - cls.last_set_psu_cooling_level = cooling_level - - @classmethod - def monitor_asic_themal_zone(cls): - """This is a protection for asic thermal zone, if asic temperature is greater than hot threshold + THERMAL_ZONE_HYSTERESIS, - and if cooling state is not MAX, we need enforce the cooling state to MAX - """ - asic_temp = utils.read_int_from_file(os.path.join(THERMAL_ZONE_ASIC_PATH, THERMAL_ZONE_TEMP_FILE), raise_exception=True) - hot_thresh = utils.read_int_from_file(os.path.join(THERMAL_ZONE_ASIC_PATH, THERMAL_ZONE_HOT_THRESHOLD), raise_exception=True) - if asic_temp >= hot_thresh + THERMAL_ZONE_HYSTERESIS: - cls.expect_cooling_state = MAX_COOLING_LEVEL - else: - cls.expect_cooling_state = None - class RemovableThermal(Thermal): def __init__(self, name, temp_file, high_th_file, high_crit_th_file, position, presence_cb): diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_actions.py b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_actions.py deleted file mode 100644 index bada4476d4c2..000000000000 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_actions.py +++ /dev/null @@ -1,111 +0,0 @@ -# -# Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. -# Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase -from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object -from .thermal import Thermal - - -class SetFanSpeedAction(ThermalPolicyActionBase): - """ - Base thermal action class to set speed for fans - """ - # JSON field definition - JSON_FIELD_SPEED = 'speed' - - def __init__(self): - """ - Constructor of SetFanSpeedAction which actually do nothing. - """ - self.speed = None - - def load_from_json(self, json_obj): - """ - Construct SetFanSpeedAction via JSON. JSON example: - { - "type": "fan.all.set_speed" - "speed": "100" - } - :param json_obj: A JSON object representing a SetFanSpeedAction action. - :return: - """ - if SetFanSpeedAction.JSON_FIELD_SPEED in json_obj: - speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) - if speed < 0 or speed > 100: - raise ValueError('SetFanSpeedAction invalid speed value {} in JSON policy file, valid value should be [0, 100]'. - format(speed)) - self.speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) - else: - raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. - format(SetFanSpeedAction.JSON_FIELD_SPEED)) - - -@thermal_json_object('fan.all.set_speed') -class SetAllFanSpeedAction(SetFanSpeedAction): - """ - Action to set speed for all fans - """ - def execute(self, thermal_info_dict): - """ - Set speed for all fans - :param thermal_info_dict: A dictionary stores all thermal information. - :return: - """ - Thermal.set_expect_cooling_level(self.speed / 10) - - -@thermal_json_object('thermal.recover') -class ThermalRecoverAction(ThermalPolicyActionBase): - UNKNOWN_SKU_COOLING_LEVEL = 6 - - def execute(self, thermal_info_dict): - from .device_data import DeviceDataManager - from .thermal import MAX_COOLING_LEVEL, MIN_COOLING_LEVEL_FOR_HIGH, logger - Thermal.monitor_asic_themal_zone() - - # Calculate dynamic minimum cooling level - dynamic_min_cooling_level = None - minimum_table = DeviceDataManager.get_minimum_table() - if not minimum_table: - # If there is no minimum_table defined, set dynamic_min_cooling_level to default value - dynamic_min_cooling_level = ThermalRecoverAction.UNKNOWN_SKU_COOLING_LEVEL - else: - trust_state = Thermal.check_module_temperature_trustable() - temperature = Thermal.get_min_amb_temperature() - temperature = int(temperature / 1000) - minimum_table = minimum_table['unk_{}'.format(trust_state)] - - for key, cooling_level in minimum_table.items(): - temp_range = key.split(':') - temp_min = int(temp_range[0].strip()) - temp_max = int(temp_range[1].strip()) - if temp_min <= temperature <= temp_max: - dynamic_min_cooling_level = cooling_level - 10 - break - - if not dynamic_min_cooling_level: - # Should not go to this branch, just in case - logger.log_error('Failed to get dynamic minimum cooling level') - dynamic_min_cooling_level = MAX_COOLING_LEVEL - - if Thermal.last_set_cooling_level is not None and dynamic_min_cooling_level > Thermal.last_set_cooling_level and dynamic_min_cooling_level >= MIN_COOLING_LEVEL_FOR_HIGH: - # No need to check thermal zone as dynamic_min_cooling_level is greater than previous value and MIN_COOLING_LEVEL_FOR_HIGH - Thermal.set_expect_cooling_level(dynamic_min_cooling_level) - else: - min_cooling_level_by_tz = Thermal.get_min_allowed_cooling_level_by_thermal_zone() - if min_cooling_level_by_tz is not None: - cooling_level = max(dynamic_min_cooling_level, min_cooling_level_by_tz) - Thermal.set_expect_cooling_level(cooling_level) diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_conditions.py b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_conditions.py deleted file mode 100644 index 24a22c41019b..000000000000 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_conditions.py +++ /dev/null @@ -1,92 +0,0 @@ -# -# Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. -# Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase -from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object - - -class FanCondition(ThermalPolicyConditionBase): - def get_fan_info(self, thermal_info_dict): - from .thermal_infos import FanInfo - if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): - return thermal_info_dict[FanInfo.INFO_NAME] - else: - return None - - -@thermal_json_object('fan.any.absence') -class AnyFanAbsenceCondition(FanCondition): - def is_match(self, thermal_info_dict): - fan_info_obj = self.get_fan_info(thermal_info_dict) - return len(fan_info_obj.get_absence_fans()) > 0 if fan_info_obj else False - - -@thermal_json_object('fan.all.absence') -class AllFanAbsenceCondition(FanCondition): - def is_match(self, thermal_info_dict): - fan_info_obj = self.get_fan_info(thermal_info_dict) - return len(fan_info_obj.get_presence_fans()) == 0 if fan_info_obj else False - - -@thermal_json_object('fan.all.presence') -class AllFanPresenceCondition(FanCondition): - def is_match(self, thermal_info_dict): - fan_info_obj = self.get_fan_info(thermal_info_dict) - return len(fan_info_obj.get_absence_fans()) == 0 if fan_info_obj else False - - -@thermal_json_object('fan.any.fault') -class AnyFanFaultCondition(FanCondition): - def is_match(self, thermal_info_dict): - fan_info_obj = self.get_fan_info(thermal_info_dict) - return len(fan_info_obj.get_fault_fans()) > 0 if fan_info_obj else False - - -@thermal_json_object('fan.all.good') -class AllFanGoodCondition(FanCondition): - def is_match(self, thermal_info_dict): - fan_info_obj = self.get_fan_info(thermal_info_dict) - return len(fan_info_obj.get_fault_fans()) == 0 if fan_info_obj else False - - -class PsuCondition(ThermalPolicyConditionBase): - def get_psu_info(self, thermal_info_dict): - from .thermal_infos import PsuInfo - if PsuInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[PsuInfo.INFO_NAME], PsuInfo): - return thermal_info_dict[PsuInfo.INFO_NAME] - else: - return None - - -@thermal_json_object('psu.any.absence') -class AnyPsuAbsenceCondition(PsuCondition): - def is_match(self, thermal_info_dict): - psu_info_obj = self.get_psu_info(thermal_info_dict) - return len(psu_info_obj.get_absence_psus()) > 0 if psu_info_obj else False - - -@thermal_json_object('psu.all.absence') -class AllPsuAbsenceCondition(PsuCondition): - def is_match(self, thermal_info_dict): - psu_info_obj = self.get_psu_info(thermal_info_dict) - return len(psu_info_obj.get_presence_psus()) == 0 if psu_info_obj else False - - -@thermal_json_object('psu.all.presence') -class AllPsuPresenceCondition(PsuCondition): - def is_match(self, thermal_info_dict): - psu_info_obj = self.get_psu_info(thermal_info_dict) - return len(psu_info_obj.get_absence_psus()) == 0 if psu_info_obj else False diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_infos.py b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_infos.py deleted file mode 100644 index f44afe735ab2..000000000000 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_infos.py +++ /dev/null @@ -1,171 +0,0 @@ -# -# Copyright (c) 2020-2021 NVIDIA CORPORATION & AFFILIATES. -# Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase -from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object - - -@thermal_json_object('fan_info') -class FanInfo(ThermalPolicyInfoBase): - """ - Fan information needed by thermal policy - """ - - # Fan information name - INFO_NAME = 'fan_info' - - def __init__(self): - self._absence_fans = set() - self._presence_fans = set() - self._fault_fans = set() - self._status_changed = False - - def collect(self, chassis): - """ - Collect absence and presence fans. - :param chassis: The chassis object - :return: - """ - self._status_changed = False - for fan_drawer in chassis.get_all_fan_drawers(): - for fan in fan_drawer.get_all_fans(): - presence = fan.get_presence() - status = fan.get_status() - if presence and fan not in self._presence_fans: - self._presence_fans.add(fan) - self._status_changed = True - if fan in self._absence_fans: - self._absence_fans.remove(fan) - elif not presence and fan not in self._absence_fans: - self._absence_fans.add(fan) - self._status_changed = True - if fan in self._presence_fans: - self._presence_fans.remove(fan) - - if not status and fan not in self._fault_fans: - self._fault_fans.add(fan) - self._status_changed = True - elif status and fan in self._fault_fans: - self._fault_fans.remove(fan) - self._status_changed = True - - - def get_absence_fans(self): - """ - Retrieves absence fans - :return: A set of absence fans - """ - return self._absence_fans - - def get_presence_fans(self): - """ - Retrieves presence fans - :return: A set of presence fans - """ - return self._presence_fans - - def get_fault_fans(self): - """ - Retrieves fault fans - :return: A set of fault fans - """ - return self._fault_fans - - def is_status_changed(self): - """ - Retrieves if the status of fan information changed - :return: True if status changed else False - """ - return self._status_changed - - -@thermal_json_object('psu_info') -class PsuInfo(ThermalPolicyInfoBase): - """ - PSU information needed by thermal policy - """ - INFO_NAME = 'psu_info' - - def __init__(self): - self._absence_psus = set() - self._presence_psus = set() - self._status_changed = False - - def collect(self, chassis): - """ - Collect absence and presence PSUs. - :param chassis: The chassis object - :return: - """ - self._status_changed = False - for psu in chassis.get_all_psus(): - if psu.get_presence() and psu not in self._presence_psus: - self._presence_psus.add(psu) - self._status_changed = True - if psu in self._absence_psus: - self._absence_psus.remove(psu) - elif (not psu.get_presence()) and psu not in self._absence_psus: - self._absence_psus.add(psu) - self._status_changed = True - if psu in self._presence_psus: - self._presence_psus.remove(psu) - - def get_absence_psus(self): - """ - Retrieves presence PSUs - :return: A set of absence PSUs - """ - return self._absence_psus - - def get_presence_psus(self): - """ - Retrieves presence PSUs - :return: A set of presence fans - """ - return self._presence_psus - - def is_status_changed(self): - """ - Retrieves if the status of PSU information changed - :return: True if status changed else False - """ - return self._status_changed - - -@thermal_json_object('chassis_info') -class ChassisInfo(ThermalPolicyInfoBase): - """ - Chassis information needed by thermal policy - """ - INFO_NAME = 'chassis_info' - - def __init__(self): - self._chassis = None - - def collect(self, chassis): - """ - Collect platform chassis. - :param chassis: The chassis object - :return: - """ - self._chassis = chassis - - def get_chassis(self): - """ - Retrieves platform chassis object - :return: A platform chassis object. - """ - return self._chassis diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_manager.py b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_manager.py index dcdd25e90635..6c7cb688a5d9 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_manager.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal_manager.py @@ -15,81 +15,9 @@ # limitations under the License. # from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase -from .cpu_thermal_control import CPUThermalControl -from .device_data import DeviceDataManager -from .thermal_actions import * -from .thermal_conditions import * -from .thermal_infos import * -from .thermal import logger, MAX_COOLING_LEVEL, Thermal class ThermalManager(ThermalManagerBase): - cpu_thermal_control = None - - @classmethod - def start_thermal_control_algorithm(cls): - """ - Start thermal control algorithm - - Returns: - bool: True if set success, False if fail. - """ - Thermal.set_thermal_algorithm_status(True) - - @classmethod - def stop_thermal_control_algorithm(cls): - """ - Stop thermal control algorithm - - Returns: - bool: True if set success, False if fail. - """ - Thermal.set_thermal_algorithm_status(False) - - @classmethod - def start_cpu_thermal_control_algoritm(cls): - if cls.cpu_thermal_control: - return - - if not DeviceDataManager.is_cpu_thermal_control_supported(): - return - - cls.cpu_thermal_control = CPUThermalControl() - cls.cpu_thermal_control.task_run() - - @classmethod - def stop_cpu_thermal_control_algoritm(cls): - if cls.cpu_thermal_control: - cls.cpu_thermal_control.task_stop() - cls.cpu_thermal_control = None - @classmethod def run_policy(cls, chassis): - if cls._running: - cls.start_cpu_thermal_control_algoritm() - else: - cls.stop_cpu_thermal_control_algoritm() - - if not cls._policy_dict: - return - - try: - cls._collect_thermal_information(chassis) - except Exception as e: - logger.log_error('Failed to collect thermal information {}'.format(repr(e))) - Thermal.set_expect_cooling_level(MAX_COOLING_LEVEL) - Thermal.commit_cooling_level(cls._thermal_info_dict) - return - - for policy in cls._policy_dict.values(): - if not cls._running: - return - try: - if policy.is_match(cls._thermal_info_dict): - policy.do_action(cls._thermal_info_dict) - except Exception as e: - logger.log_error('Failed to run thermal policy {} - {}'.format(policy.name, repr(e))) - # In case there is an exception, we put cooling level to max value - Thermal.set_expect_cooling_level(MAX_COOLING_LEVEL) - - Thermal.commit_cooling_level(cls._thermal_info_dict) + pass diff --git a/platform/mellanox/mlnx-platform-api/tests/duplicate_action.json b/platform/mellanox/mlnx-platform-api/tests/duplicate_action.json deleted file mode 100644 index c19787aa26e0..000000000000 --- a/platform/mellanox/mlnx-platform-api/tests/duplicate_action.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "any fan absence", - "conditions": [ - { - "type": "fan.any.absence" - } - ], - "actions": [ - { - "type": "fan.all.set_speed", - "speed": "100" - }, - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] -} diff --git a/platform/mellanox/mlnx-platform-api/tests/duplicate_condition.json b/platform/mellanox/mlnx-platform-api/tests/duplicate_condition.json deleted file mode 100644 index c25d84762e2a..000000000000 --- a/platform/mellanox/mlnx-platform-api/tests/duplicate_condition.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "any fan absence", - "conditions": [ - { - "type": "fan.any.absence" - }, - { - "type": "fan.any.absence" - } - ], - "actions": [ - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] -} diff --git a/platform/mellanox/mlnx-platform-api/tests/empty_action.json b/platform/mellanox/mlnx-platform-api/tests/empty_action.json deleted file mode 100644 index b1051b5a6f60..000000000000 --- a/platform/mellanox/mlnx-platform-api/tests/empty_action.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "any fan absence", - "conditions": [ - { - "type": "fan.any.absence" - } - ], - "actions": [ - ] -} \ No newline at end of file diff --git a/platform/mellanox/mlnx-platform-api/tests/empty_condition.json b/platform/mellanox/mlnx-platform-api/tests/empty_condition.json deleted file mode 100644 index e7a588459246..000000000000 --- a/platform/mellanox/mlnx-platform-api/tests/empty_condition.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "any fan absence", - "conditions": [ - ], - "actions": [ - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] -} \ No newline at end of file diff --git a/platform/mellanox/mlnx-platform-api/tests/policy_with_same_conditions.json b/platform/mellanox/mlnx-platform-api/tests/policy_with_same_conditions.json deleted file mode 100644 index 9efe773a9b07..000000000000 --- a/platform/mellanox/mlnx-platform-api/tests/policy_with_same_conditions.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "thermal_control_algorithm": { - "run_at_boot_up": "false", - "fan_speed_when_suspend": "60" - }, - "info_types": [ - { - "type": "fan_info" - }, - { - "type": "psu_info" - }, - { - "type": "chassis_info" - } - ], - "policies": [ - { - "name": "all fan and psu presence", - "conditions": [ - { - "type": "fan.all.presence" - }, - { - "type": "psu.all.presence" - } - ], - "actions": [ - { - "type": "thermal.recover" - }, - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] - }, - { - "name": "any psu absence", - "conditions": [ - { - "type": "psu.any.absence" - } - ], - "actions": [ - { - "type": "thermal.recover" - }, - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] - }, - { - "name": "all fan and psu presence 1", - "conditions": [ - { - "type": "fan.all.presence" - }, - { - "type": "psu.all.presence" - } - ], - "actions": [ - { - "type": "thermal.recover" - } - ] - } - ] -} \ No newline at end of file diff --git a/platform/mellanox/mlnx-platform-api/tests/test_cpu_thermal_control.py b/platform/mellanox/mlnx-platform-api/tests/test_cpu_thermal_control.py deleted file mode 100644 index 8970e659c0c8..000000000000 --- a/platform/mellanox/mlnx-platform-api/tests/test_cpu_thermal_control.py +++ /dev/null @@ -1,83 +0,0 @@ -# -# Copyright (c) 2019-2022 NVIDIA CORPORATION & AFFILIATES. -# Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -############################################################################# -# Mellanox -# -# Module contains an implementation of SONiC Platform Base API and -# provides the Chassis information which are available in the platform -# -############################################################################# - -import glob -import os -import pytest -import sys -if sys.version_info.major == 3: - from unittest import mock -else: - import mock - -test_path = os.path.dirname(os.path.abspath(__file__)) -modules_path = os.path.dirname(test_path) -sys.path.insert(0, modules_path) - -from sonic_platform.cpu_thermal_control import CPUThermalControl - - -class TestCPUThermalControl: - @mock.patch('sonic_platform.device_data.DeviceDataManager.get_cpu_thermal_threshold', mock.MagicMock(return_value=(85, 95))) - @mock.patch('sonic_platform.utils.read_int_from_file') - @mock.patch('sonic_platform.utils.write_file') - def test_run(self, mock_write_file, mock_read_file): - instance = CPUThermalControl() - file_content = { - CPUThermalControl.CPU_COOLING_STATE: 5, - CPUThermalControl.CPU_TEMP_FILE: instance.temp_high + 1 - } - - def read_file(file_path, **kwargs): - return file_content[file_path] - - mock_read_file.side_effect = read_file - # Test current temp is higher than high threshold - instance.run(0) - mock_write_file.assert_called_with(CPUThermalControl.CPU_COOLING_STATE, CPUThermalControl.MAX_COOLING_STATE, log_func=None) - - # Test current temp is lower than low threshold - file_content[CPUThermalControl.CPU_TEMP_FILE] = instance.temp_low - 1 - instance.run(0) - mock_write_file.assert_called_with(CPUThermalControl.CPU_COOLING_STATE, CPUThermalControl.MIN_COOLING_STATE, log_func=None) - - # Test current temp increasing - file_content[CPUThermalControl.CPU_TEMP_FILE] = instance.temp_low - instance.run(0) - mock_write_file.assert_called_with(CPUThermalControl.CPU_COOLING_STATE, 6, log_func=None) - - # Test current temp decreasing - instance.run(instance.temp_low + 1) - mock_write_file.assert_called_with(CPUThermalControl.CPU_COOLING_STATE, 4, log_func=None) - - # Test current temp increasing and current cooling state is already the max - file_content[CPUThermalControl.CPU_TEMP_FILE] = 85 - file_content[CPUThermalControl.CPU_COOLING_STATE] = CPUThermalControl.MAX_COOLING_STATE - instance.run(84) - mock_write_file.assert_called_with(CPUThermalControl.CPU_COOLING_STATE, CPUThermalControl.MAX_COOLING_STATE, log_func=None) - - # Test current temp decreasing and current cooling state is already the max - file_content[CPUThermalControl.CPU_COOLING_STATE] = CPUThermalControl.MIN_COOLING_STATE - instance.run(86) - mock_write_file.assert_called_with(CPUThermalControl.CPU_COOLING_STATE, CPUThermalControl.MIN_COOLING_STATE, log_func=None) diff --git a/platform/mellanox/mlnx-platform-api/tests/test_fan_api.py b/platform/mellanox/mlnx-platform-api/tests/test_fan_api.py index 8f51ddb31681..1a16d1ae61f0 100644 --- a/platform/mellanox/mlnx-platform-api/tests/test_fan_api.py +++ b/platform/mellanox/mlnx-platform-api/tests/test_fan_api.py @@ -108,11 +108,10 @@ def test_system_fan_set_speed(self, mock_write_file): mock_write_file.assert_called_with(fan.fan_speed_set_path, 153, raise_exception=True) @patch('sonic_platform.utils.read_int_from_file') - @patch('sonic_platform.thermal.Thermal.get_cooling_level') @patch('sonic_platform.psu.Psu.get_presence') @patch('sonic_platform.psu.Psu.get_powergood_status') @patch('os.path.exists') - def test_psu_fan_basic(self, mock_path_exists, mock_powergood, mock_presence, mock_cooling_level, mock_read_int): + def test_psu_fan_basic(self, mock_path_exists, mock_powergood, mock_presence, mock_read_int): mock_path_exists.return_value = False psu = Psu(0) fan = PsuFan(0, 1, psu) @@ -125,7 +124,7 @@ def test_psu_fan_basic(self, mock_path_exists, mock_powergood, mock_presence, mo assert fan.get_presence() is False mock_path_exists.return_value = True assert fan.get_presence() is True - mock_cooling_level.return_value = 7 + mock_read_int.return_value = 7 assert fan.get_target_speed() == 70 mock_read_int.return_value = FAN_DIR_VALUE_INTAKE assert fan.get_direction() == Fan.FAN_DIRECTION_INTAKE diff --git a/platform/mellanox/mlnx-platform-api/tests/test_thermal.py b/platform/mellanox/mlnx-platform-api/tests/test_thermal.py index d906fdf4e02f..db81f73096f4 100644 --- a/platform/mellanox/mlnx-platform-api/tests/test_thermal.py +++ b/platform/mellanox/mlnx-platform-api/tests/test_thermal.py @@ -205,149 +205,3 @@ def test_get_high_critical_threshold(self, mock_read): mock_read.return_value = None assert thermal.get_high_critical_threshold() is None - - @mock.patch('glob.iglob', mock.MagicMock(return_value=['thermal_zone1', 'thermal_zone2'])) - @mock.patch('sonic_platform.utils.write_file') - def test_set_thermal_algorithm_status(self, mock_write): - from sonic_platform.thermal import Thermal, THERMAL_ZONE_FOLDER_WILDCARD, THERMAL_ZONE_POLICY_FILE, THERMAL_ZONE_MODE_FILE - assert Thermal.set_thermal_algorithm_status(True, False) - - for folder in glob.iglob(THERMAL_ZONE_FOLDER_WILDCARD): - mock_write.assert_any_call(os.path.join(folder, THERMAL_ZONE_POLICY_FILE), 'step_wise') - mock_write.assert_any_call(os.path.join(folder, THERMAL_ZONE_MODE_FILE), 'enabled') - - assert Thermal.set_thermal_algorithm_status(False, False) - for folder in glob.iglob(THERMAL_ZONE_FOLDER_WILDCARD): - mock_write.assert_any_call(os.path.join(folder, THERMAL_ZONE_POLICY_FILE), 'user_space') - mock_write.assert_any_call(os.path.join(folder, THERMAL_ZONE_MODE_FILE), 'disabled') - - assert not Thermal.set_thermal_algorithm_status(False, False) - - assert Thermal.set_thermal_algorithm_status(False) - - @mock.patch('glob.iglob', mock.MagicMock(return_value=['thermal_zone1', 'thermal_zone2'])) - @mock.patch('sonic_platform.utils.read_int_from_file') - def test_get_min_allowed_cooling_level_by_thermal_zone(self, mock_read_file): - from sonic_platform.thermal import Thermal, THERMAL_ZONE_TEMP_FILE, THERMAL_ZONE_HIGH_THRESHOLD, THERMAL_ZONE_NORMAL_THRESHOLD, MIN_COOLING_LEVEL_FOR_HIGH, MIN_COOLING_LEVEL_FOR_NORMAL - mock_read_file.side_effect = Exception('') - assert Thermal.get_min_allowed_cooling_level_by_thermal_zone() is None - - mock_file_content = {} - def mock_read_int_from_file(file_path, default=0, raise_exception=False): - return mock_file_content[file_path] - - mock_read_file.side_effect = mock_read_int_from_file - mock_file_content[os.path.join('thermal_zone1', THERMAL_ZONE_NORMAL_THRESHOLD)] = 75000 - mock_file_content[os.path.join('thermal_zone1', THERMAL_ZONE_HIGH_THRESHOLD)] = 85000 - mock_file_content[os.path.join('thermal_zone1', THERMAL_ZONE_TEMP_FILE)] = 69000 - mock_file_content[os.path.join('thermal_zone2', THERMAL_ZONE_NORMAL_THRESHOLD)] = 75000 - mock_file_content[os.path.join('thermal_zone1', THERMAL_ZONE_HIGH_THRESHOLD)] = 85000 - mock_file_content[os.path.join('thermal_zone2', THERMAL_ZONE_TEMP_FILE)] = 24000 - assert Thermal.get_min_allowed_cooling_level_by_thermal_zone() == MIN_COOLING_LEVEL_FOR_NORMAL - - mock_file_content[os.path.join('thermal_zone1', THERMAL_ZONE_TEMP_FILE)] = 71000 - assert Thermal.get_min_allowed_cooling_level_by_thermal_zone() == MIN_COOLING_LEVEL_FOR_HIGH - - mock_file_content[os.path.join('thermal_zone1', THERMAL_ZONE_TEMP_FILE)] = 79000 - assert Thermal.get_min_allowed_cooling_level_by_thermal_zone() == MIN_COOLING_LEVEL_FOR_HIGH - - mock_file_content[os.path.join('thermal_zone1', THERMAL_ZONE_TEMP_FILE)] = 81000 - assert Thermal.get_min_allowed_cooling_level_by_thermal_zone() is None - - @mock.patch('glob.iglob', mock.MagicMock(return_value=['thermal_zone1', 'thermal_zone2'])) - @mock.patch('sonic_platform.utils.read_int_from_file') - def test_no_sensor_thermal_zone(self, mock_read_file): - from sonic_platform.thermal import Thermal, THERMAL_ZONE_TEMP_FILE, THERMAL_ZONE_HIGH_THRESHOLD, THERMAL_ZONE_NORMAL_THRESHOLD, MIN_COOLING_LEVEL_FOR_HIGH, MIN_COOLING_LEVEL_FOR_NORMAL - - mock_file_content = {} - def mock_read_int_from_file(file_path, **kwargs): - return mock_file_content[file_path] - - mock_read_file.side_effect = mock_read_int_from_file - mock_file_content[os.path.join('thermal_zone1', THERMAL_ZONE_NORMAL_THRESHOLD)] = 0 - mock_file_content[os.path.join('thermal_zone1', THERMAL_ZONE_HIGH_THRESHOLD)] = 0 - mock_file_content[os.path.join('thermal_zone1', THERMAL_ZONE_TEMP_FILE)] = 0 - mock_file_content[os.path.join('thermal_zone2', THERMAL_ZONE_NORMAL_THRESHOLD)] = 75000 - mock_file_content[os.path.join('thermal_zone2', THERMAL_ZONE_HIGH_THRESHOLD)] = 85000 - mock_file_content[os.path.join('thermal_zone2', THERMAL_ZONE_TEMP_FILE)] = 24000 - assert Thermal.get_min_allowed_cooling_level_by_thermal_zone() == MIN_COOLING_LEVEL_FOR_NORMAL - - mock_file_content[os.path.join('thermal_zone2', THERMAL_ZONE_TEMP_FILE)] = 71000 - assert Thermal.get_min_allowed_cooling_level_by_thermal_zone() == MIN_COOLING_LEVEL_FOR_HIGH - - mock_file_content[os.path.join('thermal_zone2', THERMAL_ZONE_TEMP_FILE)] = 79000 - assert Thermal.get_min_allowed_cooling_level_by_thermal_zone() == MIN_COOLING_LEVEL_FOR_HIGH - - mock_file_content[os.path.join('thermal_zone2', THERMAL_ZONE_TEMP_FILE)] = 81000 - assert Thermal.get_min_allowed_cooling_level_by_thermal_zone() is None - - @mock.patch('glob.iglob', mock.MagicMock(return_value=['thermal_zone1', 'thermal_zone2'])) - def test_check_module_temperature_trustable(self): - from sonic_platform.thermal import Thermal - from sonic_platform import utils - - utils.read_int_from_file = mock.MagicMock(return_value=1) - assert Thermal.check_module_temperature_trustable() == 'untrust' - - utils.read_int_from_file = mock.MagicMock(return_value=0) - assert Thermal.check_module_temperature_trustable() == 'trust' - - def test_get_min_amb_temperature(self): - from sonic_platform.thermal import Thermal, MAX_AMBIENT_TEMP, CHASSIS_THERMAL_SYSFS_FOLDER - from sonic_platform import utils - - utils.read_int_from_file = mock.MagicMock(side_effect=Exception('')) - assert Thermal.get_min_amb_temperature() == MAX_AMBIENT_TEMP - - mock_file_content = {} - def mock_read_int_from_file(file_path, default=0, raise_exception=False): - return mock_file_content[file_path] - - utils.read_int_from_file = mock_read_int_from_file - mock_file_content[os.path.join(CHASSIS_THERMAL_SYSFS_FOLDER, 'fan_amb')] = 50 - mock_file_content[os.path.join(CHASSIS_THERMAL_SYSFS_FOLDER, 'port_amb')] = 40 - assert Thermal.get_min_amb_temperature() == 40 - - @mock.patch('sonic_platform.utils.write_file') - def test_set_cooling_level(self, mock_write_file): - from sonic_platform.thermal import Thermal, COOLING_STATE_PATH - Thermal.set_cooling_level(10) - calls = [mock.call(COOLING_STATE_PATH, 20, raise_exception=True)] - mock_write_file.assert_has_calls(calls) - - pre_call_count = mock_write_file.call_count - Thermal.set_cooling_level(10) - assert pre_call_count == mock_write_file.call_count - - Thermal.set_cooling_level(9) - calls = [mock.call(COOLING_STATE_PATH, 19, raise_exception=True)] - mock_write_file.assert_has_calls(calls) - - @mock.patch('sonic_platform.utils.write_file') - def test_set_cooling_state(self, mock_write_file): - from sonic_platform.thermal import Thermal, COOLING_STATE_PATH - Thermal.set_cooling_state(10) - calls = [mock.call(COOLING_STATE_PATH, 10, raise_exception=True)] - mock_write_file.assert_has_calls(calls) - - pre_call_count = mock_write_file.call_count - Thermal.set_cooling_state(10) - assert pre_call_count == mock_write_file.call_count - - Thermal.set_cooling_state(9) - calls = [mock.call(COOLING_STATE_PATH, 9, raise_exception=True)] - mock_write_file.assert_has_calls(calls) - - @mock.patch('sonic_platform.utils.read_int_from_file') - def test_get_cooling_level(self, mock_read_file): - from sonic_platform.thermal import Thermal, COOLING_STATE_PATH - Thermal.get_cooling_level() - mock_read_file.assert_called_with(COOLING_STATE_PATH, raise_exception=True) - - mock_read_file.side_effect = IOError('') - with pytest.raises(RuntimeError): - Thermal.get_cooling_level() - - mock_read_file.side_effect = ValueError('') - with pytest.raises(RuntimeError): - Thermal.get_cooling_level() diff --git a/platform/mellanox/mlnx-platform-api/tests/test_thermal_policy.py b/platform/mellanox/mlnx-platform-api/tests/test_thermal_policy.py deleted file mode 100644 index ffdc6afbb0a9..000000000000 --- a/platform/mellanox/mlnx-platform-api/tests/test_thermal_policy.py +++ /dev/null @@ -1,510 +0,0 @@ -# -# Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. -# Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import os -import sys -import pytest -import json -from mock import MagicMock, patch -from .mock_platform import MockChassis, MockFan, MockFanDrawer, MockPsu - -test_path = os.path.dirname(os.path.abspath(__file__)) -modules_path = os.path.dirname(test_path) -sys.path.insert(0, modules_path) - -from sonic_platform.thermal_manager import ThermalManager -from sonic_platform.thermal_infos import FanInfo, PsuInfo -from sonic_platform.thermal import Thermal, MAX_COOLING_LEVEL -from sonic_platform.device_data import DeviceDataManager - - -@pytest.fixture(scope='session', autouse=True) -def thermal_manager(): - policy_file = os.path.join(test_path, 'thermal_policy.json') - ThermalManager.load(policy_file) - return ThermalManager - - -def test_load_policy(thermal_manager): - assert 'psu_info' in thermal_manager._thermal_info_dict - assert 'fan_info' in thermal_manager._thermal_info_dict - assert 'chassis_info' in thermal_manager._thermal_info_dict - - assert 'any fan absence' in thermal_manager._policy_dict - assert 'any psu absence' in thermal_manager._policy_dict - assert 'any fan broken' in thermal_manager._policy_dict - assert 'all fan and psu presence' in thermal_manager._policy_dict - - assert thermal_manager._fan_speed_when_suspend == 60 - assert thermal_manager._run_thermal_algorithm_at_boot_up == False - - -def test_fan_info(): - chassis = MockChassis() - chassis.make_fan_absence() - fan_info = FanInfo() - fan_info.collect(chassis) - assert len(fan_info.get_absence_fans()) == 1 - assert len(fan_info.get_presence_fans()) == 0 - assert len(fan_info.get_fault_fans()) == 0 - assert fan_info.is_status_changed() - - chassis.get_all_fan_drawers()[0].get_all_fans()[0].presence = True - fan_info.collect(chassis) - assert len(fan_info.get_absence_fans()) == 0 - assert len(fan_info.get_presence_fans()) == 1 - assert len(fan_info.get_fault_fans()) == 0 - assert fan_info.is_status_changed() - - chassis.get_all_fan_drawers()[0].get_all_fans()[0].status = False - fan_info.collect(chassis) - assert len(fan_info.get_absence_fans()) == 0 - assert len(fan_info.get_presence_fans()) == 1 - assert len(fan_info.get_fault_fans()) == 1 - assert fan_info.is_status_changed() - -def test_psu_info(): - chassis = MockChassis() - chassis.make_psu_absence() - psu_info = PsuInfo() - psu_info.collect(chassis) - assert len(psu_info.get_absence_psus()) == 1 - assert len(psu_info.get_presence_psus()) == 0 - assert psu_info.is_status_changed() - - psu_list = chassis.get_all_psus() - psu_list[0].presence = True - psu_info.collect(chassis) - assert len(psu_info.get_absence_psus()) == 0 - assert len(psu_info.get_presence_psus()) == 1 - assert psu_info.is_status_changed() - - psu_list[0].powergood = False - psu_info.collect(chassis) - assert len(psu_info.get_absence_psus()) == 0 - assert len(psu_info.get_presence_psus()) == 1 - assert not psu_info.is_status_changed() - - -@patch('sonic_platform.thermal.Thermal.monitor_asic_themal_zone', MagicMock()) -@patch('sonic_platform.thermal.Thermal.get_cooling_level', MagicMock(return_value=6)) -@patch('sonic_platform.thermal.Thermal.get_min_allowed_cooling_level_by_thermal_zone', MagicMock(return_value=2)) -@patch('sonic_platform.thermal.Thermal.set_cooling_state') -@patch('sonic_platform.thermal.Thermal.set_cooling_level') -def test_fan_policy(mock_set_cooling_level, mock_set_cooling_state, thermal_manager): - print('In test_fan_policy') - from sonic_platform.thermal import MIN_COOLING_LEVEL_FOR_NORMAL - chassis = MockChassis() - chassis.make_fan_absence() - chassis.get_all_fan_drawers()[0].get_all_fans().append(MockFan()) - chassis.platform_name = 'some_platform' - thermal_manager.run_policy(chassis) - - mock_set_cooling_level.assert_called_with(MAX_COOLING_LEVEL) - mock_set_cooling_state.assert_called_with(MAX_COOLING_LEVEL) - - Thermal.expect_cooling_level = None - fan_list = chassis.get_all_fan_drawers()[0].get_all_fans() - fan_list[0].presence = True - thermal_manager.run_policy(chassis) - mock_set_cooling_level.assert_called_with(6) - mock_set_cooling_state.assert_called_with(6) - - Thermal.expect_cooling_level = None - fan_list[0].status = False - thermal_manager.run_policy(chassis) - mock_set_cooling_level.assert_called_with(MAX_COOLING_LEVEL) - - Thermal.expect_cooling_level = None - fan_list[0].status = True - thermal_manager.run_policy(chassis) - mock_set_cooling_level.assert_called_with(6) - mock_set_cooling_state.assert_called_with(6) - - -@patch('sonic_platform.thermal.Thermal.monitor_asic_themal_zone', MagicMock()) -@patch('sonic_platform.thermal.Thermal.get_min_allowed_cooling_level_by_thermal_zone', MagicMock(return_value=2)) -@patch('sonic_platform.thermal.Thermal.get_cooling_level', MagicMock(return_value=6)) -@patch('sonic_platform.thermal.Thermal.set_cooling_state') -@patch('sonic_platform.thermal.Thermal.set_cooling_level') -def test_psu_policy(mock_set_cooling_level, mock_set_cooling_state, thermal_manager): - chassis = MockChassis() - chassis.make_psu_absence() - chassis.platform_name = 'some_platform' - thermal_manager.run_policy(chassis) - mock_set_cooling_level.assert_called_with(MAX_COOLING_LEVEL) - mock_set_cooling_state.assert_called_with(MAX_COOLING_LEVEL) - - psu_list = chassis.get_all_psus() - psu_list[0].presence = True - thermal_manager.run_policy(chassis) - mock_set_cooling_level.assert_called_with(6) - mock_set_cooling_state.assert_called_with(6) - - -def test_any_fan_absence_condition(): - chassis = MockChassis() - chassis.make_fan_absence() - fan_info = FanInfo() - fan_info.collect(chassis) - - from sonic_platform.thermal_conditions import AnyFanAbsenceCondition - condition = AnyFanAbsenceCondition() - assert condition.is_match({'fan_info': fan_info}) - - fan = chassis.get_all_fan_drawers()[0].get_all_fans()[0] - fan.presence = True - fan_info.collect(chassis) - assert not condition.is_match({'fan_info': fan_info}) - - -def test_all_fan_absence_condition(): - chassis = MockChassis() - chassis.make_fan_absence() - fan = MockFan() - fan_list = chassis.get_all_fan_drawers()[0].get_all_fans() - fan_list.append(fan) - fan_info = FanInfo() - fan_info.collect(chassis) - - from sonic_platform.thermal_conditions import AllFanAbsenceCondition - condition = AllFanAbsenceCondition() - assert not condition.is_match({'fan_info': fan_info}) - - fan.presence = False - fan_info.collect(chassis) - assert condition.is_match({'fan_info': fan_info}) - - -def test_all_fan_presence_condition(): - chassis = MockChassis() - chassis.make_fan_absence() - fan = MockFan() - fan_list = chassis.get_all_fan_drawers()[0].get_all_fans() - fan_list.append(fan) - fan_info = FanInfo() - fan_info.collect(chassis) - - from sonic_platform.thermal_conditions import AllFanPresenceCondition - condition = AllFanPresenceCondition() - assert not condition.is_match({'fan_info': fan_info}) - - fan_list[0].presence = True - fan_info.collect(chassis) - assert condition.is_match({'fan_info': fan_info}) - -def test_any_fan_fault_condition(): - chassis = MockChassis() - chassis.get_all_fan_drawers().append(MockFanDrawer()) - fan = MockFan() - fan_list = chassis.get_all_fan_drawers()[0].get_all_fans() - fan_list.append(fan) - fault_fan = MockFan() - fault_fan.status = False - fan_list.append(fault_fan) - fan_info = FanInfo() - fan_info.collect(chassis) - - from sonic_platform.thermal_conditions import AnyFanFaultCondition - condition = AnyFanFaultCondition() - assert condition.is_match({'fan_info': fan_info}) - - fault_fan.status = True - fan_info.collect(chassis) - assert not condition.is_match({'fan_info': fan_info}) - -def test_all_fan_good_condition(): - chassis = MockChassis() - chassis.get_all_fan_drawers().append(MockFanDrawer()) - fan = MockFan() - fan_list = chassis.get_all_fan_drawers()[0].get_all_fans() - fan_list.append(fan) - fault_fan = MockFan() - fault_fan.status = False - fan_list.append(fault_fan) - fan_info = FanInfo() - fan_info.collect(chassis) - - from sonic_platform.thermal_conditions import AllFanGoodCondition - condition = AllFanGoodCondition() - assert not condition.is_match({'fan_info': fan_info}) - - fault_fan.status = True - fan_info.collect(chassis) - assert condition.is_match({'fan_info': fan_info}) - - -def test_any_psu_absence_condition(): - chassis = MockChassis() - chassis.make_psu_absence() - psu_info = PsuInfo() - psu_info.collect(chassis) - - from sonic_platform.thermal_conditions import AnyPsuAbsenceCondition - condition = AnyPsuAbsenceCondition() - assert condition.is_match({'psu_info': psu_info}) - - psu = chassis.get_all_psus()[0] - psu.presence = True - psu_info.collect(chassis) - assert not condition.is_match({'psu_info': psu_info}) - - -def test_all_psu_absence_condition(): - chassis = MockChassis() - chassis.make_psu_absence() - psu = MockPsu() - psu_list = chassis.get_all_psus() - psu_list.append(psu) - psu_info = PsuInfo() - psu_info.collect(chassis) - - from sonic_platform.thermal_conditions import AllPsuAbsenceCondition - condition = AllPsuAbsenceCondition() - assert not condition.is_match({'psu_info': psu_info}) - - psu.presence = False - psu_info.collect(chassis) - assert condition.is_match({'psu_info': psu_info}) - - -def test_all_fan_presence_condition(): - chassis = MockChassis() - chassis.make_psu_absence() - psu = MockPsu() - psu_list = chassis.get_all_psus() - psu_list.append(psu) - psu_info = PsuInfo() - psu_info.collect(chassis) - - from sonic_platform.thermal_conditions import AllPsuPresenceCondition - condition = AllPsuPresenceCondition() - assert not condition.is_match({'psu_info': psu_info}) - - psu_list[0].presence = True - psu_info.collect(chassis) - assert condition.is_match({'psu_info': psu_info}) - - -def test_load_set_fan_speed_action(): - from sonic_platform.thermal_actions import SetAllFanSpeedAction - action = SetAllFanSpeedAction() - json_str = '{\"speed\": \"50\"}' - json_obj = json.loads(json_str) - action.load_from_json(json_obj) - assert action.speed == 50 - - json_str = '{\"speed\": \"-1\"}' - json_obj = json.loads(json_str) - with pytest.raises(ValueError): - action.load_from_json(json_obj) - - json_str = '{\"speed\": \"101\"}' - json_obj = json.loads(json_str) - with pytest.raises(ValueError): - action.load_from_json(json_obj) - - json_str = '{\"invalid\": \"101\"}' - json_obj = json.loads(json_str) - with pytest.raises(ValueError): - action.load_from_json(json_obj) - - -@patch('sonic_platform.thermal.Thermal.set_cooling_level', MagicMock()) -def test_execute_set_fan_speed_action(): - chassis = MockChassis() - chassis.get_all_fan_drawers().append(MockFanDrawer()) - fan_list = chassis.get_all_fan_drawers()[0].get_all_fans() - fan_list.append(MockFan()) - fan_list.append(MockFan()) - fan_info = FanInfo() - fan_info.collect(chassis) - - Thermal.expect_cooling_level = None - from sonic_platform.thermal_actions import SetAllFanSpeedAction - action = SetAllFanSpeedAction() - action.speed = 20 - action.execute({'fan_info': fan_info}) - assert Thermal.expect_cooling_level == 2 - - -def test_load_duplicate_condition(): - from sonic_platform_base.sonic_thermal_control.thermal_policy import ThermalPolicy - with open(os.path.join(test_path, 'duplicate_condition.json')) as f: - json_obj = json.load(f) - policy = ThermalPolicy() - with pytest.raises(Exception): - policy.load_from_json(json_obj) - -def test_load_duplicate_action(): - from sonic_platform_base.sonic_thermal_control.thermal_policy import ThermalPolicy - with open(os.path.join(test_path, 'duplicate_action.json')) as f: - json_obj = json.load(f) - policy = ThermalPolicy() - with pytest.raises(Exception): - policy.load_from_json(json_obj) - -def test_load_empty_condition(): - from sonic_platform_base.sonic_thermal_control.thermal_policy import ThermalPolicy - with open(os.path.join(test_path, 'empty_condition.json')) as f: - json_obj = json.load(f) - policy = ThermalPolicy() - with pytest.raises(Exception): - policy.load_from_json(json_obj) - -def test_load_empty_action(): - from sonic_platform_base.sonic_thermal_control.thermal_policy import ThermalPolicy - with open(os.path.join(test_path, 'empty_action.json')) as f: - json_obj = json.load(f) - policy = ThermalPolicy() - with pytest.raises(Exception): - policy.load_from_json(json_obj) - -def test_load_policy_with_same_conditions(): - from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase - class MockThermalManager(ThermalManagerBase): - pass - - with pytest.raises(Exception): - MockThermalManager.load(os.path.join(test_path, 'policy_with_same_conditions.json')) - -def test_dynamic_minimum_table_data(): - from sonic_platform.device_data import DEVICE_DATA - for platform, platform_data in DEVICE_DATA.items(): - if 'thermal' in platform_data and 'minimum_table' in platform_data['thermal']: - minimum_table = platform_data['thermal']['minimum_table'] - check_minimum_table_data(platform, minimum_table) - -def check_minimum_table_data(platform, minimum_table): - valid_dir = ['p2c', 'c2p', 'unk'] - valid_trust_state = ['trust', 'untrust'] - - for category, data in minimum_table.items(): - key_data = category.split('_') - assert key_data[0] in valid_dir - assert key_data[1] in valid_trust_state - - data_list = [(value, key) for key, value in data.items()] - data_list.sort(key=lambda x : x[0]) - - previous_edge = None - previous_cooling_level = None - for item in data_list: - cooling_level = item[0] - range_str = item[1] - - ranges = range_str.split(':') - low = int(ranges[0]) - high = int(ranges[1]) - assert low < high - - if previous_edge is None: - assert low == -127 - else: - assert low - previous_edge == 1, '{}-{}-{} error, item={}'.format(platform, key_data[0], key_data[1], item) - previous_edge = high - - assert 10 <= cooling_level <= 20 - if previous_cooling_level is not None: - assert cooling_level > previous_cooling_level - previous_cooling_level = cooling_level - -@patch('sonic_platform.thermal.Thermal.monitor_asic_themal_zone', MagicMock()) -@patch('sonic_platform.device_data.DeviceDataManager.get_platform_name') -@patch('sonic_platform.thermal.Thermal.get_min_allowed_cooling_level_by_thermal_zone') -@patch('sonic_platform.thermal.Thermal.get_min_amb_temperature') -@patch('sonic_platform.thermal.Thermal.check_module_temperature_trustable') -def test_thermal_recover_policy(mock_check_trustable, mock_get_min_amb, moc_get_min_allowed, mock_platform_name): - from sonic_platform.thermal_infos import ChassisInfo - from sonic_platform.thermal_actions import ThermalRecoverAction - chassis = MockChassis() - mock_platform_name.return_value = 'invalid' - info = ChassisInfo() - info._chassis = chassis - thermal_info_dict = {ChassisInfo.INFO_NAME: info} - - Thermal.expect_cooling_level = None - action = ThermalRecoverAction() - moc_get_min_allowed.return_value = 2 - action.execute(thermal_info_dict) - assert Thermal.expect_cooling_level == 6 - Thermal.last_set_cooling_level = Thermal.expect_cooling_level - - Thermal.expect_cooling_level = None - mock_platform_name.return_value = 'x86_64-mlnx_msn2700-r0' - mock_check_trustable.return_value = 'trust' - mock_get_min_amb.return_value = 29999 - moc_get_min_allowed.return_value = None - action.execute(thermal_info_dict) - assert Thermal.expect_cooling_level is None - - moc_get_min_allowed.return_value = 4 - action.execute(thermal_info_dict) - assert Thermal.expect_cooling_level == 4 - Thermal.last_set_cooling_level = Thermal.expect_cooling_level - - mock_check_trustable.return_value = 'untrust' - mock_get_min_amb.return_value = 31001 - action.execute(thermal_info_dict) - assert Thermal.expect_cooling_level == 5 - - -@patch('sonic_platform.thermal.Thermal.set_cooling_state') -@patch('sonic_platform.utils.read_int_from_file') -def test_monitor_asic_themal_zone(mock_read_int, mock_set_cooling_state): - mock_read_int.side_effect = [111000, 105000] - Thermal.monitor_asic_themal_zone() - assert Thermal.expect_cooling_state == MAX_COOLING_LEVEL - Thermal.commit_cooling_level({}) - mock_set_cooling_state.assert_called_with(MAX_COOLING_LEVEL) - mock_read_int.reset() - mock_read_int.side_effect = [104000, 105000] - Thermal.monitor_asic_themal_zone() - assert Thermal.expect_cooling_state is None - - -def test_set_expect_cooling_level(): - Thermal.set_expect_cooling_level(5) - assert Thermal.expect_cooling_level == 5 - - Thermal.set_expect_cooling_level(3) - assert Thermal.expect_cooling_level == 5 - - Thermal.set_expect_cooling_level(10) - assert Thermal.expect_cooling_level == 10 - - -@patch('sonic_platform.thermal.Thermal.commit_cooling_level', MagicMock()) -@patch('sonic_platform.thermal_conditions.AnyFanFaultCondition.is_match') -@patch('sonic_platform.thermal_manager.ThermalManager._collect_thermal_information') -@patch('sonic_platform.thermal.Thermal.set_expect_cooling_level') -def test_run_policy(mock_expect, mock_collect_info, mock_match, thermal_manager): - chassis = MockChassis() - mock_collect_info.side_effect = Exception('') - thermal_manager.run_policy(chassis) - mock_expect.assert_called_with(MAX_COOLING_LEVEL) - - mock_collect_info.side_effect = None - mock_expect.reset_mock() - mock_match.side_effect = Exception('') - thermal_manager.run_policy(chassis) - mock_expect.assert_called_with(MAX_COOLING_LEVEL) - - thermal_manager.stop() - mock_expect.reset_mock() - thermal_manager.run_policy(chassis) - assert mock_expect.call_count == 0 - diff --git a/platform/mellanox/mlnx-platform-api/tests/thermal_policy.json b/platform/mellanox/mlnx-platform-api/tests/thermal_policy.json deleted file mode 100644 index 5155c0718522..000000000000 --- a/platform/mellanox/mlnx-platform-api/tests/thermal_policy.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "thermal_control_algorithm": { - "run_at_boot_up": "false", - "fan_speed_when_suspend": "60" - }, - "info_types": [ - { - "type": "fan_info" - }, - { - "type": "psu_info" - }, - { - "type": "chassis_info" - } - ], - "policies": [ - { - "name": "any fan absence", - "conditions": [ - { - "type": "fan.any.absence" - } - ], - "actions": [ - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] - }, - { - "name": "any psu absence", - "conditions": [ - { - "type": "psu.any.absence" - } - ], - "actions": [ - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] - }, - { - "name": "any fan broken", - "conditions": [ - { - "type": "fan.any.fault" - } - ], - "actions": [ - { - "type": "fan.all.set_speed", - "speed": "100" - } - ] - }, - { - "name": "all fan and psu presence", - "conditions": [ - { - "type": "fan.all.presence" - }, - { - "type": "psu.all.presence" - }, - { - "type": "fan.all.good" - } - ], - "actions": [ - { - "type": "thermal.recover", - "status": "true" - } - ] - } - ] -} \ No newline at end of file