Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#
# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
# Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# Copyright (c) 2023-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -19,6 +19,7 @@
from . import utils
from sonic_py_common import logger

import re
import sys
import time

Expand Down Expand Up @@ -55,26 +56,78 @@ def __init__(self, sfp_list, update_asic=True):
self._timer = utils.Timer()
self._update_asic = update_asic

def wait_for_sysfs_nodes(self):
"""
Wait for temperature sysfs nodes to be present before proceeding.
Returns:
bool: True if wait success else timeout
"""
start_time = time.time()
logger.log_notice('Waiting for temperature sysfs nodes to be present...')
conditions = []

# ASIC temperature sysfs node
asic_count = DeviceDataManager.get_asic_count()
for asic_index in range(asic_count):
conditions.append(lambda idx=asic_index: os.path.exists(f'/sys/module/sx_core/asic{idx}/temperature/input'))

# Module temperature sysfs nodes
sfp_count = len(self._sfp_list) if self._sfp_list else 0
result = DeviceDataManager.wait_sysfs_ready(sfp_count)
end_time = time.time()
elapsed_time = end_time - start_time

if result:
logger.log_notice(f'Temperature sysfs nodes are ready. Wait time: {elapsed_time:.4f} seconds')
else:
logger.log_error(f'Timeout waiting for temperature sysfs nodes. Wait time: {elapsed_time:.4f} seconds')

return result

def _find_matching_key(self, dev_parameters, pattern):
"""
Find the first key in dev_parameters that matches the given regex pattern.
Returns the matching key and its value, or (None, None) if no match found.
"""
for key in dev_parameters.keys():
if re.match(pattern, key):
return key, dev_parameters[key]
return None, None

def load_tc_config(self):
asic_poll_interval = 1
sfp_poll_interval = 10
data = utils.load_json_file(TC_CONFIG_FILE, log_func=None)
if not data:
logger.log_notice(f'{TC_CONFIG_FILE} does not exist, use default polling interval')
logger.log_error(f'{TC_CONFIG_FILE} does not exist, use default polling interval')

if data:
dev_parameters = data.get('dev_parameters')
if dev_parameters is not None:
asic_parameter = dev_parameters.get('asic')
if not dev_parameters:
logger.log_error('dev_parameters not configured or empty, using default intervals')
else:
# Find ASIC parameter using regex pattern
asic_key, asic_parameter = self._find_matching_key(dev_parameters, r'asic\\d*')
if asic_parameter is not None:
asic_poll_interval_config = asic_parameter.get('poll_time')
if asic_poll_interval_config:
asic_poll_interval = int(asic_poll_interval_config) / 2
module_parameter = dev_parameters.get('module\\d+')
asic_poll_interval = int(asic_poll_interval_config)
logger.log_notice(f'ASIC parameter found with key "{asic_key}", poll_time: {asic_poll_interval_config}, interval: {asic_poll_interval}')
else:
logger.log_error(f'ASIC poll_time not configured in "{asic_key}", using default interval: {asic_poll_interval}')
else:
logger.log_error(f'ASIC parameter not found (pattern: asic\\d*), using default interval: {asic_poll_interval}')
# Find Module parameter using regex pattern
module_key, module_parameter = self._find_matching_key(dev_parameters, r'module\\d+')
if module_parameter is not None:
sfp_poll_interval_config = module_parameter.get('poll_time')
if sfp_poll_interval_config:
sfp_poll_interval = int(sfp_poll_interval_config) / 2
sfp_poll_interval = int(sfp_poll_interval_config)
logger.log_notice(f'Module parameter found with key "{module_key}", poll_time: {sfp_poll_interval_config}, interval: {sfp_poll_interval}')
else:
logger.log_error(f'Module poll_time not configured in "{module_key}", using default interval: {sfp_poll_interval}')
else:
logger.log_error(f'Module parameter not found (pattern: module\\d+), using default interval: {sfp_poll_interval}')

if self._update_asic:
logger.log_notice(f'ASIC polling interval: {asic_poll_interval}')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#
# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
# Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# Copyright (c) 2023-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -28,7 +28,7 @@
mock_tc_config = """
{
"dev_parameters": {
"asic": {
"asic\\\\d*": {
"pwm_min": 20,
"pwm_max": 100,
"val_min": "!70000",
Expand All @@ -48,22 +48,58 @@


class TestThermalUpdater:
def test_load_tc_config_non_exists(self):
@mock.patch('sonic_platform.thermal_updater.logger')
def test_load_tc_config_non_exists(self, mock_logger):
updater = ThermalUpdater(None)
updater.load_tc_config()
assert updater._timer._timestamp_queue.qsize() == 2

def test_load_tc_config_mocked(self):
@mock.patch('sonic_platform.thermal_updater.logger')
def test_load_tc_config_mocked(self, mock_logger):
updater = ThermalUpdater(None)
mock_os_open = mock.mock_open(read_data=mock_tc_config)
with mock.patch('sonic_platform.utils.open', mock_os_open):
updater.load_tc_config()
assert updater._timer._timestamp_queue.qsize() == 2
# Verify that debug logs were called with the correct parameters
assert mock_logger.log_notice.call_count >= 2 # At least ASIC and Module parameter logs

def test_find_matching_key(self):
"""Test _find_matching_key method for regex pattern matching"""
updater = ThermalUpdater(None)

# Test with asic pattern - should match 'asic\d*' keys
dev_parameters = {
'asic\\d*': {'poll_time': 3},
'module\\d+': {'poll_time': 20},
'sensor_amb': {'poll_time': 30}
}

# Test matching asic pattern
key, value = updater._find_matching_key(dev_parameters, r'asic\\d*')
assert key == 'asic\\d*'
assert value == {'poll_time': 3}

# Test matching module pattern
key, value = updater._find_matching_key(dev_parameters, r'module\\d+')
assert key == 'module\\d+'
assert value == {'poll_time': 20}

# Test non-matching pattern
key, value = updater._find_matching_key(dev_parameters, r'nonexistent')
assert key is None
assert value is None

# Test with empty dict
key, value = updater._find_matching_key({}, r'asic\\d*')
assert key is None
assert value is None

@mock.patch('sonic_platform.thermal_updater.logger')
@mock.patch('sonic_platform.thermal_updater.ThermalUpdater.update_asic', mock.MagicMock())
@mock.patch('sonic_platform.thermal_updater.ThermalUpdater.update_module', mock.MagicMock())
@mock.patch('sonic_platform.utils.write_file')
def test_start_stop(self, mock_write):
def test_start_stop(self, mock_write, mock_logger):
mock_sfp = mock.MagicMock()
mock_sfp.sdk_index = 1
updater = ThermalUpdater([mock_sfp])
Expand Down
Loading