[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
This commit is contained in:
FuzailBrcm 2022-03-18 23:44:10 +05:30 committed by GitHub
parent ad6200029f
commit d3f2da8679
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 248 additions and 76 deletions

View File

@ -10,7 +10,7 @@ try:
from sonic_platform_base.chassis_base import ChassisBase from sonic_platform_base.chassis_base import ChassisBase
from sonic_platform.sfp import Sfp from sonic_platform.sfp import Sfp
from sonic_platform.psu import Psu 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.thermal import Thermal
from sonic_platform.eeprom import Eeprom from sonic_platform.eeprom import Eeprom
except ImportError as e: except ImportError as e:
@ -52,9 +52,9 @@ class PddfChassis(ChassisBase):
# FANs # FANs
for i in range(self.platform_inventory['num_fantrays']): for i in range(self.platform_inventory['num_fantrays']):
for j in range(self.platform_inventory['num_fans_pertray']): fandrawer = FanDrawer(i, self.pddf_obj, self.plugin_data)
fan = Fan(i, j, self.pddf_obj, self.plugin_data) self._fan_drawer_list.append(fandrawer)
self._fan_list.append(fan) self._fan_list.extend(fandrawer._fan_list)
# PSUs # PSUs
for i in range(self.platform_inventory['num_psus']): for i in range(self.platform_inventory['num_psus']):

View File

@ -153,7 +153,7 @@ class PddfFan(FanBase):
speed = int(output['status']) speed = int(output['status'])
max_speed = int(self.plugin_data['PSU']['PSU_FAN_MAX_SPEED']) 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 return speed_percentage
else: else:
# TODO This calculation should change based on MAX FAN SPEED # TODO This calculation should change based on MAX FAN SPEED

View File

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

View File

@ -20,6 +20,7 @@
try: try:
from sonic_platform_base.psu_base import PsuBase from sonic_platform_base.psu_base import PsuBase
from sonic_platform.fan import Fan from sonic_platform.fan import Fan
from sonic_platform.thermal import Thermal
except ImportError as e: except ImportError as e:
raise ImportError(str(e) + "- required module not found") 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) psu_fan = Fan(0, psu_fan_idx, pddf_data, pddf_plugin_data, True, self.psu_index)
self._fan_list.append(psu_fan) 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): def get_num_fans(self):
""" """
Retrieves the number of fan modules available on this PSU Retrieves the number of fan modules available on this PSU

View File

@ -22,7 +22,7 @@ class PddfThermal(ThermalBase):
pddf_obj = {} pddf_obj = {}
plugin_data = {} 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: if not pddf_data or not pddf_plugin_data:
raise ValueError('PDDF JSON data error') 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_name = "TEMP{}".format(self.thermal_index)
self.thermal_obj = self.pddf_obj.data[self.thermal_obj_name] 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): def get_name(self):
if 'dev_attr' in self.thermal_obj.keys(): if self.is_psu_thermal:
if 'display_name' in self.thermal_obj['dev_attr']: return "PSU{}_TEMP{}".format(self.thermals_psu_index, self.thermal_index)
return str(self.thermal_obj['dev_attr']['display_name']) else:
# In case of errors if 'dev_attr' in self.thermal_obj.keys():
return (self.thermal_obj_name) 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): def get_temperature(self):
output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_input") if self.is_psu_thermal:
if not output: device = "PSU{}".format(self.thermals_psu_index)
return None output = self.pddf_obj.get_attr_name_output(device, "psu_temp1_input")
if not output:
return None
if output['status'].isalpha(): temp1 = output['status']
attr_value = None # temperature returned is in milli celcius
return float(temp1)/1000
else: 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': if output['status'].isalpha():
return attr_value attr_value = None
else: else:
return (attr_value/float(1000)) attr_value = float(output['status'])
if output['mode'] == 'bmc':
return attr_value
else:
return (attr_value/float(1000))
def get_high_threshold(self): def get_high_threshold(self):
output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_threshold") if not self.is_psu_thermal:
if not output: output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_threshold")
return None if not output:
return None
if output['status'].isalpha(): if output['status'].isalpha():
attr_value = None attr_value = None
else: else:
attr_value = float(output['status']) attr_value = float(output['status'])
if output['mode'] == 'bmc': if output['mode'] == 'bmc':
return attr_value return attr_value
else:
return (attr_value/float(1000))
else: else:
return (attr_value/float(1000)) raise NotImplementedError
def get_low_threshold(self): def get_low_threshold(self):
output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_threshold") if not self.is_psu_thermal:
if not output: output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_threshold")
return None if not output:
return None
if output['status'].isalpha(): if output['status'].isalpha():
attr_value = None attr_value = None
else: else:
attr_value = float(output['status']) attr_value = float(output['status'])
if output['mode'] == 'bmc': if output['mode'] == 'bmc':
return attr_value return attr_value
else:
return (attr_value/float(1000))
else: else:
return (attr_value/float(1000)) raise NotImplementedError
def set_high_threshold(self, temperature): def set_high_threshold(self, temperature):
node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_high_threshold") if not self.is_psu_thermal:
if node is None: node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_high_threshold")
print("ERROR %s does not exist" % node) if node is None:
return None print("ERROR %s does not exist" % node)
return None
cmd = "echo '%d' > %s" % (temperature * 1000, node) cmd = "echo '%d' > %s" % (temperature * 1000, node)
os.system(cmd) os.system(cmd)
return (True) return (True)
else:
raise NotImplementedError
def set_low_threshold(self, temperature): def set_low_threshold(self, temperature):
node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_low_threshold") if not self.is_psu_thermal:
if node is None: node = self.pddf_obj.get_path(self.thermal_obj_name, "temp1_low_threshold")
print("ERROR %s does not exist" % node) if node is None:
return None print("ERROR %s does not exist" % node)
cmd = "echo '%d' > %s" % (temperature * 1000, node) return None
os.system(cmd) cmd = "echo '%d' > %s" % (temperature * 1000, node)
os.system(cmd)
return (True) return (True)
else:
raise NotImplementedError
def get_high_critical_threshold(self): 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 A float number, the high critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125 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 self.is_psu_thermal:
if not output: output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_high_crit_threshold")
return None if not output:
return None
if output['status'].isalpha(): if output['status'].isalpha():
attr_value = None attr_value = None
else: else:
attr_value = float(output['status']) attr_value = float(output['status'])
if output['mode'] == 'bmc': if output['mode'] == 'bmc':
return attr_value return attr_value
else:
return (attr_value/float(1000))
else: else:
return (attr_value/float(1000)) raise NotImplementedError
def get_low_critical_threshold(self): 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 A float number, the low critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125 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 self.is_psu_thermal:
if not output: output = self.pddf_obj.get_attr_name_output(self.thermal_obj_name, "temp1_low_crit_threshold")
return None if not output:
return None
if output['status'].isalpha(): if output['status'].isalpha():
attr_value = None attr_value = None
else: else:
attr_value = float(output['status']) attr_value = float(output['status'])
if output['mode'] == 'bmc': if output['mode'] == 'bmc':
return attr_value return attr_value
else:
return (attr_value/float(1000))
else: else:
return (attr_value/float(1000)) raise NotImplementedError
# Helper Functions # Helper Functions
def get_temp_label(self): def get_temp_label(self):
if 'bmc' in self.pddf_obj.data[self.thermal_obj_name].keys(): if 'bmc' in self.pddf_obj.data[self.thermal_obj_name].keys():
return None return None