Skip to content

Commit f1409e0

Browse files
[psud] Enhancement for PSU led management (sonic-net#55)
1 parent 238fc06 commit f1409e0

File tree

1 file changed

+196
-0
lines changed
  • sonic-psud/scripts

1 file changed

+196
-0
lines changed

sonic-psud/scripts/psud

+196
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def _wrapper_get_psus_status(psu_index):
7373
pass
7474
return platform_psuutil.get_psu_status(psu_index)
7575

76+
7677
#
7778
# Helper functions =============================================================
7879
#
@@ -85,6 +86,108 @@ def psu_db_update(psu_tbl, psu_num):
8586
'true' if _wrapper_get_psus_status(psu_index) else 'false')])
8687
psu_tbl.set(PSU_INFO_KEY_TEMPLATE.format(psu_index), fvs)
8788

89+
90+
# try get information from platform API and return a default value if caught NotImplementedError
91+
def try_get(callback, default=None):
92+
"""
93+
Handy function to invoke the callback and catch NotImplementedError
94+
:param callback: Callback to be invoked
95+
:param default: Default return value if exception occur
96+
:return: Default return value if exception occur else return value of the callback
97+
"""
98+
try:
99+
ret = callback()
100+
if ret is None:
101+
ret = default
102+
except NotImplementedError:
103+
ret = default
104+
105+
return ret
106+
107+
def log_on_status_changed(normal_status, normal_log, abnormal_log):
108+
"""
109+
Log when any status changed
110+
:param normal_status: Expected status.
111+
:param normal_log: Log string for expected status.
112+
:param abnormal_log: Log string for unexpected status
113+
:return:
114+
"""
115+
if normal_status:
116+
logger.log_notice(normal_log)
117+
else:
118+
logger.log_warning(abnormal_log)
119+
120+
#
121+
# PSU status ===================================================================
122+
#
123+
124+
class PsuStatus(object):
125+
update_led_color = True
126+
127+
def __init__(self, psu):
128+
self.psu = psu
129+
self.presence = True
130+
self.power_good = True
131+
self.voltage_good = True
132+
self.temperature_good = True
133+
134+
def set_presence(self, presence):
135+
"""
136+
Set and cache PSU presence status
137+
:param presence: PSU presence status
138+
:return: True if status changed else False
139+
"""
140+
if presence == self.presence:
141+
return False
142+
143+
self.presence = presence
144+
return True
145+
146+
def set_power_good(self, power_good):
147+
"""
148+
Set and cache PSU power good status
149+
:param power_good: PSU power good status
150+
:return: True if status changed else False
151+
"""
152+
if power_good == self.power_good:
153+
return False
154+
155+
self.power_good = power_good
156+
return True
157+
158+
def set_voltage(self, voltage, high_threshold, low_threshold):
159+
if not voltage or not high_threshold or not low_threshold:
160+
if self.voltage_good is not True:
161+
logger.log_warning('PSU voltage or high_threshold or low_threshold become unavailable, '
162+
'voltage={}, high_threshold={}, low_threshold={}'.format(voltage, high_threshold, low_threshold))
163+
self.voltage_good = True
164+
return False
165+
166+
voltage_good = (low_threshold <= voltage <= high_threshold)
167+
if voltage_good == self.voltage_good:
168+
return False
169+
170+
self.voltage_good = voltage_good
171+
return True
172+
173+
def set_temperature(self, temperature, high_threshold):
174+
if not temperature or not high_threshold:
175+
if self.temperature_good is not True:
176+
logger.log_warning('PSU temperature or high_threshold become unavailable, '
177+
'temperature={}, high_threshold={}'.format(temperature, high_threshold))
178+
self.temperature_good = True
179+
return False
180+
181+
temperature_good = (temperature < high_threshold)
182+
if temperature_good == self.temperature_good:
183+
return False
184+
185+
self.temperature_good = temperature_good
186+
return True
187+
188+
def is_ok(self):
189+
return self.presence and self.power_good and self.voltage_good and self.temperature_good
190+
88191
#
89192
# Daemon =======================================================================
90193
#
@@ -94,6 +197,7 @@ class DaemonPsud(DaemonBase):
94197
DaemonBase.__init__(self)
95198

96199
self.stop = threading.Event()
200+
self.psu_status_dict = {}
97201

98202
# Signal handler
99203
def signal_handler(self, sig, frame):
@@ -145,6 +249,8 @@ class DaemonPsud(DaemonBase):
145249

