9bb0a7f33c
* [BFN] Canceling PSU platform API calls on SIGTERM Signed-off-by: Andriy Kokhan <andriyx.kokhan@intel.com> * [BFN] Fixed SONiC fwutil exec time (#31) Signed-off-by: Taras Keryk <tarasx.keryk@intel.com> Signed-off-by: Andriy Kokhan <andriyx.kokhan@intel.com> Signed-off-by: Taras Keryk <tarasx.keryk@intel.com> Co-authored-by: Taras Keryk <tarasx.keryk@intel.com>
321 lines
11 KiB
Python
321 lines
11 KiB
Python
try:
|
|
import os
|
|
import subprocess
|
|
from sonic_platform_base.component_base import ComponentBase
|
|
from platform_thrift_client import thrift_try
|
|
import json
|
|
from collections import OrderedDict
|
|
from sonic_py_common import device_info
|
|
from platform_utils import limit_execution_time
|
|
|
|
except ImportError as e:
|
|
raise ImportError(str(e) + "- required module not found")
|
|
|
|
def get_bios_version():
|
|
"""
|
|
Retrieves the firmware version of the BIOS
|
|
Returns:
|
|
A string containing the firmware version of the BIOS
|
|
"""
|
|
try:
|
|
cmd = ['dmidecode', '-s', 'bios-version']
|
|
if os.geteuid() != 0:
|
|
cmd.insert(0, 'sudo')
|
|
return subprocess.check_output(cmd).strip().decode()
|
|
except subprocess.CalledProcessError as e:
|
|
raise RuntimeError("Failed to get BIOS version")
|
|
|
|
@limit_execution_time(1)
|
|
def get_bmc_version():
|
|
"""
|
|
Retrieves the firmware version of the BMC
|
|
Returns:
|
|
A string containing the firmware version of the BMC
|
|
"""
|
|
ver = "N/A"
|
|
def bmc_get(client):
|
|
return client.pltfm_mgr.pltfm_mgr_chss_mgmt_bmc_ver_get()
|
|
try:
|
|
ver = thrift_try(bmc_get)
|
|
except Exception:
|
|
pass
|
|
|
|
return ver
|
|
|
|
class BFPlatformComponentsParser(object):
|
|
"""
|
|
BFPlatformComponentsParser
|
|
"""
|
|
CHASSIS_KEY = "chassis"
|
|
MODULE_KEY = "module"
|
|
COMPONENT_KEY = "component"
|
|
FIRMWARE_KEY = "firmware"
|
|
|
|
def __init__(self, platform_components_path):
|
|
self.__chassis_component_map = OrderedDict()
|
|
self.__component_list = []
|
|
self.__bf_model = ""
|
|
self.__parse_platform_components(platform_components_path)
|
|
|
|
def __is_str(self, obj):
|
|
return isinstance(obj, str)
|
|
|
|
def __is_dict(self, obj):
|
|
return isinstance(obj, dict)
|
|
|
|
def __parser_fail(self, msg):
|
|
raise RuntimeError("Failed to parse \"{}\": {}".format(PLATFORM_COMPONENTS_FILE, msg))
|
|
|
|
def __parser_platform_fail(self, msg):
|
|
self.__parser_fail("invalid platform schema: {}".format(msg))
|
|
|
|
def __parser_chassis_fail(self, msg):
|
|
self.__parser_fail("invalid chassis schema: {}".format(msg))
|
|
|
|
def __parser_component_fail(self, msg):
|
|
self.__parser_fail("invalid component schema: {}".format(msg))
|
|
|
|
def __parse_component_section(self, section, component, is_module_component=False):
|
|
if not self.__is_dict(component):
|
|
self.__parser_component_fail("dictionary is expected: key={}".format(self.COMPONENT_KEY))
|
|
|
|
if not component:
|
|
return
|
|
|
|
missing_key = None
|
|
|
|
for key1, value1 in component.items():
|
|
if not self.__is_dict(value1):
|
|
self.__parser_component_fail("dictionary is expected: key={}".format(key1))
|
|
|
|
self.__chassis_component_map[section][key1] = OrderedDict()
|
|
|
|
if value1:
|
|
if len(value1) < 1 or len(value1) > 3:
|
|
self.__parser_component_fail("unexpected number of records: key={}".format(key1))
|
|
|
|
if self.FIRMWARE_KEY not in value1:
|
|
missing_key = self.FIRMWARE_KEY
|
|
break
|
|
|
|
for key2, value2 in value1.items():
|
|
if not self.__is_str(value2):
|
|
self.__parser_component_fail("string is expected: key={}".format(key2))
|
|
|
|
self.__chassis_component_map[section][key1] = value1
|
|
|
|
if missing_key is not None:
|
|
self.__parser_component_fail("\"{}\" key hasn't been found".format(missing_key))
|
|
|
|
def __parse_chassis_section(self, chassis):
|
|
self.__chassis_component_map = OrderedDict()
|
|
|
|
if not self.__is_dict(chassis):
|
|
self.__parser_chassis_fail("dictionary is expected: key={}".format(self.CHASSIS_KEY))
|
|
|
|
if not chassis:
|
|
self.__parser_chassis_fail("dictionary is empty: key={}".format(self.CHASSIS_KEY))
|
|
|
|
if len(chassis) != 1:
|
|
self.__parser_chassis_fail("unexpected number of records: key={}".format(self.CHASSIS_KEY))
|
|
|
|
for key, value in chassis.items():
|
|
if not self.__is_dict(value):
|
|
self.__parser_chassis_fail("dictionary is expected: key={}".format(key))
|
|
|
|
if not value:
|
|
self.__parser_chassis_fail("dictionary is empty: key={}".format(key))
|
|
|
|
if self.COMPONENT_KEY not in value:
|
|
self.__parser_chassis_fail("\"{}\" key hasn't been found".format(self.COMPONENT_KEY))
|
|
|
|
if len(value) != 1:
|
|
self.__parser_chassis_fail("unexpected number of records: key={}".format(key))
|
|
|
|
self.__chassis_component_map[key] = OrderedDict()
|
|
self.__parse_component_section(key, value[self.COMPONENT_KEY])
|
|
|
|
def get_components_list(self):
|
|
self.__component_list = []
|
|
for key, value in self.__chassis_component_map[self.__bf_model].items():
|
|
self.__component_list.append(key)
|
|
|
|
return self.__component_list
|
|
|
|
def get_chassis_component_map(self):
|
|
return self.__chassis_component_map
|
|
|
|
def __parse_platform_components(self, platform_components_path):
|
|
with open(platform_components_path) as platform_components:
|
|
data = json.load(platform_components)
|
|
kkey, val = list(data[self.CHASSIS_KEY].items())[0]
|
|
self.__bf_model = kkey
|
|
|
|
if not self.__is_dict(data):
|
|
self.__parser_platform_fail("dictionary is expected: key=root")
|
|
|
|
if not data:
|
|
self.__parser_platform_fail("dictionary is empty: key=root")
|
|
|
|
if self.CHASSIS_KEY not in data:
|
|
self.__parser_platform_fail("\"{}\" key hasn't been found".format(self.CHASSIS_KEY))
|
|
|
|
if len(data) != 1:
|
|
self.__parser_platform_fail("unexpected number of records: key=root")
|
|
|
|
self.__parse_chassis_section(data[self.CHASSIS_KEY])
|
|
|
|
chassis_component_map = property(fget=get_chassis_component_map)
|
|
|
|
class Components(ComponentBase):
|
|
"""BFN Montara Platform-specific Component class"""
|
|
bf_platform = device_info.get_path_to_platform_dir()
|
|
bf_platform_json = "{}/platform_components.json".format(bf_platform.strip())
|
|
bpcp = BFPlatformComponentsParser(bf_platform_json)
|
|
|
|
def __init__(self, component_index=0):
|
|
try:
|
|
self.index = component_index
|
|
self.name = "N/A"
|
|
self.version = "N/A"
|
|
self.description = "N/A"
|
|
self.name = self.bpcp.get_components_list()[self.index]
|
|
except IndexError as e:
|
|
print("Error: No components found in plaform_components.json")
|
|
|
|
if (self.name == "BMC"):
|
|
self.version = get_bmc_version()
|
|
self.description = "Chassis BMC"
|
|
elif (self.name == "BIOS"):
|
|
self.version = get_bios_version()
|
|
self.description = "Chassis BIOS"
|
|
|
|
def get_name(self):
|
|
"""
|
|
Retrieves the name of the component
|
|
Returns:
|
|
A string containing the name of the component
|
|
"""
|
|
if not self.name:
|
|
return "N/A"
|
|
return self.name
|
|
|
|
def get_description(self):
|
|
"""
|
|
Retrieves the description of the component
|
|
Returns:
|
|
A string containing the description of the component
|
|
"""
|
|
return self.description
|
|
|
|
def get_firmware_version(self):
|
|
"""
|
|
Retrieves the firmware version of the component
|
|
Returns:
|
|
A string containing the firmware version of the component
|
|
"""
|
|
return self.version
|
|
|
|
def install_firmware(self, image_path):
|
|
"""
|
|
Installs firmware to the component
|
|
Args:
|
|
image_path: A string, path to firmware image
|
|
Returns:
|
|
A boolean, True if install was successful, False if not
|
|
"""
|
|
return False
|
|
|
|
def get_presence(self):
|
|
"""
|
|
Retrieves the presence of the component
|
|
Returns:
|
|
bool: True if component is present, False if not
|
|
"""
|
|
return True
|
|
|
|
def get_model(self):
|
|
"""
|
|
Retrieves the model number (or part number) of the component
|
|
Returns:
|
|
string: Model/part number of component
|
|
"""
|
|
return 'N/A'
|
|
|
|
def get_serial(self):
|
|
"""
|
|
Retrieves the serial number of the component
|
|
Returns:
|
|
string: Serial number of component
|
|
"""
|
|
return 'N/A'
|
|
|
|
def get_status(self):
|
|
"""
|
|
Retrieves the operational status of the component
|
|
Returns:
|
|
A boolean value, True if component is operating properly, False if not
|
|
"""
|
|
return True
|
|
|
|
def get_position_in_parent(self):
|
|
"""
|
|
Retrieves 1-based relative physical position in parent device.
|
|
If the agent cannot determine the parent-relative position
|
|
for some reason, or if the associated value of
|
|
entPhysicalContainedIn is'0', then the value '-1' is returned
|
|
Returns:
|
|
integer: The 1-based relative physical position in parent device
|
|
or -1 if cannot determine the position
|
|
"""
|
|
return -1
|
|
|
|
def is_replaceable(self):
|
|
"""
|
|
Indicate whether this component is replaceable.
|
|
Returns:
|
|
bool: True if it is replaceable.
|
|
"""
|
|
return False
|
|
|
|
def get_available_firmware_version(self, image_path):
|
|
return 'None'
|
|
|
|
def get_firmware_update_notification(self, image_path):
|
|
"""
|
|
Retrieves a notification on what should be done in order to complete
|
|
the component firmware update
|
|
|
|
Args:
|
|
image_path: A string, path to firmware image
|
|
|
|
Returns:
|
|
A string containing the component firmware update notification if required.
|
|
By default 'None' value will be used, which indicates that no actions are required
|
|
"""
|
|
return 'None'
|
|
|
|
def update_firmware(self, image_path):
|
|
"""
|
|
Updates firmware of the component
|
|
|
|
This API performs firmware update: it assumes firmware installation and loading in a single call.
|
|
In case platform component requires some extra steps (apart from calling Low Level Utility)
|
|
to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API
|
|
|
|
Args:
|
|
image_path: A string, path to firmware image
|
|
|
|
Raises:
|
|
RuntimeError: update failed
|
|
"""
|
|
return False
|
|
|
|
def auto_update_firmware(self, image_path, boot_action):
|
|
"""
|
|
Default handling of attempted automatic update for a component
|
|
Will skip the installation if the boot_action is 'warm' or 'fast' and will call update_firmware()
|
|
if boot_action is fast.
|
|
"""
|
|
return 1
|