[Mellanox] Enhancement for fan led management (#4437)
This commit is contained in:
parent
d3c28a45d9
commit
5e6c20481d
1
device/mellanox/x86_64-mlnx_msn3420-r0/thermal_policy.json
Symbolic link
1
device/mellanox/x86_64-mlnx_msn3420-r0/thermal_policy.json
Symbolic link
@ -0,0 +1 @@
|
||||
../x86_64-mlnx_msn2700-r0/thermal_policy.json
|
1
device/mellanox/x86_64-mlnx_msn4600c-r0/thermal_policy.json
Symbolic link
1
device/mellanox/x86_64-mlnx_msn4600c-r0/thermal_policy.json
Symbolic link
@ -0,0 +1 @@
|
||||
../x86_64-mlnx_msn2700-r0/thermal_policy.json
|
1
device/mellanox/x86_64-mlnx_msn4700-r0/thermal_policy.json
Symbolic link
1
device/mellanox/x86_64-mlnx_msn4700-r0/thermal_policy.json
Symbolic link
@ -0,0 +1 @@
|
||||
../x86_64-mlnx_msn2700-r0/thermal_policy.json
|
@ -12,10 +12,10 @@ try:
|
||||
from sonic_platform_base.chassis_base import ChassisBase
|
||||
from sonic_platform_base.component_base import ComponentBase
|
||||
from sonic_device_util import get_machine_info
|
||||
from sonic_device_util import get_platform_info
|
||||
from sonic_daemon_base.daemon_base import Logger
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
from glob import glob
|
||||
import sys
|
||||
import io
|
||||
import re
|
||||
@ -61,12 +61,14 @@ class Chassis(ChassisBase):
|
||||
|
||||
# Initialize SKU name
|
||||
self.sku_name = self._get_sku_name()
|
||||
self.platform_name = self._get_platform_name()
|
||||
|
||||
mi = get_machine_info()
|
||||
if mi is not None:
|
||||
self.name = mi['onie_platform']
|
||||
self.platform_name = get_platform_info(mi)
|
||||
else:
|
||||
self.name = self.sku_name
|
||||
self.platform_name = self._get_platform_name()
|
||||
|
||||
# move the initialization of each components to their dedicated initializer
|
||||
# which will be called from platform
|
||||
@ -86,36 +88,29 @@ class Chassis(ChassisBase):
|
||||
# Initialize PSU list
|
||||
self.psu_module = Psu
|
||||
for index in range(MLNX_NUM_PSU):
|
||||
psu = Psu(index, self.sku_name)
|
||||
psu = Psu(index, self.platform_name)
|
||||
self._psu_list.append(psu)
|
||||
|
||||
|
||||
def initialize_fan(self):
|
||||
from .device_data import DEVICE_DATA
|
||||
from sonic_platform.fan import Fan
|
||||
from sonic_platform.fan import FAN_PATH
|
||||
self.fan_module = Fan
|
||||
self.fan_path = FAN_PATH
|
||||
# Initialize FAN list
|
||||
multi_rotor_in_drawer = False
|
||||
num_of_fan, num_of_drawer = self._extract_num_of_fans_and_fan_drawers()
|
||||
multi_rotor_in_drawer = num_of_fan > num_of_drawer
|
||||
from .fan_drawer import RealDrawer, VirtualDrawer
|
||||
|
||||
# Fan's direction isn't supported on spectrum 1 devices for now
|
||||
mst_dev_list = glob(MST_DEVICE_NAME_PATTERN)
|
||||
if not mst_dev_list:
|
||||
raise RuntimeError("Can't get chip type due to {} not found".format(MST_DEVICE_NAME_PATTERN))
|
||||
m = re.search(MST_DEVICE_RE_PATTERN, mst_dev_list[0])
|
||||
if m.group(1) == SPECTRUM1_CHIP_ID:
|
||||
has_fan_dir = False
|
||||
else:
|
||||
has_fan_dir = True
|
||||
|
||||
for index in range(num_of_fan):
|
||||
if multi_rotor_in_drawer:
|
||||
fan = Fan(has_fan_dir, index, index/2, False, self.platform_name)
|
||||
else:
|
||||
fan = Fan(has_fan_dir, index, index, False, self.platform_name)
|
||||
self._fan_list.append(fan)
|
||||
fan_data = DEVICE_DATA[self.platform_name]['fans']
|
||||
drawer_num = fan_data['drawer_num']
|
||||
drawer_type = fan_data['drawer_type']
|
||||
fan_num_per_drawer = fan_data['fan_num_per_drawer']
|
||||
drawer_ctor = RealDrawer if drawer_type == 'real' else VirtualDrawer
|
||||
fan_index = 0
|
||||
for drawer_index in range(drawer_num):
|
||||
drawer = drawer_ctor(drawer_index, fan_data)
|
||||
self._fan_drawer_list.append(drawer)
|
||||
for index in range(fan_num_per_drawer):
|
||||
fan = Fan(fan_index, drawer)
|
||||
fan_index += 1
|
||||
drawer._fan_list.append(fan)
|
||||
self._fan_list.append(fan)
|
||||
|
||||
|
||||
def initialize_sfp(self):
|
||||
|
@ -5,6 +5,19 @@ DEVICE_DATA = {
|
||||
"unk_trust": {"-127:30":13, "31:40":14 , "41:120":15},
|
||||
"unk_untrust": {"-127:25":13, "26:30":14 , "31:35":15, "36:120":16}
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 4,
|
||||
'drawer_type': 'real',
|
||||
'fan_num_per_drawer': 2,
|
||||
'support_fan_direction': False,
|
||||
'hot_swappable': True
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': True,
|
||||
'led_num': 1
|
||||
}
|
||||
},
|
||||
'x86_64-mlnx_msn2740-r0': {
|
||||
@ -13,6 +26,19 @@ DEVICE_DATA = {
|
||||
"unk_trust": {"-127:120":13},
|
||||
"unk_untrust": {"-127:15":13, "16:25":14 , "26:30":15, "31:120":17},
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 4,
|
||||
'drawer_type': 'real',
|
||||
'fan_num_per_drawer': 1,
|
||||
'support_fan_direction': False,
|
||||
'hot_swappable': True
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': True,
|
||||
'led_num': 1
|
||||
}
|
||||
},
|
||||
'x86_64-mlnx_msn2100-r0': {
|
||||
@ -21,6 +47,19 @@ DEVICE_DATA = {
|
||||
"unk_trust": {"-127:40":12, "41:120":13},
|
||||
"unk_untrust": {"-127:15":12, "16:25":13, "26:30":14, "31:35":15, "36:120":16}
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 1,
|
||||
'drawer_type': 'virtual',
|
||||
'fan_num_per_drawer': 4,
|
||||
'support_fan_direction': False,
|
||||
'hot_swappable': False
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': False,
|
||||
'led_num': 2
|
||||
}
|
||||
},
|
||||
'x86_64-mlnx_msn2410-r0': {
|
||||
@ -29,6 +68,19 @@ DEVICE_DATA = {
|
||||
"unk_trust": {"-127:30":13, "31:40":14 , "41:120":15},
|
||||
"unk_untrust": {"-127:25":13, "26:30":14 , "31:35":15, "36:120":16}
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 4,
|
||||
'drawer_type': 'real',
|
||||
'fan_num_per_drawer': 2,
|
||||
'support_fan_direction': False,
|
||||
'hot_swappable': True
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': True,
|
||||
'led_num': 1
|
||||
}
|
||||
},
|
||||
'x86_64-mlnx_msn2010-r0': {
|
||||
@ -37,6 +89,19 @@ DEVICE_DATA = {
|
||||
"unk_trust": {"-127:120":12},
|
||||
"unk_untrust": {"-127:15":12, "16:20":13 , "21:30":14, "31:35":15, "36:120":16}
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 1,
|
||||
'drawer_type': 'virtual',
|
||||
'fan_num_per_drawer': 4,
|
||||
'support_fan_direction': False,
|
||||
'hot_swappable': False
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': False,
|
||||
'led_num': 2
|
||||
}
|
||||
},
|
||||
'x86_64-mlnx_msn3700-r0': {
|
||||
@ -45,6 +110,19 @@ DEVICE_DATA = {
|
||||
"unk_trust": {"-127:25":12, "26:40":13 , "41:120":14},
|
||||
"unk_untrust": {"-127:15":12, "16:30":13 , "31:35":14, "36:40":15, "41:120":16},
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 6,
|
||||
'drawer_type': 'real',
|
||||
'fan_num_per_drawer': 2,
|
||||
'support_fan_direction': True,
|
||||
'hot_swappable': True
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': True,
|
||||
'led_num': 1
|
||||
}
|
||||
},
|
||||
'x86_64-mlnx_msn3700c-r0': {
|
||||
@ -53,6 +131,19 @@ DEVICE_DATA = {
|
||||
"unk_trust": {"-127:40":12, "41:120":13},
|
||||
"unk_untrust": {"-127:10":12, "11:20":13 , "21:30":14, "31:35":15, "36:120":16},
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 4,
|
||||
'drawer_type': 'real',
|
||||
'fan_num_per_drawer': 2,
|
||||
'support_fan_direction': True,
|
||||
'hot_swappable': True
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': True,
|
||||
'led_num': 1
|
||||
}
|
||||
},
|
||||
'x86_64-mlnx_msn3800-r0': {
|
||||
@ -61,14 +152,82 @@ DEVICE_DATA = {
|
||||
"unk_trust": {"-127:30":12, "31:40":13 , "41:120":14},
|
||||
"unk_untrust": {"-127:0":12, "1:10":13 , "11:15":14, "16:20":15, "21:35":16, "36:120":17},
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 3,
|
||||
'drawer_type': 'real',
|
||||
'fan_num_per_drawer': 1,
|
||||
'support_fan_direction': True,
|
||||
'hot_swappable': True
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': True,
|
||||
'led_num': 1
|
||||
}
|
||||
},
|
||||
'x86_64-mlnx_msn4700-r0': {
|
||||
'thermal': {
|
||||
'minimum_table': {
|
||||
"unk_trust": {"-127:120":16},
|
||||
"unk_untrust": {"-127:120":16},
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 6,
|
||||
'drawer_type': 'real',
|
||||
'fan_num_per_drawer': 2,
|
||||
'support_fan_direction': True,
|
||||
'hot_swappable': True
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': True,
|
||||
'led_num': 1
|
||||
}
|
||||
},
|
||||
'x86_64-mlnx_msn3420-r0': {
|
||||
'thermal': {
|
||||
'minimum_table': {
|
||||
"unk_trust": {"-127:120":16},
|
||||
"unk_untrust": {"-127:120":16},
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 5,
|
||||
'drawer_type': 'real',
|
||||
'fan_num_per_drawer': 2,
|
||||
'support_fan_direction': True,
|
||||
'hot_swappable': True
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': True,
|
||||
'led_num': 1
|
||||
}
|
||||
},
|
||||
'x86_64-mlnx_msn4600c-r0': {
|
||||
'thermal': {
|
||||
'minimum_table': {
|
||||
"unk_trust": {"-127:120":16},
|
||||
"unk_untrust": {"-127:120":16},
|
||||
}
|
||||
},
|
||||
'fans': {
|
||||
'drawer_num': 3,
|
||||
'drawer_type': 'real',
|
||||
'fan_num_per_drawer': 1,
|
||||
'support_fan_direction': True,
|
||||
'hot_swappable': True
|
||||
},
|
||||
'psus': {
|
||||
'psu_num': 2,
|
||||
'fan_num_per_psu': 1,
|
||||
'hot_swappable': True,
|
||||
'led_num': 1
|
||||
}
|
||||
}
|
||||
}
|
@ -13,25 +13,18 @@ import subprocess
|
||||
|
||||
try:
|
||||
from sonic_platform_base.fan_base import FanBase
|
||||
from .led import FanLed, ComponentFaultyIndicator
|
||||
except ImportError as e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
|
||||
LED_ON = '1'
|
||||
LED_OFF = '0'
|
||||
|
||||
PWM_MAX = 255
|
||||
|
||||
FAN_PATH = "/var/run/hw-management/thermal/"
|
||||
LED_PATH = "/var/run/hw-management/led/"
|
||||
CONFIG_PATH = "/var/run/hw-management/config"
|
||||
# fan_dir isn't supported on Spectrum 1. It is supported on Spectrum 2 and later switches
|
||||
FAN_DIR = "/var/run/hw-management/system/fan_dir"
|
||||
COOLING_STATE_PATH = "/var/run/hw-management/thermal/cooling_cur_state"
|
||||
|
||||
# Platforms with unplugable FANs:
|
||||
# 1. don't have fanX_status and should be treated as always present
|
||||
platform_with_unplugable_fan = ['x86_64-mlnx_msn2010-r0', 'x86_64-mlnx_msn2100-r0']
|
||||
|
||||
|
||||
class Fan(FanBase):
|
||||
"""Platform-specific Fan class"""
|
||||
@ -44,21 +37,28 @@ class Fan(FanBase):
|
||||
PSU_FAN_SPEED = ['0x3c', '0x3c', '0x3c', '0x3c', '0x3c',
|
||||
'0x3c', '0x3c', '0x46', '0x50', '0x5a', '0x64']
|
||||
|
||||
def __init__(self, has_fan_dir, fan_index, drawer_index = 1, psu_fan = False, platform = None):
|
||||
def __init__(self, fan_index, fan_drawer, psu_fan = False):
|
||||
super(Fan, self).__init__()
|
||||
|
||||
# API index is starting from 0, Mellanox platform index is starting from 1
|
||||
self.index = fan_index + 1
|
||||
self.drawer_index = drawer_index + 1
|
||||
self.fan_drawer = fan_drawer
|
||||
|
||||
self.is_psu_fan = psu_fan
|
||||
self.always_presence = False if platform not in platform_with_unplugable_fan else True
|
||||
if self.fan_drawer:
|
||||
self.led = ComponentFaultyIndicator(self.fan_drawer.get_led())
|
||||
elif self.is_psu_fan:
|
||||
from .psu import Psu
|
||||
self.led = ComponentFaultyIndicator(Psu.get_shared_led())
|
||||
else:
|
||||
self.led = FanLed(self.index)
|
||||
|
||||
self.fan_min_speed_path = "fan{}_min".format(self.index)
|
||||
if not self.is_psu_fan:
|
||||
self.fan_speed_get_path = "fan{}_speed_get".format(self.index)
|
||||
self.fan_speed_set_path = "fan{}_speed_set".format(self.index)
|
||||
self.fan_presence_path = "fan{}_status".format(self.drawer_index)
|
||||
self.fan_max_speed_path = "fan{}_max".format(self.index)
|
||||
self._name = "fan{}".format(fan_index + 1)
|
||||
self._name = "fan{}".format(self.index)
|
||||
else:
|
||||
self.fan_speed_get_path = "psu{}_fan1_speed_get".format(self.index)
|
||||
self.fan_presence_path = "psu{}_fan1_speed_get".format(self.index)
|
||||
@ -69,15 +69,7 @@ class Fan(FanBase):
|
||||
self.psu_i2c_command_path = os.path.join(CONFIG_PATH, 'fan_command')
|
||||
|
||||
self.fan_status_path = "fan{}_fault".format(self.index)
|
||||
self.fan_green_led_path = "led_fan{}_green".format(self.drawer_index)
|
||||
self.fan_red_led_path = "led_fan{}_red".format(self.drawer_index)
|
||||
self.fan_orange_led_path = "led_fan{}_orange".format(self.drawer_index)
|
||||
self.fan_pwm_path = "pwm1"
|
||||
self.fan_led_cap_path = "led_fan{}_capability".format(self.drawer_index)
|
||||
if has_fan_dir:
|
||||
self.fan_dir = FAN_DIR
|
||||
else:
|
||||
self.fan_dir = None
|
||||
|
||||
|
||||
def get_direction(self):
|
||||
@ -99,20 +91,10 @@ class Fan(FanBase):
|
||||
1 stands for forward, in other words intake
|
||||
0 stands for reverse, in other words exhaust
|
||||
"""
|
||||
if not self.fan_dir or self.is_psu_fan or not self.get_presence():
|
||||
if self.is_psu_fan:
|
||||
return self.FAN_DIRECTION_NOT_APPLICABLE
|
||||
|
||||
try:
|
||||
with open(os.path.join(self.fan_dir), 'r') as fan_dir:
|
||||
fan_dir_bits = int(fan_dir.read().strip())
|
||||
fan_mask = 1 << self.drawer_index - 1
|
||||
if fan_dir_bits & fan_mask:
|
||||
return self.FAN_DIRECTION_INTAKE
|
||||
else:
|
||||
return self.FAN_DIRECTION_EXHAUST
|
||||
except (ValueError, IOError) as e:
|
||||
raise RuntimeError("Failed to read fan direction status to {}".format(repr(e)))
|
||||
|
||||
else:
|
||||
return self.fan_drawer.get_direction()
|
||||
|
||||
def get_name(self):
|
||||
return self._name
|
||||
@ -150,17 +132,9 @@ class Fan(FanBase):
|
||||
status = 1
|
||||
else:
|
||||
status = 0
|
||||
return status == 1
|
||||
else:
|
||||
if self.always_presence:
|
||||
status = 1
|
||||
else:
|
||||
try:
|
||||
with open(os.path.join(FAN_PATH, self.fan_presence_path), 'r') as presence_status:
|
||||
status = int(presence_status.read().strip())
|
||||
except (ValueError, IOError):
|
||||
status = 0
|
||||
|
||||
return status == 1
|
||||
return self.fan_drawer.get_presence()
|
||||
|
||||
|
||||
def _get_min_speed_in_rpm(self):
|
||||
@ -281,18 +255,6 @@ class Fan(FanBase):
|
||||
return status
|
||||
|
||||
|
||||
def _get_led_capability(self):
|
||||
cap_list = None
|
||||
try:
|
||||
with open(os.path.join(LED_PATH, self.fan_led_cap_path), 'r') as fan_led_cap:
|
||||
caps = fan_led_cap.read()
|
||||
cap_list = caps.split()
|
||||
except (ValueError, IOError):
|
||||
status = 0
|
||||
|
||||
return cap_list
|
||||
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Set led to expected color
|
||||
@ -304,48 +266,7 @@ class Fan(FanBase):
|
||||
Returns:
|
||||
bool: True if set success, False if fail.
|
||||
"""
|
||||
led_cap_list = self._get_led_capability()
|
||||
if led_cap_list is None:
|
||||
return False
|
||||
|
||||
if self.is_psu_fan:
|
||||
# PSU fan led status is not able to set
|
||||
return False
|
||||
status = False
|
||||
try:
|
||||
if color == self.STATUS_LED_COLOR_GREEN:
|
||||
with open(os.path.join(LED_PATH, self.fan_green_led_path), 'w') as fan_led:
|
||||
fan_led.write(LED_ON)
|
||||
status = True
|
||||
elif color == self.STATUS_LED_COLOR_RED:
|
||||
# Some fan don't support red led but support orange led, in this case we set led to orange
|
||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
||||
led_path = os.path.join(LED_PATH, self.fan_red_led_path)
|
||||
elif self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||
led_path = os.path.join(LED_PATH, self.fan_orange_led_path)
|
||||
else:
|
||||
return False
|
||||
with open(led_path, 'w') as fan_led:
|
||||
fan_led.write(LED_ON)
|
||||
status = True
|
||||
elif color == self.STATUS_LED_COLOR_OFF:
|
||||
if self.STATUS_LED_COLOR_GREEN in led_cap_list:
|
||||
with open(os.path.join(LED_PATH, self.fan_green_led_path), 'w') as fan_led:
|
||||
fan_led.write(str(LED_OFF))
|
||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
||||
with open(os.path.join(LED_PATH, self.fan_red_led_path), 'w') as fan_led:
|
||||
fan_led.write(str(LED_OFF))
|
||||
if self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||
with open(os.path.join(LED_PATH, self.fan_orange_led_path), 'w') as fan_led:
|
||||
fan_led.write(str(LED_OFF))
|
||||
|
||||
status = True
|
||||
else:
|
||||
status = False
|
||||
except (ValueError, IOError):
|
||||
status = False
|
||||
|
||||
return status
|
||||
return self.led.set_status(color)
|
||||
|
||||
|
||||
def get_status_led(self):
|
||||
@ -355,26 +276,7 @@ class Fan(FanBase):
|
||||
Returns:
|
||||
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
||||
"""
|
||||
led_cap_list = self._get_led_capability()
|
||||
if led_cap_list is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
try:
|
||||
with open(os.path.join(LED_PATH, self.fan_green_led_path), 'r') as fan_led:
|
||||
if LED_OFF != fan_led.read().rstrip('\n'):
|
||||
return self.STATUS_LED_COLOR_GREEN
|
||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
||||
with open(os.path.join(LED_PATH, self.fan_red_led_path), 'r') as fan_led:
|
||||
if LED_OFF != fan_led.read().rstrip('\n'):
|
||||
return self.STATUS_LED_COLOR_RED
|
||||
if self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||
with open(os.path.join(LED_PATH, self.fan_orange_led_path), 'r') as fan_led:
|
||||
if LED_OFF != fan_led.read().rstrip('\n'):
|
||||
return self.STATUS_LED_COLOR_RED
|
||||
except (ValueError, IOError) as e:
|
||||
raise RuntimeError("Failed to read led status for fan {} due to {}".format(self.index, repr(e)))
|
||||
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
return self.led.get_status()
|
||||
|
||||
|
||||
def get_speed_tolerance(self):
|
||||
|
104
platform/mellanox/mlnx-platform-api/sonic_platform/fan_drawer.py
Normal file
104
platform/mellanox/mlnx-platform-api/sonic_platform/fan_drawer.py
Normal file
@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# Mellanox
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Fan Drawer status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
|
||||
try:
|
||||
from sonic_platform_base.fan_drawer_base import FanDrawerBase
|
||||
from sonic_platform_base.fan_base import FanBase
|
||||
from .led import FanLed, SharedLed
|
||||
except ImportError as e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
|
||||
|
||||
class MellanoxFanDrawer(FanDrawerBase):
|
||||
def __init__(self, index, fan_data):
|
||||
from .fan import FAN_PATH
|
||||
super(MellanoxFanDrawer, self).__init__()
|
||||
self._index = index + 1
|
||||
self._fan_data = fan_data
|
||||
self._presence_path = os.path.join(FAN_PATH, 'fan{}_status'.format(self._index))
|
||||
self._led = None
|
||||
|
||||
def get_index(self):
|
||||
return self._index
|
||||
|
||||
def get_led(self):
|
||||
return self._led
|
||||
|
||||
def get_presence(self):
|
||||
if not self._fan_data['hot_swappable']:
|
||||
return True
|
||||
|
||||
status = 0
|
||||
try:
|
||||
with open(self._presence_path, 'r') as presence_status:
|
||||
status = int(presence_status.read())
|
||||
except (ValueError, IOError) as e:
|
||||
status = 0
|
||||
|
||||
return status == 1
|
||||
|
||||
def get_direction(self):
|
||||
if not self._fan_data['support_fan_direction'] or not self.get_presence():
|
||||
return FanBase.FAN_DIRECTION_NOT_APPLICABLE
|
||||
|
||||
try:
|
||||
from .fan import FAN_DIR
|
||||
with open(FAN_DIR, 'r') as fan_dir:
|
||||
fan_dir_bits = int(fan_dir.read())
|
||||
fan_mask = 1 << self._index - 1
|
||||
if fan_dir_bits & fan_mask:
|
||||
return FanBase.FAN_DIRECTION_INTAKE
|
||||
else:
|
||||
return FanBase.FAN_DIRECTION_EXHAUST
|
||||
except (ValueError, IOError) as e:
|
||||
raise RuntimeError("Failed to read fan direction status to {}".format(repr(e)))
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Sets the state of the fan drawer status LED
|
||||
|
||||
Args:
|
||||
color: A string representing the color with which to set the
|
||||
fan drawer status LED
|
||||
|
||||
Returns:
|
||||
bool: True if status LED state is set successfully, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_status_led(self):
|
||||
"""
|
||||
Gets the state of the fan drawer LED
|
||||
|
||||
Returns:
|
||||
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
||||
"""
|
||||
return self._led.get_status()
|
||||
|
||||
|
||||
class RealDrawer(MellanoxFanDrawer):
|
||||
def __init__(self, index, fan_data):
|
||||
super(RealDrawer, self).__init__(index, fan_data)
|
||||
self._name = 'drawer{}'.format(self._index)
|
||||
self._led = SharedLed(FanLed(self._index))
|
||||
|
||||
def get_name(self):
|
||||
return self._name
|
||||
|
||||
|
||||
class VirtualDrawer(MellanoxFanDrawer):
|
||||
def __init__(self, index, fan_data):
|
||||
super(VirtualDrawer, self).__init__(index, fan_data)
|
||||
self._led = SharedLed(FanLed(None))
|
||||
|
||||
def get_name(self):
|
||||
return 'N/A'
|
201
platform/mellanox/mlnx-platform-api/sonic_platform/led.py
Normal file
201
platform/mellanox/mlnx-platform-api/sonic_platform/led.py
Normal file
@ -0,0 +1,201 @@
|
||||
import os
|
||||
|
||||
|
||||
class Led(object):
|
||||
STATUS_LED_COLOR_GREEN = 'green'
|
||||
STATUS_LED_COLOR_RED = 'red'
|
||||
STATUS_LED_COLOR_ORANGE = 'orange'
|
||||
STATUS_LED_COLOR_OFF = 'off'
|
||||
|
||||
LED_ON = '1'
|
||||
LED_OFF = '0'
|
||||
|
||||
LED_PATH = "/var/run/hw-management/led/"
|
||||
|
||||
def set_status(self, color):
|
||||
led_cap_list = self.get_capability()
|
||||
if led_cap_list is None:
|
||||
return False
|
||||
|
||||
status = False
|
||||
try:
|
||||
if color == Led.STATUS_LED_COLOR_GREEN:
|
||||
with open(self.get_green_led_path(), 'w') as led:
|
||||
led.write(Led.LED_ON)
|
||||
status = True
|
||||
elif color == Led.STATUS_LED_COLOR_RED:
|
||||
# Some led don't support red led but support orange led, in this case we set led to orange
|
||||
if Led.STATUS_LED_COLOR_RED in led_cap_list:
|
||||
led_path = self.get_red_led_path()
|
||||
elif Led.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||
led_path = self.get_orange_led_path()
|
||||
else:
|
||||
return False
|
||||
|
||||
with open(led_path, 'w') as led:
|
||||
led.write(Led.LED_ON)
|
||||
status = True
|
||||
elif color == Led.STATUS_LED_COLOR_OFF:
|
||||
if Led.STATUS_LED_COLOR_GREEN in led_cap_list:
|
||||
with open(self.get_green_led_path(), 'w') as led:
|
||||
led.write(Led.LED_OFF)
|
||||
if Led.STATUS_LED_COLOR_RED in led_cap_list:
|
||||
with open(self.get_red_led_path(), 'w') as led:
|
||||
led.write(Led.LED_OFF)
|
||||
if Led.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||
with open(self.get_orange_led_path(), 'w') as led:
|
||||
led.write(Led.LED_OFF)
|
||||
|
||||
status = True
|
||||
else:
|
||||
status = False
|
||||
except (ValueError, IOError):
|
||||
status = False
|
||||
|
||||
return status
|
||||
|
||||
def get_status(self):
|
||||
led_cap_list = self.get_capability()
|
||||
if led_cap_list is None:
|
||||
return Led.STATUS_LED_COLOR_OFF
|
||||
|
||||
try:
|
||||
with open(self.get_green_led_path(), 'r') as led:
|
||||
if Led.LED_OFF != led.read().rstrip('\n'):
|
||||
return Led.STATUS_LED_COLOR_GREEN
|
||||
|
||||
if Led.STATUS_LED_COLOR_RED in led_cap_list:
|
||||
with open(self.get_red_led_path(), 'r') as led:
|
||||
if Led.LED_OFF != led.read().rstrip('\n'):
|
||||
return Led.STATUS_LED_COLOR_RED
|
||||
if Led.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||
with open(self.get_orange_led_path(), 'r') as led:
|
||||
if Led.LED_OFF != led.read().rstrip('\n'):
|
||||
return Led.STATUS_LED_COLOR_RED
|
||||
except (ValueError, IOError) as e:
|
||||
raise RuntimeError("Failed to read led status due to {}".format(repr(e)))
|
||||
|
||||
return Led.STATUS_LED_COLOR_OFF
|
||||
|
||||
def get_capability(self):
|
||||
cap_list = None
|
||||
try:
|
||||
with open(self.get_led_cap_path(), 'r') as led_cap:
|
||||
caps = led_cap.read()
|
||||
cap_list = caps.split()
|
||||
except (ValueError, IOError):
|
||||
pass
|
||||
|
||||
return cap_list
|
||||
|
||||
def get_green_led_path(self):
|
||||
pass
|
||||
|
||||
def get_red_led_path(self):
|
||||
pass
|
||||
|
||||
def get_orange_led_path(self):
|
||||
pass
|
||||
|
||||
def get_led_cap_path(self):
|
||||
pass
|
||||
|
||||
|
||||
class FanLed(Led):
|
||||
LED_PATH = "/var/run/hw-management/led/"
|
||||
|
||||
def __init__(self, index):
|
||||
if index is not None:
|
||||
self._green_led_path = os.path.join(Led.LED_PATH, "led_fan{}_green".format(index))
|
||||
self._red_led_path = os.path.join(Led.LED_PATH, "led_fan{}_red".format(index))
|
||||
self._orange_led_path = os.path.join(Led.LED_PATH, "led_fan{}_orange".format(index))
|
||||
self._led_cap_path = os.path.join(Led.LED_PATH, "led_fan{}_capability".format(index))
|
||||
else:
|
||||
self._green_led_path = os.path.join(Led.LED_PATH, "led_fan_green")
|
||||
self._red_led_path = os.path.join(Led.LED_PATH, "led_fan_red")
|
||||
self._orange_led_path = os.path.join(Led.LED_PATH, "led_fan_orange")
|
||||
self._led_cap_path = os.path.join(Led.LED_PATH, "led_fan_capability")
|
||||
|
||||
self.set_status(Led.STATUS_LED_COLOR_GREEN)
|
||||
|
||||
def get_green_led_path(self):
|
||||
return self._green_led_path
|
||||
|
||||
def get_red_led_path(self):
|
||||
return self._red_led_path
|
||||
|
||||
def get_orange_led_path(self):
|
||||
return self._orange_led_path
|
||||
|
||||
def get_led_cap_path(self):
|
||||
return self._led_cap_path
|
||||
|
||||
|
||||
class PsuLed(Led):
|
||||
def __init__(self, index):
|
||||
if index is not None:
|
||||
self._green_led_path = os.path.join(Led.LED_PATH, "led_psu{}_green".format(index))
|
||||
self._red_led_path = os.path.join(Led.LED_PATH, "led_psu{}_red".format(index))
|
||||
self._orange_led_path = os.path.join(Led.LED_PATH, "led_psu{}_orange".format(index))
|
||||
self._led_cap_path = os.path.join(Led.LED_PATH, "led_psu{}_capability".format(index))
|
||||
else:
|
||||
self._green_led_path = os.path.join(Led.LED_PATH, "led_psu_green")
|
||||
self._red_led_path = os.path.join(Led.LED_PATH, "led_psu_red")
|
||||
self._orange_led_path = os.path.join(Led.LED_PATH, "led_psu_orange")
|
||||
self._led_cap_path = os.path.join(Led.LED_PATH, "led_psu_capability")
|
||||
|
||||
self.set_status(Led.STATUS_LED_COLOR_GREEN)
|
||||
|
||||
def get_green_led_path(self):
|
||||
return self._green_led_path
|
||||
|
||||
def get_red_led_path(self):
|
||||
return self._red_led_path
|
||||
|
||||
def get_orange_led_path(self):
|
||||
return self._orange_led_path
|
||||
|
||||
def get_led_cap_path(self):
|
||||
return self._led_cap_path
|
||||
|
||||
|
||||
class SharedLed(object):
|
||||
LED_PRIORITY = {
|
||||
Led.STATUS_LED_COLOR_RED: 0,
|
||||
Led.STATUS_LED_COLOR_GREEN: 1
|
||||
}
|
||||
|
||||
def __init__(self, led):
|
||||
self._led = led
|
||||
self._virtual_leds = []
|
||||
|
||||
def add_virtual_leds(self, led):
|
||||
self._virtual_leds.append(led)
|
||||
|
||||
def update_status_led(self):
|
||||
target_color = Led.STATUS_LED_COLOR_GREEN
|
||||
for virtual_led in self._virtual_leds:
|
||||
if SharedLed.LED_PRIORITY[virtual_led.get_led_color()] < SharedLed.LED_PRIORITY[target_color]:
|
||||
target_color = virtual_led.get_led_color()
|
||||
|
||||
return self._led.set_status(target_color)
|
||||
|
||||
def get_status(self):
|
||||
return self._led.get_status()
|
||||
|
||||
|
||||
class ComponentFaultyIndicator(object):
|
||||
def __init__(self, shared_led):
|
||||
self._color = Led.STATUS_LED_COLOR_GREEN
|
||||
self._shared_led = shared_led
|
||||
self._shared_led.add_virtual_leds(self)
|
||||
|
||||
def set_status(self, color):
|
||||
self._color = color
|
||||
return self._shared_led.update_status_led()
|
||||
|
||||
def get_led_color(self):
|
||||
return self._color
|
||||
|
||||
def get_status(self):
|
||||
return self._shared_led.get_status()
|
@ -13,11 +13,11 @@ try:
|
||||
from sonic_platform_base.psu_base import PsuBase
|
||||
from sonic_daemon_base.daemon_base import Logger
|
||||
from sonic_platform.fan import Fan
|
||||
from .led import PsuLed, SharedLed, ComponentFaultyIndicator
|
||||
from .device_data import DEVICE_DATA
|
||||
except ImportError as e:
|
||||
raise ImportError (str(e) + "- required module not found")
|
||||
|
||||
LED_ON = '1'
|
||||
LED_OFF = '0'
|
||||
|
||||
# Global logger class instance
|
||||
logger = Logger()
|
||||
@ -28,16 +28,11 @@ PSU_CURRENT = "current"
|
||||
PSU_VOLTAGE = "voltage"
|
||||
PSU_POWER = "power"
|
||||
|
||||
LED_PATH = "/var/run/hw-management/led/"
|
||||
|
||||
# SKUs with unplugable PSUs:
|
||||
# 1. don't have psuX_status and should be treated as always present
|
||||
# 2. don't have voltage, current and power values
|
||||
hwsku_dict_with_unplugable_psu = ['ACS-MSN2010', 'ACS-MSN2100']
|
||||
|
||||
# in most SKUs the file psuX_curr, psuX_volt and psuX_power contain current, voltage and power data respectively.
|
||||
# in most platforms the file psuX_curr, psuX_volt and psuX_power contain current, voltage and power data respectively.
|
||||
# but there are exceptions which will be handled by the following dictionary
|
||||
hwsku_dict_psu = {'ACS-MSN3700': 1, 'ACS-MSN3700C': 1, 'ACS-MSN3800': 1, 'Mellanox-SN3800-D112C8': 1, 'ACS-MSN4700': 1, 'ACS-MSN3420': 1, 'ACS-MSN4600C': 1}
|
||||
|
||||
platform_dict_psu = {'x86_64-mlnx_msn3700-r0': 1, 'x86_64-mlnx_msn3700c-r0': 1, 'x86_64-mlnx_msn3800-r0': 1, 'x86_64-mlnx_msn4700-r0': 1}
|
||||
|
||||
psu_profile_list = [
|
||||
# default filename convention
|
||||
{
|
||||
@ -56,9 +51,9 @@ psu_profile_list = [
|
||||
class Psu(PsuBase):
|
||||
"""Platform-specific Psu class"""
|
||||
|
||||
STATUS_LED_COLOR_ORANGE = "orange"
|
||||
shared_led = None
|
||||
|
||||
def __init__(self, psu_index, sku):
|
||||
def __init__(self, psu_index, platform):
|
||||
global psu_list
|
||||
PsuBase.__init__(self)
|
||||
# PSU is 1-based on Mellanox platform
|
||||
@ -66,17 +61,19 @@ class Psu(PsuBase):
|
||||
psu_list.append(self.index)
|
||||
self.psu_path = "/var/run/hw-management/"
|
||||
psu_oper_status = "thermal/psu{}_pwr_status".format(self.index)
|
||||
#psu_oper_status should always be present for all SKUs
|
||||
#psu_oper_status should always be present for all platforms
|
||||
self.psu_oper_status = os.path.join(self.psu_path, psu_oper_status)
|
||||
self._name = "PSU{}".format(psu_index + 1)
|
||||
|
||||
if sku in hwsku_dict_psu:
|
||||
filemap = psu_profile_list[hwsku_dict_psu[sku]]
|
||||
if platform in platform_dict_psu:
|
||||
filemap = psu_profile_list[platform_dict_psu[platform]]
|
||||
else:
|
||||
filemap = psu_profile_list[0]
|
||||
|
||||
if sku in hwsku_dict_with_unplugable_psu:
|
||||
self.always_presence = True
|
||||
self.psu_data = DEVICE_DATA[platform]['psus']
|
||||
|
||||
if not self.psu_data['hot_swappable']:
|
||||
self.always_present = True
|
||||
self.psu_voltage = None
|
||||
self.psu_current = None
|
||||
self.psu_power = None
|
||||
@ -84,7 +81,7 @@ class Psu(PsuBase):
|
||||
self.psu_temp = None
|
||||
self.psu_temp_threshold = None
|
||||
else:
|
||||
self.always_presence = False
|
||||
self.always_present = False
|
||||
psu_voltage = filemap[PSU_VOLTAGE].format(self.index)
|
||||
psu_voltage = os.path.join(self.psu_path, psu_voltage)
|
||||
self.psu_voltage = psu_voltage
|
||||
@ -105,14 +102,14 @@ class Psu(PsuBase):
|
||||
self.psu_temp_threshold = os.path.join(self.psu_path, 'thermal/psu{}_temp_max'.format(self.index))
|
||||
|
||||
# unplugable PSU has no FAN
|
||||
if sku not in hwsku_dict_with_unplugable_psu:
|
||||
fan = Fan(False, psu_index, psu_index, True)
|
||||
if self.psu_data['hot_swappable']:
|
||||
fan = Fan(psu_index, None, True)
|
||||
self._fan_list.append(fan)
|
||||
|
||||
self.psu_green_led_path = "led_psu_green"
|
||||
self.psu_red_led_path = "led_psu_red"
|
||||
self.psu_orange_led_path = "led_psu_orange"
|
||||
self.psu_led_cap_path = "led_psu_capability"
|
||||
if self.psu_data['led_num'] == 1:
|
||||
self.led = ComponentFaultyIndicator(Psu.get_shared_led())
|
||||
else: # 2010/2100
|
||||
self.led = PsuLed(self.index)
|
||||
|
||||
|
||||
def get_name(self):
|
||||
@ -151,8 +148,8 @@ class Psu(PsuBase):
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
"""
|
||||
if self.always_presence:
|
||||
return self.always_presence
|
||||
if self.always_present:
|
||||
return self.always_present
|
||||
else:
|
||||
status = self._read_generic_file(self.psu_presence, 0)
|
||||
return status == 1
|
||||
@ -199,19 +196,6 @@ class Psu(PsuBase):
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _get_led_capability(self):
|
||||
cap_list = None
|
||||
try:
|
||||
with open(os.path.join(LED_PATH, self.psu_led_cap_path), 'r') as psu_led_cap:
|
||||
caps = psu_led_cap.read()
|
||||
cap_list = caps.split()
|
||||
except (ValueError, IOError):
|
||||
status = 0
|
||||
|
||||
return cap_list
|
||||
|
||||
|
||||
def set_status_led(self, color):
|
||||
"""
|
||||
Sets the state of the PSU status LED
|
||||
@ -226,45 +210,7 @@ class Psu(PsuBase):
|
||||
Notes:
|
||||
Only one led for all PSUs.
|
||||
"""
|
||||
led_cap_list = self._get_led_capability()
|
||||
if led_cap_list is None:
|
||||
return False
|
||||
|
||||
status = False
|
||||
try:
|
||||
if color == self.STATUS_LED_COLOR_GREEN:
|
||||
with open(os.path.join(LED_PATH, self.psu_green_led_path), 'w') as psu_led:
|
||||
psu_led.write(LED_ON)
|
||||
status = True
|
||||
elif color == self.STATUS_LED_COLOR_RED:
|
||||
# Some fan don't support red led but support orange led, in this case we set led to orange
|
||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
||||
led_path = os.path.join(LED_PATH, self.psu_red_led_path)
|
||||
elif self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||
led_path = os.path.join(LED_PATH, self.psu_orange_led_path)
|
||||
else:
|
||||
return False
|
||||
with open(led_path, 'w') as psu_led:
|
||||
psu_led.write(LED_ON)
|
||||
status = True
|
||||
elif color == self.STATUS_LED_COLOR_OFF:
|
||||
if self.STATUS_LED_COLOR_GREEN in led_cap_list:
|
||||
with open(os.path.join(LED_PATH, self.psu_green_led_path), 'w') as psu_led:
|
||||
psu_led.write(str(LED_OFF))
|
||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
||||
with open(os.path.join(LED_PATH, self.psu_red_led_path), 'w') as psu_led:
|
||||
psu_led.write(str(LED_OFF))
|
||||
if self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||
with open(os.path.join(LED_PATH, self.psu_orange_led_path), 'w') as psu_led:
|
||||
psu_led.write(str(LED_OFF))
|
||||
|
||||
status = True
|
||||
else:
|
||||
status = False
|
||||
except (ValueError, IOError):
|
||||
status = False
|
||||
|
||||
return status
|
||||
return self.led.set_status(color)
|
||||
|
||||
|
||||
def get_status_led(self):
|
||||
@ -274,26 +220,10 @@ class Psu(PsuBase):
|
||||
Returns:
|
||||
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
||||
"""
|
||||
led_cap_list = self._get_led_capability()
|
||||
if led_cap_list is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
try:
|
||||
with open(os.path.join(LED_PATH, self.psu_green_led_path), 'r') as psu_led:
|
||||
if LED_OFF != psu_led.read().rstrip('\n'):
|
||||
return self.STATUS_LED_COLOR_GREEN
|
||||
if self.STATUS_LED_COLOR_RED in led_cap_list:
|
||||
with open(os.path.join(LED_PATH, self.psu_red_led_path), 'r') as psu_led:
|
||||
if LED_OFF != psu_led.read().rstrip('\n'):
|
||||
return self.STATUS_LED_COLOR_RED
|
||||
if self.STATUS_LED_COLOR_ORANGE in led_cap_list:
|
||||
with open(os.path.join(LED_PATH, self.psu_orange_led_path), 'r') as psu_led:
|
||||
if LED_OFF != psu_led.read().rstrip('\n'):
|
||||
return self.STATUS_LED_COLOR_RED
|
||||
except (ValueError, IOError) as e:
|
||||
raise RuntimeError("Failed to read led status for psu due to {}".format(repr(e)))
|
||||
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
if self.psu_data['led_num'] == 1:
|
||||
return Psu.get_shared_led().get_status()
|
||||
else:
|
||||
return self.led.get_status()
|
||||
|
||||
|
||||
def get_power_available_status(self):
|
||||
@ -312,6 +242,12 @@ class Psu(PsuBase):
|
||||
else:
|
||||
return True, ""
|
||||
|
||||
@classmethod
|
||||
def get_shared_led(cls):
|
||||
if not cls.shared_led:
|
||||
cls.shared_led = SharedLed(PsuLed(None))
|
||||
return cls.shared_led
|
||||
|
||||
def get_temperature(self):
|
||||
"""
|
||||
Retrieves current temperature reading from PSU
|
||||
@ -367,4 +303,3 @@ class Psu(PsuBase):
|
||||
"""
|
||||
# hw-management doesn't expose those sysfs for now
|
||||
raise NotImplementedError
|
||||
|
||||
|
@ -124,7 +124,7 @@ thermal_api_names = [
|
||||
THERMAL_API_GET_HIGH_THRESHOLD
|
||||
]
|
||||
|
||||
hwsku_dict_thermal = {'ACS-MSN2700': 0, 'LS-SN2700':0, 'ACS-MSN2740': 3, 'ACS-MSN2100': 1, 'ACS-MSN2410': 2, 'ACS-MSN2010': 4, 'ACS-MSN3700': 5, 'ACS-MSN3700C': 6, 'Mellanox-SN2700': 0, 'Mellanox-SN2700-D48C8': 0, 'ACS-MSN3800': 7, 'Mellanox-SN3800-D112C8': 7, 'ACS-MSN4700': 8, 'ACS-MSN3420': 9, 'ACS-MSN4600C': 9}
|
||||
hwsku_dict_thermal = {'ACS-MSN2700': 0, 'LS-SN2700':0, 'ACS-MSN2740': 3, 'ACS-MSN2100': 1, 'ACS-MSN2410': 2, 'ACS-MSN2010': 4, 'ACS-MSN3700': 5, 'ACS-MSN3700C': 6, 'Mellanox-SN2700': 0, 'Mellanox-SN2700-D48C8': 0, 'ACS-MSN3800': 7, 'Mellanox-SN3800-D112C8': 7, 'ACS-MSN4700': 8, 'ACS-MSN3420': 9, 'ACS-MSN4600C': 10}
|
||||
thermal_profile_list = [
|
||||
# 2700
|
||||
{
|
||||
@ -267,7 +267,7 @@ thermal_profile_list = [
|
||||
},
|
||||
# 3420
|
||||
{
|
||||
THERMAL_DEV_CATEGORY_CPU_CORE:(0, 4),
|
||||
THERMAL_DEV_CATEGORY_CPU_CORE:(0, 2),
|
||||
THERMAL_DEV_CATEGORY_MODULE:(1, 60),
|
||||
THERMAL_DEV_CATEGORY_PSU:(1, 2),
|
||||
THERMAL_DEV_CATEGORY_CPU_PACK:(0,1),
|
||||
|
@ -2,6 +2,7 @@ class MockFan:
|
||||
speed = 60
|
||||
def __init__(self):
|
||||
self.presence = True
|
||||
self.name = None
|
||||
self.status = True
|
||||
|
||||
def get_presence(self):
|
||||
@ -16,6 +17,9 @@ class MockFan:
|
||||
def get_target_speed(self):
|
||||
return MockFan.speed
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class MockPsu:
|
||||
def __init__(self):
|
||||
|
@ -1,17 +1,57 @@
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
from mock import MagicMock
|
||||
from .mock_platform import MockFan
|
||||
|
||||
test_path = os.path.dirname(os.path.abspath(__file__))
|
||||
modules_path = os.path.dirname(test_path)
|
||||
sys.path.insert(0, modules_path)
|
||||
|
||||
from sonic_platform.fan import Fan
|
||||
from sonic_platform.led import FanLed
|
||||
from sonic_platform.fan_drawer import RealDrawer
|
||||
from sonic_platform.device_data import DEVICE_DATA
|
||||
|
||||
|
||||
def test_get_absence_fan_direction():
|
||||
fan = Fan(True, 0, 0)
|
||||
fan.get_presence = MagicMock(return_value=False)
|
||||
assert fan.fan_dir is not None
|
||||
fan_drawer = RealDrawer(0, DEVICE_DATA['x86_64-mlnx_msn2700-r0']['fans'])
|
||||
fan = Fan(0, fan_drawer)
|
||||
fan_drawer.get_presence = MagicMock(return_value=False)
|
||||
|
||||
assert not fan.is_psu_fan
|
||||
assert fan.get_direction() == Fan.FAN_DIRECTION_NOT_APPLICABLE
|
||||
|
||||
|
||||
def test_fan_drawer_set_status_led():
|
||||
fan_drawer = RealDrawer(0, DEVICE_DATA['x86_64-mlnx_msn2700-r0']['fans'])
|
||||
with pytest.raises(Exception):
|
||||
fan_drawer.set_status_led(None, 'Invalid color')
|
||||
|
||||
with pytest.raises(Exception):
|
||||
fan_drawer.set_status_led(None, Fan.STATUS_LED_COLOR_RED)
|
||||
|
||||
fan1 = Fan(0, fan_drawer)
|
||||
fan2 = Fan(1, fan_drawer)
|
||||
fan_list = fan_drawer.get_all_fans()
|
||||
fan_list.append(fan1)
|
||||
fan_list.append(fan2)
|
||||
|
||||
FanLed.set_status = MagicMock()
|
||||
|
||||
fan1.set_status_led(Fan.STATUS_LED_COLOR_RED)
|
||||
fan_drawer.set_status_led(Fan.STATUS_LED_COLOR_RED)
|
||||
FanLed.set_status.assert_called_with(Fan.STATUS_LED_COLOR_RED)
|
||||
|
||||
fan2.set_status_led(Fan.STATUS_LED_COLOR_GREEN)
|
||||
fan_drawer.set_status_led(Fan.STATUS_LED_COLOR_GREEN)
|
||||
FanLed.set_status.assert_called_with(Fan.STATUS_LED_COLOR_RED)
|
||||
|
||||
fan1.set_status_led(Fan.STATUS_LED_COLOR_GREEN)
|
||||
fan_drawer.set_status_led(Fan.STATUS_LED_COLOR_GREEN)
|
||||
FanLed.set_status.assert_called_with(Fan.STATUS_LED_COLOR_GREEN)
|
||||
|
||||
fan1.set_status_led(Fan.STATUS_LED_COLOR_RED)
|
||||
fan_drawer.set_status_led(Fan.STATUS_LED_COLOR_RED)
|
||||
FanLed.set_status.assert_called_with(Fan.STATUS_LED_COLOR_RED)
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 28c39c55666dcaef10f62492906c1399eec4ccba
|
||||
Subproject commit 75698a8dd8f5a9ea2a0e72c5f7e2b3196d22571a
|
Loading…
Reference in New Issue
Block a user