146250
while not self.stop.wait(PSU_INFO_UPDATE_PERIOD_SECS):
147251
psu_db_update(psu_tbl, psu_num)
252+
self.update_psu_data()
253+
self._update_led_color(psu_tbl)
148254

149255
logger.log_info("Stop daemon main loop")
150256

@@ -156,6 +262,96 @@ class DaemonPsud(DaemonBase):
156262

157263
logger.log_info("Shutting down...")
158264

265+
def update_psu_data(self):
266+
if not platform_chassis:
267+
return
268+
269+
for index, psu in enumerate(platform_chassis.get_all_psus()):
270+
try:
271+
self._update_single_psu_data(index + 1, psu)
272+
except Exception as e:
273+
logger.log_warning("Failed to update PSU data - {}".format(e))
274+
275+
def _update_single_psu_data(self, index, psu):
276+
name = try_get(psu.get_name)
277+
if not name:
278+
name = PSU_INFO_KEY_TEMPLATE.format(index)
279+
presence = _wrapper_get_psus_presence(index)
280+
power_good = False
281+
voltage = None
282+
voltage_high_threshold = None
283+
voltage_low_threshold = None
284+
temperature = None
285+
temperature_threshold = None
286+
if presence:
287+
power_good = _wrapper_get_psus_status(index)
288+
voltage = try_get(psu.get_voltage)
289+
voltage_high_threshold = try_get(psu.get_voltage_high_threshold)
290+
voltage_low_threshold = try_get(psu.get_voltage_low_threshold)
291+
temperature = try_get(psu.get_temperature)
292+
temperature_threshold = try_get(psu.get_temperature_high_threshold)
293+
294+
if index not in self.psu_status_dict:
295+
self.psu_status_dict[index] = PsuStatus(psu)
296+
297+
psu_status = self.psu_status_dict[index]
298+
set_led = False
299+
if psu_status.set_presence(presence):
300+
set_led = True
301+
log_on_status_changed(psu_status.presence,
302+
'PSU absence warning cleared: {} is inserted back.'.format(name),
303+
'PSU absence warning: {} is not present.'.format(name)
304+
)
305+
306+
if presence and psu_status.set_power_good(power_good):
307+
set_led = True
308+
log_on_status_changed(psu_status.power_good,
309+
'Power absence warning cleared: {} power is back to normal.'.format(name),
310+
'Power absence warning: {} is out of power.'.format(name)
311+
)
312+
313+
if presence and psu_status.set_voltage(voltage, voltage_high_threshold, voltage_low_threshold):
314+
set_led = True
315+
log_on_status_changed(psu_status.voltage_good,
316+
'PSU voltage warning cleared: {} voltage is back to normal.'.format(name),
317+
'PSU voltage warning: {} voltage out of range, current voltage={}, valid range=[{}, {}].'.format(name, voltage, voltage_high_threshold, voltage_low_threshold)
318+
)
319+
320+
if presence and psu_status.set_temperature(temperature, temperature_threshold):
321+
set_led = True
322+
log_on_status_changed(psu_status.temperature_good,
323+
'PSU temperature warning cleared: {} temperature is back to normal.'.format(name),
324+
'PSU temperature warning: {} temperature too hot, temperature={}, threshold={}.'.format(name, temperature, temperature_threshold)
325+
)
326+
327+
if set_led:
328+
PsuStatus.update_led_color = True
329+
self._set_psu_led(psu, psu_status)
330+
331+
def _set_psu_led(self, psu, psu_status):
332+
try:
333+
color = psu.STATUS_LED_COLOR_GREEN if psu_status.is_ok() else psu.STATUS_LED_COLOR_RED
334+
psu.set_status_led(color)
335+
except NotImplementedError as e:
336+
pass
337+
338+
def _update_led_color(self, psu_tbl):
339+
if not platform_chassis:
340+
return
341+
342+
if PsuStatus.update_led_color:
343+
for index, psu_status in self.psu_status_dict.items():
344+
try:
345+
fvs = swsscommon.FieldValuePairs([
346+
('led_status', str(try_get(psu_status.psu.get_status_led)))
347+
])
348+
except Exception as e:
349+
logger.log_warning('Failed to get led status for psu {}'.format(index))
350+
fvs = swsscommon.FieldValuePairs([
351+
('led_status', NOT_AVAILABLE)
352+
])
353+
psu_tbl.set(PSU_INFO_KEY_TEMPLATE.format(index), fvs)
354+
PsuStatus.update_led_color = False
159355
#
160356
# Main =========================================================================
161357
#

0 commit comments

Comments
 (0)