[platform/device] - Implement Silverstone platform API [Chassis/Fan] (#3706)
Implement part of the Chassis and Fan related APIs. - Chassis APIs get_base_mac() get_serial_number() get_serial_number() get_system_eeprom_info() get_reboot_cause() - Fan APIs get_direction() get_speed() get_target_speed() get_speed_tolerance() set_speed() set_status_led() get_target_speed() - Fan APIs base on Device API get_name() get_presence() get_model() get_serial() get_status() Signed-off-by: Wirut Getbamrung wgetbumr@celestica.com
This commit is contained in:
parent
3b51cec9a3
commit
65fc916dcf
@ -0,0 +1,2 @@
|
|||||||
|
__all__ = ["platform", "chassis"]
|
||||||
|
from sonic_platform import *
|
@ -0,0 +1,114 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Celestica
|
||||||
|
#
|
||||||
|
# Module contains an implementation of SONiC Platform Base API and
|
||||||
|
# provides the Chassis information which are available in the platform
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import json
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.chassis_base import ChassisBase
|
||||||
|
from sonic_platform.eeprom import Tlv
|
||||||
|
from sonic_platform.fan import Fan
|
||||||
|
from helper import APIHelper
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
NUM_FAN_TRAY = 7
|
||||||
|
NUM_FAN = 2
|
||||||
|
NUM_PSU = 2
|
||||||
|
NUM_THERMAL = 5
|
||||||
|
NUM_SFP = 32
|
||||||
|
NUM_COMPONENT = 5
|
||||||
|
|
||||||
|
IPMI_OEM_NETFN = "0x3A"
|
||||||
|
IPMI_GET_REBOOT_CAUSE = "0x03 0x00 0x01 0x06"
|
||||||
|
|
||||||
|
|
||||||
|
class Chassis(ChassisBase):
|
||||||
|
"""Platform-specific Chassis class"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.config_data = {}
|
||||||
|
ChassisBase.__init__(self)
|
||||||
|
self._eeprom = Tlv()
|
||||||
|
self._api_helper = APIHelper()
|
||||||
|
|
||||||
|
for fant_index in range(0, NUM_FAN_TRAY):
|
||||||
|
for fan_index in range(0, NUM_FAN):
|
||||||
|
fan = Fan(fant_index, fan_index)
|
||||||
|
self._fan_list.append(fan)
|
||||||
|
|
||||||
|
def get_base_mac(self):
|
||||||
|
"""
|
||||||
|
Retrieves the base MAC address for the chassis
|
||||||
|
Returns:
|
||||||
|
A string containing the MAC address in the format
|
||||||
|
'XX:XX:XX:XX:XX:XX'
|
||||||
|
"""
|
||||||
|
return self._eeprom.get_mac()
|
||||||
|
|
||||||
|
def get_serial_number(self):
|
||||||
|
"""
|
||||||
|
Retrieves the hardware serial number for the chassis
|
||||||
|
Returns:
|
||||||
|
A string containing the hardware serial number for this chassis.
|
||||||
|
"""
|
||||||
|
return self._eeprom.get_serial()
|
||||||
|
|
||||||
|
def get_system_eeprom_info(self):
|
||||||
|
"""
|
||||||
|
Retrieves the full content of system EEPROM information for the chassis
|
||||||
|
Returns:
|
||||||
|
A dictionary where keys are the type code defined in
|
||||||
|
OCP ONIE TlvInfo EEPROM format and values are their corresponding
|
||||||
|
values.
|
||||||
|
"""
|
||||||
|
return self._eeprom.get_eeprom()
|
||||||
|
|
||||||
|
def get_reboot_cause(self):
|
||||||
|
"""
|
||||||
|
Retrieves the cause of the previous reboot
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A tuple (string, string) where the first element is a string
|
||||||
|
containing the cause of the previous reboot. This string must be
|
||||||
|
one of the predefined strings in this class. If the first string
|
||||||
|
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
|
||||||
|
to pass a description of the reboot cause.
|
||||||
|
"""
|
||||||
|
|
||||||
|
status, raw_cause = self._api_helper.ipmi_raw(
|
||||||
|
IPMI_OEM_NETFN, IPMI_GET_REBOOT_CAUSE)
|
||||||
|
hx_cause = raw_cause.split()[0] if status else 00
|
||||||
|
reboot_cause = {
|
||||||
|
"00": self.REBOOT_CAUSE_HARDWARE_OTHER,
|
||||||
|
"11": self.REBOOT_CAUSE_POWER_LOSS,
|
||||||
|
"22": self.REBOOT_CAUSE_NON_HARDWARE,
|
||||||
|
"33": self.REBOOT_CAUSE_HARDWARE_OTHER,
|
||||||
|
"44": self.REBOOT_CAUSE_NON_HARDWARE,
|
||||||
|
"55": self.REBOOT_CAUSE_NON_HARDWARE,
|
||||||
|
"66": self.REBOOT_CAUSE_WATCHDOG,
|
||||||
|
"77": self.REBOOT_CAUSE_NON_HARDWARE
|
||||||
|
}.get(hx_cause, self.REBOOT_CAUSE_HARDWARE_OTHER)
|
||||||
|
|
||||||
|
description = {
|
||||||
|
"00": "Unknown reason",
|
||||||
|
"11": "The last reset is Power on reset",
|
||||||
|
"22": "The last reset is soft-set CPU warm reset",
|
||||||
|
"33": "The last reset is soft-set CPU cold reset",
|
||||||
|
"44": "The last reset is CPU warm reset",
|
||||||
|
"55": "The last reset is CPU cold reset",
|
||||||
|
"66": "The last reset is watchdog reset",
|
||||||
|
"77": "The last reset is power cycle reset"
|
||||||
|
}.get(hx_cause, "Unknown reason")
|
||||||
|
|
||||||
|
return (reboot_cause, description)
|
@ -0,0 +1,113 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Celestica Silverstone
|
||||||
|
#
|
||||||
|
# Platform and model specific eeprom subclass, inherits from the base class,
|
||||||
|
# and provides the followings:
|
||||||
|
# - the eeprom format definition
|
||||||
|
# - specific encoder/decoder if there is special need
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
try:
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import imp
|
||||||
|
import re
|
||||||
|
from array import array
|
||||||
|
from cStringIO import StringIO
|
||||||
|
from sonic_platform_base.sonic_eeprom import eeprom_dts
|
||||||
|
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
|
||||||
|
except ImportError, e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
CACHE_ROOT = '/var/cache/sonic/decode-syseeprom'
|
||||||
|
CACHE_FILE = 'syseeprom_cache'
|
||||||
|
TLV_EEPROM_I2C_BUS = 0
|
||||||
|
TLV_EEPROM_I2C_ADDR = 56
|
||||||
|
|
||||||
|
class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
|
||||||
|
|
||||||
|
EEPROM_DECODE_HEADLINES = 6
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-00{1}/eeprom".format(TLV_EEPROM_I2C_BUS, TLV_EEPROM_I2C_ADDR)
|
||||||
|
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
|
||||||
|
self._eeprom = self._load_eeprom()
|
||||||
|
|
||||||
|
def __parse_output(self, decode_output):
|
||||||
|
decode_output.replace('\0', '')
|
||||||
|
lines = decode_output.split('\n')
|
||||||
|
lines = lines[self.EEPROM_DECODE_HEADLINES:]
|
||||||
|
_eeprom_info_dict = dict()
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
try:
|
||||||
|
match = re.search(
|
||||||
|
'(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line)
|
||||||
|
if match is not None:
|
||||||
|
idx = match.group(1)
|
||||||
|
value = match.group(3).rstrip('\0')
|
||||||
|
|
||||||
|
_eeprom_info_dict[idx] = value
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return _eeprom_info_dict
|
||||||
|
|
||||||
|
def _load_eeprom(self):
|
||||||
|
original_stdout = sys.stdout
|
||||||
|
sys.stdout = StringIO()
|
||||||
|
try:
|
||||||
|
self.read_eeprom_db()
|
||||||
|
except:
|
||||||
|
decode_output = sys.stdout.getvalue()
|
||||||
|
sys.stdout = original_stdout
|
||||||
|
return self.__parse_output(decode_output)
|
||||||
|
|
||||||
|
status = self.check_status()
|
||||||
|
if 'ok' not in status:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not os.path.exists(CACHE_ROOT):
|
||||||
|
try:
|
||||||
|
os.makedirs(CACHE_ROOT)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
#
|
||||||
|
# only the eeprom classes that inherit from eeprom_base
|
||||||
|
# support caching. Others will work normally
|
||||||
|
#
|
||||||
|
try:
|
||||||
|
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
e = self.read_eeprom()
|
||||||
|
if e is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.update_cache(e)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.decode_eeprom(e)
|
||||||
|
decode_output = sys.stdout.getvalue()
|
||||||
|
sys.stdout = original_stdout
|
||||||
|
|
||||||
|
(is_valid, valid_crc) = self.is_checksum_valid(e)
|
||||||
|
if not is_valid:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return self.__parse_output(decode_output)
|
||||||
|
|
||||||
|
def get_eeprom(self):
|
||||||
|
return self._eeprom
|
||||||
|
|
||||||
|
def get_serial(self):
|
||||||
|
return self._eeprom.get('0x23', "Undefined.")
|
||||||
|
|
||||||
|
def get_mac(self):
|
||||||
|
return self._eeprom.get('0x24', "Undefined.")
|
276
device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py
Normal file
276
device/celestica/x86_64-cel_silverstone-r0/sonic_platform/fan.py
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Celestica
|
||||||
|
#
|
||||||
|
# Module contains an implementation of SONiC Platform Base API and
|
||||||
|
# provides the fan status which are available in the platform
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.fan_base import FanBase
|
||||||
|
from helper import APIHelper
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
|
||||||
|
FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", "FAN-3F", "FAN-3R",
|
||||||
|
"FAN-4F", "FAN-4R", "FAN-5F", "FAN-5R", "FAN-6F", "FAN-6R", "FAN-7F", "FAN-7R"]
|
||||||
|
|
||||||
|
IPMI_OEM_NETFN = "0x3A"
|
||||||
|
IPMI_SENSOR_NETFN = "0x04"
|
||||||
|
IPMI_FAN_SPEED_CMD = "0x2D {}"
|
||||||
|
IPMI_AIR_FLOW_CMD = "0x0A {}"
|
||||||
|
IPMI_FAN_PRESENT_CMD = "0x06 0x03 {}"
|
||||||
|
IPMI_SET_FAN_LED_CMD = "0x07 {} {}"
|
||||||
|
IPMI_GET_FAN_LED_CMD = "0x08 {}"
|
||||||
|
IPMI_SET_PWM = "0x03 0x01 0x02 {} {}"
|
||||||
|
IPMI_FRU_PRINT_ID = "ipmitool fru print {}"
|
||||||
|
IPMI_FRU_MODEL_KEY = "Board Part Number"
|
||||||
|
IPMI_FRU_SERIAL_KEY = "Board Serial"
|
||||||
|
|
||||||
|
MAX_OUTLET = 24700
|
||||||
|
MAX_INLET = 29700
|
||||||
|
SPEED_TOLERANCE = 10
|
||||||
|
|
||||||
|
FAN1_FRONT_SS_ID = "0x0D"
|
||||||
|
FAN1_REAR_SS_ID = "0x45"
|
||||||
|
FAN_LED_OFF_CMD = "0x00"
|
||||||
|
FAN_LED_GREEN_CMD = "0x01"
|
||||||
|
FAN_LED_RED_CMD = "0x02"
|
||||||
|
FAN1_LED_CMD = "0x04"
|
||||||
|
FAN_PWM_REGISTER_START = 0x22
|
||||||
|
FAN_PWM_REGISTER_STEP = 0x10
|
||||||
|
FAN1_FRU_ID = 6
|
||||||
|
|
||||||
|
|
||||||
|
class Fan(FanBase):
|
||||||
|
"""Platform-specific Fan class"""
|
||||||
|
|
||||||
|
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
|
||||||
|
self.fan_index = fan_index
|
||||||
|
self.fan_tray_index = fan_tray_index
|
||||||
|
self.is_psu_fan = is_psu_fan
|
||||||
|
if self.is_psu_fan:
|
||||||
|
self.psu_index = psu_index
|
||||||
|
self._api_helper = APIHelper()
|
||||||
|
self.index = self.fan_tray_index * 2 + self.fan_index
|
||||||
|
|
||||||
|
def get_direction(self):
|
||||||
|
"""
|
||||||
|
Retrieves the direction of fan
|
||||||
|
Returns:
|
||||||
|
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
|
||||||
|
depending on fan direction
|
||||||
|
"""
|
||||||
|
direction = self.FAN_DIRECTION_EXHAUST
|
||||||
|
status, raw_flow = self._api_helper.ipmi_raw(
|
||||||
|
IPMI_OEM_NETFN, IPMI_AIR_FLOW_CMD.format(hex(self.fan_tray_index)))
|
||||||
|
if status and raw_flow == "01":
|
||||||
|
direction = self.FAN_DIRECTION_INTAKE
|
||||||
|
|
||||||
|
return direction
|
||||||
|
|
||||||
|
def get_speed(self):
|
||||||
|
"""
|
||||||
|
Retrieves the speed of fan as a percentage of full speed
|
||||||
|
Returns:
|
||||||
|
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||||
|
to 100 (full speed)
|
||||||
|
|
||||||
|
Note:
|
||||||
|
M = 150
|
||||||
|
Max F2B = 24700 RPM
|
||||||
|
Max B2F = 29700 RPM
|
||||||
|
"""
|
||||||
|
# ipmitool raw 0x3a 0x03 0x01 0x01 {register}
|
||||||
|
# register = 22 32 42 52 62 72 82
|
||||||
|
|
||||||
|
max_rpm = MAX_OUTLET if self.fan_index % 2 == 0 else MAX_INLET
|
||||||
|
fan1_ss_start = FAN1_FRONT_SS_ID if self.fan_index % 2 == 0 else FAN1_REAR_SS_ID
|
||||||
|
|
||||||
|
ss_id = hex(int(fan1_ss_start, 16) + self.fan_tray_index)
|
||||||
|
status, raw_ss_read = self._api_helper.ipmi_raw(
|
||||||
|
IPMI_SENSOR_NETFN, IPMI_FAN_SPEED_CMD.format(ss_id))
|
||||||
|
|
||||||
|
ss_read = raw_ss_read.split()[0]
|
||||||
|
rpm_speed = int(ss_read, 16)*150
|
||||||
|
speed = int(float(rpm_speed)/max_rpm * 100)
|
||||||
|
|
||||||
|
return speed
|
||||||
|
|
||||||
|
def get_target_speed(self):
|
||||||
|
"""
|
||||||
|
Retrieves the target (expected) speed of the fan
|
||||||
|
Returns:
|
||||||
|
An integer, the percentage of full fan speed, in the range 0 (off)
|
||||||
|
to 100 (full speed)
|
||||||
|
|
||||||
|
Note:
|
||||||
|
speed_pc = pwm_target/255*100
|
||||||
|
|
||||||
|
0 : when PWM mode is use
|
||||||
|
pwm : when pwm mode is not use
|
||||||
|
"""
|
||||||
|
target = 0
|
||||||
|
return target
|
||||||
|
|
||||||
|
def get_speed_tolerance(self):
|
||||||
|
"""
|
||||||
|
Retrieves the speed tolerance of the fan
|
||||||
|
Returns:
|
||||||
|
An integer, the percentage of variance from target speed which is
|
||||||
|
considered tolerable
|
||||||
|
"""
|
||||||
|
return SPEED_TOLERANCE
|
||||||
|
|
||||||
|
def set_speed(self, speed):
|
||||||
|
"""
|
||||||
|
Sets the fan speed
|
||||||
|
Args:
|
||||||
|
speed: An integer, the percentage of full fan speed to set fan to,
|
||||||
|
in the range 0 (off) to 100 (full speed)
|
||||||
|
Returns:
|
||||||
|
A boolean, True if speed is set successfully, False if not
|
||||||
|
Notes:
|
||||||
|
pwm setting mode must set as Manual
|
||||||
|
manual: ipmitool raw 0x3a 0x06 0x01 0x0
|
||||||
|
auto: ipmitool raw 0x3a 0x06 0x01 0x1
|
||||||
|
"""
|
||||||
|
# ipmitool raw 0x3a 0x03 0x01 0x02 {register} {pwm_speed}
|
||||||
|
# register = 22 32 42 52 62 72 82
|
||||||
|
|
||||||
|
speed_hex = hex(int(float(speed)/100 * 255))
|
||||||
|
fan_register_hex = hex(FAN_PWM_REGISTER_START +
|
||||||
|
(self.fan_tray_index*FAN_PWM_REGISTER_STEP))
|
||||||
|
|
||||||
|
set_speed_cmd = IPMI_SET_PWM.format(fan_register_hex, speed_hex)
|
||||||
|
status, set_speed_res = self._api_helper.ipmi_raw(
|
||||||
|
IPMI_OEM_NETFN, set_speed_cmd)
|
||||||
|
|
||||||
|
set_speed = False if not status else True
|
||||||
|
|
||||||
|
return set_speed
|
||||||
|
|
||||||
|
def set_status_led(self, color):
|
||||||
|
"""
|
||||||
|
Sets the state of the fan module status LED
|
||||||
|
Args:
|
||||||
|
color: A string representing the color with which to set the
|
||||||
|
fan module status LED
|
||||||
|
Returns:
|
||||||
|
bool: True if status LED state is set successfully, False if not
|
||||||
|
|
||||||
|
Note:
|
||||||
|
LED setting mode must set as Manual
|
||||||
|
manual: ipmitool raw 0x3A 0x09 0x02 0x00
|
||||||
|
auto: ipmitool raw 0x3A 0x09 0x02 0x01
|
||||||
|
"""
|
||||||
|
led_cmd = {
|
||||||
|
self.STATUS_LED_COLOR_GREEN: FAN_LED_GREEN_CMD,
|
||||||
|
self.STATUS_LED_COLOR_RED: FAN_LED_RED_CMD,
|
||||||
|
self.STATUS_LED_COLOR_OFF: FAN_LED_OFF_CMD
|
||||||
|
}.get(color)
|
||||||
|
|
||||||
|
fan_selector = hex(int(FAN1_LED_CMD, 16) + self.fan_tray_index)
|
||||||
|
status, set_led = self._api_helper.ipmi_raw(
|
||||||
|
IPMI_OEM_NETFN, IPMI_SET_FAN_LED_CMD.format(fan_selector, led_cmd))
|
||||||
|
set_status_led = False if not status else True
|
||||||
|
|
||||||
|
return set_status_led
|
||||||
|
|
||||||
|
def get_status_led(self):
|
||||||
|
"""
|
||||||
|
Gets the state of the fan status LED
|
||||||
|
Returns:
|
||||||
|
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
||||||
|
|
||||||
|
Note:
|
||||||
|
STATUS_LED_COLOR_GREEN = "green"
|
||||||
|
STATUS_LED_COLOR_AMBER = "amber"
|
||||||
|
STATUS_LED_COLOR_RED = "red"
|
||||||
|
STATUS_LED_COLOR_OFF = "off"
|
||||||
|
"""
|
||||||
|
fan_selector = hex(int(FAN1_LED_CMD, 16) + self.fan_tray_index)
|
||||||
|
status, hx_color = self._api_helper.ipmi_raw(
|
||||||
|
IPMI_OEM_NETFN, IPMI_GET_FAN_LED_CMD.format(fan_selector))
|
||||||
|
|
||||||
|
status_led = {
|
||||||
|
"00": self.STATUS_LED_COLOR_OFF,
|
||||||
|
"01": self.STATUS_LED_COLOR_GREEN,
|
||||||
|
"02": self.STATUS_LED_COLOR_RED,
|
||||||
|
}.get(hx_color, self.STATUS_LED_COLOR_OFF)
|
||||||
|
|
||||||
|
return status_led
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
"""
|
||||||
|
Retrieves the name of the device
|
||||||
|
Returns:
|
||||||
|
string: The name of the device
|
||||||
|
"""
|
||||||
|
fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] if not self.is_psu_fan else "PSU-{} FAN-{}".format(
|
||||||
|
self.psu_index+1, self.fan_index+1)
|
||||||
|
|
||||||
|
return fan_name
|
||||||
|
|
||||||
|
def get_presence(self):
|
||||||
|
"""
|
||||||
|
Retrieves the presence of the FAN
|
||||||
|
Returns:
|
||||||
|
bool: True if FAN is present, False if not
|
||||||
|
"""
|
||||||
|
presence = False
|
||||||
|
status, raw_present = self._api_helper.ipmi_raw(
|
||||||
|
IPMI_OEM_NETFN, IPMI_FAN_PRESENT_CMD.format(hex(self.index)))
|
||||||
|
if status and raw_present == "00":
|
||||||
|
presence = True
|
||||||
|
|
||||||
|
return presence
|
||||||
|
|
||||||
|
def get_model(self):
|
||||||
|
"""
|
||||||
|
Retrieves the model number (or part number) of the device
|
||||||
|
Returns:
|
||||||
|
string: Model/part number of device
|
||||||
|
"""
|
||||||
|
model = "Unknown"
|
||||||
|
ipmi_fru_idx = self.fan_tray_index + FAN1_FRU_ID
|
||||||
|
status, raw_model = self._api_helper.ipmi_fru_id(
|
||||||
|
ipmi_fru_idx, IPMI_FRU_MODEL_KEY)
|
||||||
|
|
||||||
|
fru_pn_list = raw_model.split()
|
||||||
|
if len(fru_pn_list) > 4:
|
||||||
|
model = fru_pn_list[4]
|
||||||
|
|
||||||
|
return model
|
||||||
|
|
||||||
|
def get_serial(self):
|
||||||
|
"""
|
||||||
|
Retrieves the serial number of the device
|
||||||
|
Returns:
|
||||||
|
string: Serial number of device
|
||||||
|
"""
|
||||||
|
serial = "Unknown"
|
||||||
|
ipmi_fru_idx = self.fan_tray_index + FAN1_FRU_ID
|
||||||
|
status, raw_model = self._api_helper.ipmi_fru_id(
|
||||||
|
ipmi_fru_idx, IPMI_FRU_SERIAL_KEY)
|
||||||
|
|
||||||
|
fru_sr_list = raw_model.split()
|
||||||
|
if len(fru_sr_list) > 3:
|
||||||
|
serial = fru_sr_list[3]
|
||||||
|
|
||||||
|
return serial
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
"""
|
||||||
|
Retrieves the operational status of the device
|
||||||
|
Returns:
|
||||||
|
A boolean value, True if device is operating properly, False if not
|
||||||
|
"""
|
||||||
|
return self.get_presence() and self.get_speed() > 0
|
@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
HOST_CHK_CMD = "docker > /dev/null 2>&1"
|
||||||
|
EMPTY_STRING = ""
|
||||||
|
|
||||||
|
|
||||||
|
class APIHelper():
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def is_host(self):
|
||||||
|
return os.system(HOST_CHK_CMD) == 0
|
||||||
|
|
||||||
|
def read_txt_file(self, file_path):
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r') as fd:
|
||||||
|
data = fd.read()
|
||||||
|
return data.strip()
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
def ipmi_raw(self, netfn, cmd):
|
||||||
|
status = True
|
||||||
|
result = ""
|
||||||
|
try:
|
||||||
|
cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd))
|
||||||
|
p = subprocess.Popen(
|
||||||
|
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
raw_data, err = p.communicate()
|
||||||
|
if err == '':
|
||||||
|
result = raw_data.strip()
|
||||||
|
except:
|
||||||
|
status = False
|
||||||
|
return status, result
|
||||||
|
|
||||||
|
def ipmi_fru_id(self, id, key=None):
|
||||||
|
status = True
|
||||||
|
result = ""
|
||||||
|
try:
|
||||||
|
cmd = "ipmitool fru print {}".format(str(
|
||||||
|
id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key))
|
||||||
|
|
||||||
|
p = subprocess.Popen(
|
||||||
|
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
raw_data, err = p.communicate()
|
||||||
|
if err == '':
|
||||||
|
result = raw_data.strip()
|
||||||
|
except:
|
||||||
|
status = False
|
||||||
|
return status, result
|
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Celestica
|
||||||
|
#
|
||||||
|
# Module contains an implementation of SONiC Platform Base API and
|
||||||
|
# provides the platform information
|
||||||
|
#
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
try:
|
||||||
|
from sonic_platform_base.platform_base import PlatformBase
|
||||||
|
from sonic_platform.chassis import Chassis
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(str(e) + "- required module not found")
|
||||||
|
|
||||||
|
|
||||||
|
class Platform(PlatformBase):
|
||||||
|
"""Platform-specific Platform class"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
PlatformBase.__init__(self)
|
||||||
|
self._chassis = Chassis()
|
@ -29,6 +29,8 @@ start)
|
|||||||
fi
|
fi
|
||||||
decode-syseeprom --init 2> /dev/null &
|
decode-syseeprom --init 2> /dev/null &
|
||||||
|
|
||||||
|
/bin/sh /usr/local/bin/platform_api_mgnt.sh init
|
||||||
|
|
||||||
echo "done."
|
echo "done."
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
silverstone/cfg/silverstone-modules.conf etc/modules-load.d
|
silverstone/cfg/silverstone-modules.conf etc/modules-load.d
|
||||||
silverstone/systemd/platform-modules-silverstone.service lib/systemd/system
|
silverstone/systemd/platform-modules-silverstone.service lib/systemd/system
|
||||||
|
silverstone/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_silverstone-r0
|
||||||
|
services/platform_api/platform_api_mgnt.sh usr/local/bin
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
depmod -a
|
depmod -a
|
||||||
systemctl enable platform-modules-silverstone.service
|
systemctl enable platform-modules-silverstone.service
|
||||||
systemctl start platform-modules-silverstone.service
|
systemctl start platform-modules-silverstone.service
|
||||||
|
|
||||||
|
/usr/local/bin/platform_api_mgnt.sh install
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
DEVICE_NAME = 'celestica'
|
||||||
|
HW_SKU = 'x86_64-cel_silverstone-r0'
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='sonic-platform',
|
||||||
|
version='1.0',
|
||||||
|
description='SONiC platform API implementation on Celestica Platforms',
|
||||||
|
license='Apache 2.0',
|
||||||
|
author='SONiC Team',
|
||||||
|
author_email='linuxnetdev@microsoft.com',
|
||||||
|
url='https://github.com/Azure/sonic-buildimage',
|
||||||
|
maintainer='Wirut Getbamrung',
|
||||||
|
maintainer_email='wgetbumr@celestica.com',
|
||||||
|
packages=[
|
||||||
|
'sonic_platform',
|
||||||
|
],
|
||||||
|
package_dir={
|
||||||
|
'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)},
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 3 - Alpha',
|
||||||
|
'Environment :: Plugins',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'Intended Audience :: Information Technology',
|
||||||
|
'Intended Audience :: System Administrators',
|
||||||
|
'License :: OSI Approved :: Apache Software License',
|
||||||
|
'Natural Language :: English',
|
||||||
|
'Operating System :: POSIX :: Linux',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
|
'Topic :: Utilities',
|
||||||
|
],
|
||||||
|
keywords='sonic SONiC platform PLATFORM',
|
||||||
|
)
|
Reference in New Issue
Block a user