sonic-buildimage/platform/barefoot/sonic-platform-modules-bfn-montara/sonic_platform/component.py
Andriy Kokhan 9bb0a7f33c
[BFN] Canceling PSU platform API calls on SIGTERM (#10720)
* [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>
2022-09-29 15:18:43 -07:00

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