@@ -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