From d3f2da867952a429d29d115ca259249d0df8e6c1 Mon Sep 17 00:00:00 2001 From: FuzailBrcm <51665572+FuzailBrcm@users.noreply.github.com> Date: Fri, 18 Mar 2022 23:44:10 +0530 Subject: [PATCH] [pddf]: Adding support for fan_drawer class in PDDF common platform APIs (#10213) Why I did it fan_drawer support was missing in PDDF common platform APIs. This resulted in 'thermalctld' not working and 'show platform fan' and 'show platfomr temperature' commands not working. _thermal_list array inside PSU class was not initialized. Made changes to attach the PSU related thermal sensors in the PSU instance. How I did it Added a common class pddf_fan_drawer.py. This class uses the PDDF JSON to fetch the platform specific data. A platform which uses PDDF would follow the below hierarchy. fan_drawer_base.py ---> pddf_fan_drawer.py ---> fan_drawer.py How to verify it Run the 'show platform fan' and 'show platform temperature' commands and check the o/p. o/p on AS7326: root@sonic:/home/admin# show platform fan s Drawer LED FAN Speed Direction Presence Status Timestamp -------- ----- ---------- ------- ----------- ---------- -------- ----------------- Fantray1 green Fantray1_1 38% EXHAUST Present OK 20220311 04:15:03 Fantray1 green Fantray1_2 38% EXHAUST Present OK 20220311 04:15:03 Fantray2 green Fantray2_1 38% EXHAUST Present OK 20220311 04:15:03 Fantray2 green Fantray2_2 38% EXHAUST Present OK 20220311 04:15:03 Fantray3 green Fantray3_1 38% EXHAUST Present OK 20220311 04:15:03 Fantray3 green Fantray3_2 38% EXHAUST Present OK 20220311 04:15:03 Fantray4 green Fantray4_1 38% EXHAUST Present OK 20220311 04:15:03 Fantray4 green Fantray4_2 38% EXHAUST Present OK 20220311 04:15:03 Fantray5 green Fantray5_1 38% EXHAUST Present OK 20220311 04:15:03 Fantray5 green Fantray5_2 38% EXHAUST Present OK 20220311 04:15:03 Fantray6 green Fantray6_1 38% EXHAUST Present OK 20220311 04:15:03 Fantray6 green Fantray6_2 38% EXHAUST Present OK 20220311 04:15:03 N/A off PSU1_FAN1 0% Present Not OK 20220311 04:15:05 N/A green PSU2_FAN1 34% EXHAUST Present OK 20220311 04:15:05 hroot@sonic:/home/admin# show platform temperature Sensor Temperature High TH Low TH Crit High TH Crit Low TH Warning Timestamp ---------- ------------- --------- -------- -------------- ------------- --------- ----------------- PSU1_TEMP1 0 N/A N/A N/A N/A False 20220311 04:15:05 PSU2_TEMP1 37 N/A N/A N/A N/A False 20220311 04:15:05 TEMP1 37 80.0 N/A N/A N/A False 20220311 04:15:05 TEMP2 27 80.0 N/A N/A N/A False 20220311 04:15:05 TEMP3 28.5 80.0 N/A N/A N/A False 20220311 04:15:05 TEMP4 30.5 80.0 N/A N/A N/A False 20220311 04:15:05 root@sonic:/home/admin# root@sonic:/home/admin# root@sonic:/home/admin# o/p on AS7726: root@as7726-32x-2:~# show platform fan Drawer LED FAN Speed Direction Presence Status Timestamp -------- ----- ---------- ------- ----------- ---------- -------- ----------------- Fantray1 green Fantray1_1 38% EXHAUST Present OK 20220311 08:13:04 Fantray1 green Fantray1_2 38% EXHAUST Present OK 20220311 08:13:04 Fantray2 green Fantray2_1 38% EXHAUST Present OK 20220311 08:13:04 Fantray2 green Fantray2_2 38% EXHAUST Present OK 20220311 08:13:04 Fantray3 green Fantray3_1 38% EXHAUST Present OK 20220311 08:13:04 Fantray3 green Fantray3_2 38% EXHAUST Present OK 20220311 08:13:04 Fantray4 green Fantray4_1 38% EXHAUST Present OK 20220311 08:13:04 Fantray4 green Fantray4_2 38% EXHAUST Present OK 20220311 08:13:04 Fantray5 green Fantray5_1 38% EXHAUST Present OK 20220311 08:13:04 Fantray5 green Fantray5_2 38% EXHAUST Present OK 20220311 08:13:04 Fantray6 green Fantray6_1 38% EXHAUST Present OK 20220311 08:13:04 Fantray6 green Fantray6_2 38% EXHAUST Present OK 20220311 08:13:04 N/A green PSU1_FAN1 23% EXHAUST Present OK 20220311 08:13:04 N/A green PSU2_FAN1 22% EXHAUST Present OK 20220311 08:13:04 root@as7726-32x-2:~# show platform temp Sensor Temperature High TH Low TH Crit High TH Crit Low TH Warning Timestamp ---------- ------------- --------- -------- -------------- ------------- --------- ----------------- PSU1_TEMP1 28 N/A N/A N/A N/A False 20220311 08:13:04 PSU2_TEMP1 25 N/A N/A N/A N/A False 20220311 08:13:04 TEMP1 23.5 80.0 N/A N/A N/A False 20220311 08:13:04 TEMP2 27 80.0 N/A N/A N/A False 20220311 08:13:04 TEMP3 24 80.0 N/A N/A N/A False 20220311 08:13:04 TEMP4 27 80.0 N/A N/A N/A False 20220311 08:13:04 TEMP5 24 80.0 N/A N/A N/A False 20220311 08:13:04 --- .../sonic_platform_pddf_base/pddf_chassis.py | 8 +- .../sonic_platform_pddf_base/pddf_fan.py | 2 +- .../pddf_fan_drawer.py | 110 ++++++++++ .../sonic_platform_pddf_base/pddf_psu.py | 6 + .../sonic_platform_pddf_base/pddf_thermal.py | 198 +++++++++++------- 5 files changed, 248 insertions(+), 76 deletions(-) create mode 100755 platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan_drawer.py diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_chassis.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_chassis.py index 0ba2e8902c..d90949184d 100644 --- a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_chassis.py +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_chassis.py @@ -10,7 +10,7 @@ try: from sonic_platform_base.chassis_base import ChassisBase from sonic_platform.sfp import Sfp from sonic_platform.psu import Psu - from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer from sonic_platform.thermal import Thermal from sonic_platform.eeprom import Eeprom except ImportError as e: @@ -52,9 +52,9 @@ class PddfChassis(ChassisBase): # FANs for i in range(self.platform_inventory['num_fantrays']): - for j in range(self.platform_inventory['num_fans_pertray']): - fan = Fan(i, j, self.pddf_obj, self.plugin_data) - self._fan_list.append(fan) + fandrawer = FanDrawer(i, self.pddf_obj, self.plugin_data) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) # PSUs for i in range(self.platform_inventory['num_psus']): diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan.py index d272d40e61..2a8ef46085 100644 --- a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan.py +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan.py @@ -153,7 +153,7 @@ class PddfFan(FanBase): speed = int(output['status']) max_speed = int(self.plugin_data['PSU']['PSU_FAN_MAX_SPEED']) - speed_percentage = (speed*100)/max_speed + speed_percentage = round((speed*100)/max_speed) return speed_percentage else: # TODO This calculation should change based on MAX FAN SPEED diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan_drawer.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan_drawer.py new file mode 100755 index 0000000000..f88e833408 --- /dev/null +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_fan_drawer.py @@ -0,0 +1,110 @@ +############################################################################# +# PDDF +# +# PDDF fan_drawer base class inherited from the common base class fan_drawer.py +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class PddfFanDrawer(FanDrawerBase): + """PDDF generic Fan Drawer class""" + + pddf_obj = {} + plugin_data = {} + + def __init__(self, tray_idx, pddf_data=None, pddf_plugin_data=None): + FanDrawerBase.__init__(self) + if not pddf_data or not pddf_plugin_data: + raise ValueError('PDDF JSON data error') + + self.pddf_obj = pddf_data + self.plugin_data = pddf_plugin_data + self.platform = self.pddf_obj.get_platform() + + if tray_idx < 0 or tray_idx >= self.platform['num_fantrays']: + print("Invalid fantray index %d\n" % tray_idx) + return + + self.fantray_index = tray_idx+1 + for j in range(self.platform['num_fans_pertray']): + # Fan index is 0-based for the init call + self._fan_list.append(Fan(tray_idx, j, self.pddf_obj, self.plugin_data)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: String containing fan-drawer name + """ + return "Fantray{0}".format(self.fantray_index) + + def get_presence(self): + status = False + # Usually if a tray is removed, all the fans inside it are absent + if self._fan_list: + status = self._fan_list[0].get_presence() + + return status + + def get_status(self): + status = False + # if all the fans are working fine, then tray status should be okay + if self._fan_list: + status = all(fan.get_status() == True for fan in self._fan_list) + + return status + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + # Usually Fantrays are replaceable + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return self.fantray_index + + def get_status_led(self): + led_device_name = "FANTRAY{}".format(self.fantray_index) + "_LED" + + if led_device_name not in self.pddf_obj.data.keys(): + # Implement a generic status_led color scheme + if self.get_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + + device_name = self.pddf_obj.data[led_device_name]['dev_info']['device_name'] + self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('index', str(self.fantray_index-1), self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('dev_ops', 'get_status', self.pddf_obj.get_led_path()) + color = self.pddf_obj.get_led_color() + return (color) + + def set_status_led(self, color): + result = False + led_device_name = "FANTRAY{}".format(self.fantray_index) + "_LED" + result, msg = self.pddf_obj.is_supported_sysled_state(led_device_name, color) + if result == False: + print(msg) + return (False) + + device_name = self.pddf_obj.data[led_device_name]['dev_info']['device_name'] + self.pddf_obj.create_attr('device_name', device_name, self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('index', str(self.fantray_index-1), self.pddf_obj.get_led_path()) + self.pddf_obj.create_attr('color', color, self.pddf_obj.get_led_cur_state_path()) + self.pddf_obj.create_attr('dev_ops', 'set_status', self.pddf_obj.get_led_path()) + return (True) diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_psu.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_psu.py index 912333df8b..bbe7dc0a1a 100644 --- a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_psu.py +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_psu.py @@ -20,6 +20,7 @@ try: from sonic_platform_base.psu_base import PsuBase from sonic_platform.fan import Fan + from sonic_platform.thermal import Thermal except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -45,6 +46,11 @@ class PddfPsu(PsuBase): psu_fan = Fan(0, psu_fan_idx, pddf_data, pddf_plugin_data, True, self.psu_index) self._fan_list.append(psu_fan) + self.num_psu_thermals = 1 # Fixing it 1 for now + for psu_thermal_idx in range(self.num_psu_thermals): + psu_thermal = Thermal(psu_thermal_idx, pddf_data, pddf_plugin_data, True, self.psu_index) + self._thermal_list.append(psu_thermal) + def get_num_fans(self): """ Retrieves the number of fan modules available on this PSU diff --git a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_thermal.py b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_thermal.py index 644292eb17..a0fe6a28bf 100644 --- a/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_thermal.py +++ b/platform/pddf/platform-api-pddf-base/sonic_platform_pddf_base/pddf_thermal.py @@ -22,7 +22,7 @@ class PddfThermal(ThermalBase): pddf_obj = {} plugin_data = {} - def __init__(self, index, pddf_data=None, pddf_plugin_data=None): + def __init__(self, index, pddf_data=None, pddf_plugin_data=None, is_psu_thermal=False, psu_index=0): if not pddf_data or not pddf_plugin_data: raise ValueError('PDDF JSON data error') @@ -35,78 +35,129 @@ class PddfThermal(ThermalBase): self.thermal_obj_name = "TEMP{}".format(self.thermal_index) self.thermal_obj = self.pddf_obj.data[self.thermal_obj_name] + self.is_psu_thermal = is_psu_thermal + if self.is_psu_thermal: + self.thermals_psu_index = psu_index + def get_name(self): - if 'dev_attr' in self.thermal_obj.keys(): - if 'display_name' in self.thermal_obj['dev_attr']: - return str(self.thermal_obj['dev_attr']['display_name']) - # In case of errors - return (self.thermal_obj_name) + if self.is_psu_thermal: + return "PSU{}_TEMP{}".format(self.thermals_psu_index, self.thermal_index) + else: + if 'dev_attr' in self.thermal_obj.keys(): + if 'display_name' in self.thermal_obj['dev_attr']: + return str(self.thermal_obj['dev_attr']['display_name']) + # In case of errors + return (self.thermal_obj_name) + + def get_presence(self): + if self.is_psu_thermal: + # Temp sensor on the PSU + device = "PSU{}".format(self.thermals_psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_present") + if not output: + return False + + mode = output['mode'] + status = output['status'] + + vmap = self.plugin_data['PSU']['psu_present'][mode]['valmap'] + + if status.rstrip('\n') in vmap: + return vmap[status.rstrip('\n')] + else: + return False + else: + # Temp sensor on the board + return True def get_temperature(self): - output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_input") - if not output: - return None + if self.is_psu_thermal: + device = "PSU{}".format(self.thermals_psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_temp1_input") + if not output: + return None - if output['status'].isalpha(): - attr_value = None + temp1 = output['status'] + # temperature returned is in milli celcius + return float(temp1)/1000 else: - attr_value = float(output['status']) + output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_input") + if not output: + return None - if output['mode'] == 'bmc': - return attr_value - else: - return (attr_value/float(1000)) + if output['status'].isalpha(): + attr_value = None + else: + attr_value = float(output['status']) + + if output['mode'] == 'bmc': + return attr_value + else: + return (attr_value/float(1000)) def get_high_threshold(self): - output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_threshold") - if not output: - return None + if not self.is_psu_thermal: + output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_threshold") + if not output: + return None - if output['status'].isalpha(): - attr_value = None - else: - attr_value = float(output['status']) + if output['status'].isalpha(): + attr_value = None + else: + attr_value = float(output['status']) - if output['mode'] == 'bmc': - return attr_value + if output['mode'] == 'bmc': + return attr_value + else: + return (attr_value/float(1000)) else: - return (attr_value/float(1000)) + raise NotImplementedError + def get_low_threshold(self): - output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_threshold") - if not output: - return None + if not self.is_psu_thermal: + output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_threshold") + if not output: + return None - if output['status'].isalpha(): - attr_value = None - else: - attr_value = float(output['status']) + if output['status'].isalpha(): + attr_value = None + else: + attr_value = float(output['status']) - if output['mode'] == 'bmc': - return attr_value + if output['mode'] == 'bmc': + return attr_value + else: + return (attr_value/float(1000)) else: - return (attr_value/float(1000)) + raise NotImplementedError def set_high_threshold(self, temperature): - node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_high_threshold") - if node is None: - print("ERROR %s does not exist" % node) - return None + if not self.is_psu_thermal: + node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_high_threshold") + if node is None: + print("ERROR %s does not exist" % node) + return None - cmd = "echo '%d' > %s" % (temperature * 1000, node) - os.system(cmd) + cmd = "echo '%d' > %s" % (temperature * 1000, node) + os.system(cmd) - return (True) + return (True) + else: + raise NotImplementedError def set_low_threshold(self, temperature): - node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_low_threshold") - if node is None: - print("ERROR %s does not exist" % node) - return None - cmd = "echo '%d' > %s" % (temperature * 1000, node) - os.system(cmd) + if not self.is_psu_thermal: + node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_low_threshold") + if node is None: + print("ERROR %s does not exist" % node) + return None + cmd = "echo '%d' > %s" % (temperature * 1000, node) + os.system(cmd) - return (True) + return (True) + else: + raise NotImplementedError def get_high_critical_threshold(self): """ @@ -116,19 +167,22 @@ class PddfThermal(ThermalBase): A float number, the high critical threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_crit_threshold") - if not output: - return None + if not self.is_psu_thermal: + output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_crit_threshold") + if not output: + return None - if output['status'].isalpha(): - attr_value = None - else: - attr_value = float(output['status']) + if output['status'].isalpha(): + attr_value = None + else: + attr_value = float(output['status']) - if output['mode'] == 'bmc': - return attr_value + if output['mode'] == 'bmc': + return attr_value + else: + return (attr_value/float(1000)) else: - return (attr_value/float(1000)) + raise NotImplementedError def get_low_critical_threshold(self): """ @@ -138,22 +192,24 @@ class PddfThermal(ThermalBase): A float number, the low critical threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_crit_threshold") - if not output: - return None + if not self.is_psu_thermal: + output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_crit_threshold") + if not output: + return None - if output['status'].isalpha(): - attr_value = None - else: - attr_value = float(output['status']) + if output['status'].isalpha(): + attr_value = None + else: + attr_value = float(output['status']) - if output['mode'] == 'bmc': - return attr_value + if output['mode'] == 'bmc': + return attr_value + else: + return (attr_value/float(1000)) else: - return (attr_value/float(1000)) + raise NotImplementedError # Helper Functions - def get_temp_label(self): if 'bmc' in self.pddf_obj.data[self.thermal_obj_name].keys(): return None