Skip to content

Commit b290945

Browse files
patrickmacarthurvvolam
authored andcommitted
thermalctld: Add support for fans on non-CPU modules (sonic-net#555)
* thermalctld: Add support for fans on non-CPU modules * Add module fan to unit tests
1 parent db19064 commit b290945

3 files changed

Lines changed: 50 additions & 11 deletions

File tree

sonic-thermalctld/scripts/thermalctld

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
Thermal control daemon for SONiC
66
"""
77

8+
from enum import Enum, auto
89
import signal
910
import sys
1011
import threading
@@ -61,18 +62,23 @@ def update_entity_info(table, parent_name, key, device, device_index):
6162
table.set(key, fvs)
6263

6364

65+
class FanType(Enum):
66+
DRAWER = auto()
67+
PSU = auto()
68+
MODULE = auto()
69+
6470
class FanStatus(logger.Logger):
6571
absent_fan_count = 0
6672
faulty_fan_count = 0
6773

68-
def __init__(self, fan=None, is_psu_fan=False):
74+
def __init__(self, fan=None, fan_type=FanType.DRAWER):
6975
"""
7076
Initializer of FanStatus
7177
"""
7278
super(FanStatus, self).__init__(SYSLOG_IDENTIFIER)
7379

7480
self.fan = fan
75-
self.is_psu_fan = is_psu_fan
81+
self.fan_type = fan_type
7682
self.presence = True
7783
self.status = True
7884
self.under_speed = False
@@ -95,7 +101,7 @@ class FanStatus(logger.Logger):
95101
:param presence: Fan presence status
96102
:return: True if status changed else False
97103
"""
98-
if not presence and not self.is_psu_fan:
104+
if not presence and self.fan_type == FanType.DRAWER:
99105
FanStatus.absent_fan_count += 1
100106

101107
if presence == self.presence:
@@ -228,16 +234,25 @@ class FanUpdater(logger.Logger):
228234
if self.task_stopping_event.is_set():
229235
return
230236
try:
231-
self._refresh_fan_status(drawer, drawer_index, fan, fan_index)
237+
self._refresh_fan_status(drawer, drawer_index, fan, fan_index, FanType.DRAWER)
232238
except Exception as e:
233239
self.log_warning('Failed to update fan status - {}'.format(repr(e)))
234240

241+
for module_index, module in enumerate(self.chassis.get_all_modules()):
242+
for fan_index, fan in enumerate(module.get_all_fans()):
243+
if self.task_stopping_event.is_set():
244+
return
245+
try:
246+
self._refresh_fan_status(module, module_index, fan, fan_index, FanType.MODULE)
247+
except Exception as e:
248+
self.log_warning('Failed to update module fan status - {}'.format(repr(e)))
249+
235250
for psu_index, psu in enumerate(self.chassis.get_all_psus()):
236251
for fan_index, fan in enumerate(psu.get_all_fans()):
237252
if self.task_stopping_event.is_set():
238253
return
239254
try:
240-
self._refresh_fan_status(psu, psu_index, fan, fan_index, True)
255+
self._refresh_fan_status(psu, psu_index, fan, fan_index, FanType.PSU)
241256
except Exception as e:
242257
self.log_warning('Failed to update PSU fan status - {}'.format(repr(e)))
243258

@@ -270,7 +285,7 @@ class FanUpdater(logger.Logger):
270285

271286
self.drawer_table.set(drawer_name, fvs)
272287

273-
def _refresh_fan_status(self, parent, parent_index, fan, fan_index, is_psu_fan=False):
288+
def _refresh_fan_status(self, parent, parent_index, fan, fan_index, fan_type=FanType.DRAWER):
274289
"""
275290
Get Fan status by platform API and write to database for a given Fan
276291
:param parent: Parent device of this fan
@@ -280,15 +295,17 @@ class FanUpdater(logger.Logger):
280295
:param name_prefix: name prefix of Fan object if Fan.get_name not presented
281296
:return:
282297
"""
283-
drawer_name = NOT_AVAILABLE if is_psu_fan else str(try_get(parent.get_name))
284-
if is_psu_fan:
298+
drawer_name = NOT_AVAILABLE if fan_type != FanType.DRAWER else str(try_get(parent.get_name))
299+
if fan_type == FanType.PSU:
285300
parent_name = 'PSU {}'.format(parent_index + 1)
301+
elif fan_type == FanType.MODULE:
302+
parent_name = 'Module {}'.format(parent_index + 1)
286303
else:
287304
parent_name = drawer_name if drawer_name != NOT_AVAILABLE else CHASSIS_INFO_KEY
288305
fan_name = try_get(fan.get_name, '{} fan {}'.format(parent_name, fan_index + 1))
289306
update_entity_info(self.phy_entity_table, parent_name, fan_name, fan, fan_index + 1)
290307
if fan_name not in self.fan_status_dict:
291-
self.fan_status_dict[fan_name] = FanStatus(fan, is_psu_fan)
308+
self.fan_status_dict[fan_name] = FanStatus(fan, fan_type)
292309

293310
fan_status = self.fan_status_dict[fan_name]
294311

@@ -342,7 +359,7 @@ class FanUpdater(logger.Logger):
342359

343360
# We don't set PSU led here, PSU led will be handled in psud
344361
if set_led:
345-
if not is_psu_fan:
362+
if fan_type == FanType.DRAWER:
346363
self._set_fan_led(parent, fan, fan_name, fan_status)
347364

348365
if fan_fault_status != NOT_AVAILABLE:

sonic-thermalctld/tests/mock_platform.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,10 @@ def make_module_thermal(self):
401401
sfp._thermal_list.append(MockThermal())
402402
psu = MockPsu()
403403
psu._thermal_list.append(MockThermal())
404+
fan = MockFan()
404405
module._sfp_list.append(sfp)
405406
module._psu_list.append(psu)
407+
module._fan_list.append(fan)
406408
module._thermal_list.append(MockThermal())
407409

408410
def is_modular_chassis(self):

sonic-thermalctld/tests/test_thermalctld.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
from sonic_py_common import daemon_base
2626

27-
from .mock_platform import MockChassis, MockFan, MockPsu, MockSfp, MockThermal
27+
from .mock_platform import MockChassis, MockFan, MockModule, MockPsu, MockSfp, MockThermal
2828
from .mock_swsscommon import Table
2929

3030
daemon_base.db_connect = mock.MagicMock()
@@ -267,6 +267,26 @@ def test_update_psu_fans(self):
267267
else:
268268
fan_updater.log_warning.assert_called_with("Failed to update PSU fan status - Exception('Test message',)")
269269

270+
def test_update_module_fans(self):
271+
chassis = MockChassis()
272+
module = MockModule()
273+
mock_fan = MockFan()
274+
chassis.set_modular_chassis(True)
275+
module._fan_list.append(mock_fan)
276+
chassis._module_list.append(module)
277+
fan_updater = thermalctld.FanUpdater(chassis, multiprocessing.Event())
278+
fan_updater.update()
279+
assert fan_updater.log_warning.call_count == 0
280+
281+
fan_updater._refresh_fan_status = mock.MagicMock(side_effect=Exception("Test message"))
282+
fan_updater.update()
283+
assert fan_updater.log_warning.call_count == 1
284+
285+
# TODO: Clean this up once we no longer need to support Python 2
286+
if sys.version_info.major == 3:
287+
fan_updater.log_warning.assert_called_with("Failed to update module fan status - Exception('Test message')")
288+
else:
289+
fan_updater.log_warning.assert_called_with("Failed to update module fan status - Exception('Test message',)")
270290

271291
class TestThermalMonitor(object):
272292
"""

0 commit comments

Comments
 (0)