From e607585b178cc29a38230b95f256c1e94bd77633 Mon Sep 17 00:00:00 2001 From: nancyc12 Date: Mon, 15 Apr 2024 17:57:51 +0800 Subject: [PATCH 01/10] add firmware update support for HPEDevice and introduce FirmwareUpdateError --- .../devices/__init__.py | 54 +- .../fw_devices/HPE/HPE.py | 530 ++++++++++++++++++ .../fw_devices/HPE/test_logger | 15 + .../fw_devices/HPE/test_url | 60 ++ .../fw_devices/HPE/tests/HPE_data.py | 148 +++++ .../HPE/tests/mock_hpe_fwpp-gen10.html | 98 ++++ .../HPE/tests/raw_firmwareinventory | 497 ++++++++++++++++ .../fw_devices/HPE/tests/test_HPE.py | 143 +++++ .../fw_devices/LVFS/LVFS.py | 60 +- .../fw_devices/LVFS/tests/test_LVFS.py | 12 +- .../fw_devices/OEM/OEM.py | 16 - .../fw_devices/__init__.py | 12 +- .../fw_devices/base.py | 59 +- .../fw_devices/dmi.py | 10 +- .../fw_devices/firmware_update.py | 49 +- .../fw_devices/tests/test_firmware_update.py | 38 +- 16 files changed, 1657 insertions(+), 144 deletions(-) create mode 100755 device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py create mode 100755 device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_logger create mode 100755 device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_url create mode 100644 device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/HPE_data.py create mode 100644 device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/mock_hpe_fwpp-gen10.html create mode 100644 device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/raw_firmwareinventory create mode 100644 device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/test_HPE.py delete mode 100644 device-connectors/src/testflinger_device_connectors/fw_devices/OEM/OEM.py diff --git a/device-connectors/src/testflinger_device_connectors/devices/__init__.py b/device-connectors/src/testflinger_device_connectors/devices/__init__.py index 8c145bc8..9fc816c8 100644 --- a/device-connectors/src/testflinger_device_connectors/devices/__init__.py +++ b/device-connectors/src/testflinger_device_connectors/devices/__init__.py @@ -29,6 +29,8 @@ import testflinger_device_connectors from testflinger_device_connectors.fw_devices.firmware_update import ( detect_device, + LVFSDevice, + FirmwareUpdateError, ) logger = logging.getLogger(__name__) @@ -150,32 +152,38 @@ def firmware_update(self, args): device_ip = config["device_ip"] target_device_username = "ubuntu" exitcode = 0 - supported_version = ["latest"] + lvfs_supported_version = ["latest"] - if version not in supported_version: - logger.info( - "Fail to provide version in firmware_update_data. " - + "Current supported version: latest", + try: + target_device = detect_device( + device_ip, target_device_username, config ) - exitcode = 1 - else: - try: - target_device = detect_device( - device_ip, target_device_username + # For LVFS, only update to latest is supported + if ( + isinstance(target_device, LVFSDevice) + and version not in lvfs_supported_version + ): + raise FirmwareUpdateError( + "Fail to provide version in firmware_update_data. " + f"Current supported version: {lvfs_supported_version}" ) - target_device.get_fw_info() - if version == "latest": - reboot_required = target_device.upgrade() - if reboot_required: - target_device.reboot() - update_succeeded = target_device.check_results() - if not update_succeeded: - exitcode = 1 - except Exception as err: - logger.error("Firmware Update failed: ", str(err)) - exitcode = 1 - finally: - logger.info("END firmware_update") + target_device.get_fw_info() + reboot_required = ( + target_device.upgrade() + if version == "latest" + else target_device.downgrade(version) + ) + if reboot_required: + target_device.reboot() + if not target_device.check_results(): + raise FirmwareUpdateError( + "The firmware version did not update successfully" + ) + except Exception as e: + logger.error("Firmware Update failed: ", e.output) + exitcode = 1 + finally: + logger.info("END firmware_update") if ignore_failure: exitcode = 0 return exitcode diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py new file mode 100755 index 00000000..b246c401 --- /dev/null +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py @@ -0,0 +1,530 @@ +"""Device class for flashing firmware on HPE server machines""" + +import subprocess +import json +import os +import logging +import time +import requests +import re +import ipaddress +from testflinger_device_connectors.fw_devices.base import ( + OEMDevice, + FirmwareUpdateError, +) +from typing import Tuple + +logger = logging.getLogger(__name__) + +"""HPE firmware repository and index file""" +HPE_SDR = "https://downloads.linux.hpe.com/SDR/" +HPE_SDR_REPO = f"{HPE_SDR}repo/" +FW_REPOS = { + "rl": "rlcp/firmware/", + "gen10": "fwpp-gen10/", + "gen11": "fwpp-gen11/", +} +INDEX_FILE = "fwrepodata/fwrepo.json" + + +class HPEDevice(OEMDevice): + """Device class for HPE server machines""" + + fw_update_type = "OEM-defined" + vendor = ["HPE"] + reboot_timeout = 1800 + + def __init__( + self, + ipaddr: str, + user: str, + bmc_ip: str, + bmc_user: str, + bmc_password: str, + ): + super().__init__(ipaddr, user) + try: + ipaddress.ip_address(bmc_ip) + except ValueError: + raise FirmwareUpdateError("BMC IP address is not valid") + else: + self.bmc_ip = bmc_ip + self.bmc_user = bmc_user + self.bmc_password = bmc_password + self.fwrepo_index = {} + self._install_ilorest() + self._login_ilo() + + def _install_ilorest(self): + """Install stable/current ilorest deb from HPE SDR""" + install_cmd = [ + f"curl -fsSL {HPE_SDR}hpePublicKey2048_key1.pub" + " | sudo gpg --dearmor | sudo tee" + " /etc/apt/trusted.gpg.d/hpe.gpg > /dev/null", + f"echo '# HPE ilorest\n" + f"deb {HPE_SDR_REPO}ilorest stable/current non-free'" + " > /etc/apt/sources.list.d/ilorest.list", + "apt update", + "apt install -y ilorest", + ] + for cmd in install_cmd: + subprocess.run( + cmd, + shell=True, + capture_output=True, + ) + rc, stdout, stderr = self.run_cmd("--version") + if rc == 0: + logger.info("successfully installed %s", stdout) + else: + raise FirmwareUpdateError("failed to install ilorest") + + def run_cmd( + self, cmds: str, raise_stderr: bool = True, timeout: int = 30 + ) -> Tuple[int, str, str]: + """ + Execute ilorest command + + :param cmds: ilorest commands + :param raise_stderr: when set to `True`, raise RuntimeError if return + code != 0, otherwise ignore it + :param timeout: timeout for the command response + :returns: return code, stdout, stderr + """ + ilorest_prefix = "ilorest --nologo " + if isinstance(cmds, list): + ilorest_cmd = ";".join([ilorest_prefix + cmd for cmd in cmds]) + else: + ilorest_cmd = ilorest_prefix + cmds + r = subprocess.run( + ilorest_cmd, shell=True, capture_output=True, timeout=timeout + ) + rc, stdout, stderr = ( + r.returncode, + r.stdout.decode().strip(), + r.stderr.decode().strip(), + ) + + if raise_stderr and rc != 0: + err_msg = ( + f"failed to execute {ilorest_cmd}:\n[{rc}] {stdout} {stderr}" + ) + raise FirmwareUpdateError(err_msg) + else: + return rc, stdout, stderr + + def _login_ilo(self): + """Log in HPE machine's iLO""" + self.run_cmd( + f"login {self.bmc_ip} -u {self.bmc_user} -p {self.bmc_password}" + ) + + def _logout_ilo(self): + """Log out HPE machine's iLO""" + self.run_cmd("logout") + + def _repo_search(self, device_cls: str, targets: list) -> list: + """ + Search FW file by filename, description, or target IDs + + :param device_cls: device class ID that allowed to be None + :param targets: a list of target ID associate to the FW + :return: a list of FW files with detailed information + """ + fwpkg_data = {} + for spp, json_index in self.fwrepo_index.items(): + temp_fw = {} + for fw_file in json_index: + if any( + t in str(json_index[fw_file]["target"]) for t in targets + ) and ( + json_index[fw_file]["deviceclass"] == device_cls + or device_cls is None + ): + if ( + temp_fw == {} + or temp_fw["version"] < json_index[fw_file]["version"] + ): + temp_fw = {"file": fw_file, **json_index[fw_file]} + if temp_fw: + fwpkg_data[spp] = temp_fw + return dict(sorted(fwpkg_data.items(), reverse=True)) + + def _rawget_firmware_inventory(self): + """Get iLO firmware inventory raw data""" + rc, stdout, stderr = self.run_cmd( + "rawget /redfish/v1/UpdateService/FirmwareInventory/" + " --expand --silent" + ) + return json.loads(stdout)["Members"] + + def _download_fwrepo(self, url): + err_msg = "" + for _ in range(3): + r = requests.get(url) + if r.status_code != 200: + err_msg = ( + f"Failed to download HPE fwrepo {url}: {r.status_code}" + ) + logging.error(err_msg) + else: + return r + if err_msg: + raise FirmwareUpdateError(err_msg) + + def _get_hpe_fw_repo(self): + """ + Get firmware index file (fwrepo.json) according to server model + """ + rc, stdout, stderr = self.run_cmd("systeminfo --system --json") + dev_model = json.loads(stdout)["system"]["Model"] + self.repo_name = [ + FW_REPOS[x] + for x in list(FW_REPOS.keys()) + if x in dev_model.lower() + ][0] + logger.info("HPE server model: %s", self.repo_name) + + self.repo_url = HPE_SDR_REPO + self.repo_name + links, fwrepo_index_init = [], {} + r = self._download_fwrepo(self.repo_url) + links = re.findall( + r"\d{4}\.\d{2}\.\d{1,2}[\._]?[\w\._]*", r.text, re.I + ) + logger.info( + "Available firmware options: %s", + sorted(list(set(links)), reverse=True), + ) + current_url = f"{self.repo_url}current/{INDEX_FILE}" + self.fwrepo_current = self._download_fwrepo(current_url).json() + for spp in sorted(list(set(links)), reverse=True): + fwrepo_index_init[spp] = {} + self.fwrepo_index = fwrepo_index_init + + def get_fw_info(self): + """ + Get current firmware version of all updatable devices on HPE machine, + and get all available repositories from HPE SDR + """ + fw_inventory = self._rawget_firmware_inventory() + server_fw_info = [] + for fw in fw_inventory: + update_order = 4 if fw["Updateable"] else 5 + device_class = target_id = "" + if fw["Oem"]["Hpe"].get("Targets") is not None: + device_class = fw["Oem"]["Hpe"].get("DeviceClass") + target_id = fw["Oem"]["Hpe"]["Targets"] + server_fw_info.append( + dict( + { + "Firmware Name": fw["Name"], + "Firmware Version": fw["Version"], + "Location": fw["Oem"]["Hpe"]["DeviceContext"], + "Fwpkg Available": {}, + "Update Order": update_order, + "Device Class": device_class, + "Target ID": target_id, + } + ) + ) + self.fw_info = server_fw_info + logger.info("firmware on HPE machine:\n%s", self.fw_info) + + self._get_hpe_fw_repo() + + def _purify_ver(self, ver_string: str) -> str: + """ + Extract pure version number and unify the format + + :param ver_string: version from iLO or fwrepo.json + :return: purified numeric version + """ + ver_num = re.sub( + r"\.|\)|\(|\/|-|_", + " ", + re.match(r"([^a-zA-Z]*)", ver_string.split("v")[-1]) + .group(1) + .replace(" ", ""), + ).strip() + return ".".join(map(str, list(map(int, ver_num.split(" "))))) + + def _update_fw_info(self, spp: str): + """ + Get fwrepo.json from HPE SDR and update self.fw_info + + :param spp: HPE SPP released date = repo folder name + """ + fwrepo_url = self.HPE_SDR_REPO + self.repo_name + spp + INDEX_FILE + for retry in range(3): + r = requests.get(fwrepo_url) + if r.status_code != 200: + err_msg = f"Failed to download {fwrepo_url}: {r.status_code}" + logging.error(err_msg) + else: + err_msg = "" + break + if err_msg: + raise FirmwareUpdateError(err_msg) + + self.fwrepo_index[spp] = r.json() + for name in self.fwrepo_index[spp]: + if self.fwrepo_index[spp][name].get("target") and isinstance( + self.fwrepo_index[spp][name]["target"], list + ): + continue + elif name not in self.fwrepo_current: + self.fwrepo_index[spp][name]["target"] = [ + self.fwrepo_index[spp][name]["target"] + ] + # Update "target" referring to current/fwrepodata/fwrepo.json + # This is only needed for legacy fwrepo.json + else: + self.fwrepo_index[spp][name]["target"] = self.fwrepo_current[ + name + ]["target"] + + update_prio = [ + "system rom", + "server platform services", + "innovation engine", + "ilo", + ] + for fw in self.fw_info: + if fw["Target ID"]: + fw["Fwpkg Available"] = self._repo_search( + fw["Device Class"], + fw["Target ID"], + ) + fw["Update Order"] = next( + ( + update_prio.index(x) + for x in update_prio + if x in fw["Name"].lower() + ), + 5, + ) + temp_fw_info = sorted(self.fw_info, key=lambda x: x["Update Order"]) + self.fw_info = temp_fw_info + + def _flash_fwpkg(self, spp: str) -> bool: + """ + Flash FW via ilorest and return `True` if a machine reboot is needed + + :param spp: HPE SPP released date = repo folder name + :return: `True` if reboot is needed, `False` otherwise + """ + if spp not in str(self.fwrepo_index): + logging.error( + "SPP %s is not available in %s%s", + spp, + HPE_SDR_REPO, + self.repo_name, + ) + + raise FirmwareUpdateError( + f"SPP {spp} is not available in HPE FW repository." + ) + + # compare current and target firmware version for each component and + # only do the necessary and valid update + self._update_fw_info(spp) + logger.info("start flashing all firmware with files in SPP %s", spp) + install_list = [] + for fw in self.fw_info: + if fw.get("Fwpkg Available", {}).get(spp): + current_ver = fw["Firmware Version"] + new_ver = fw["Fwpkg Available"][spp]["version"] + min_req_ver = fw["Fwpkg Available"][spp][ + "minimum_active_version" + ] + if self._purify_ver(current_ver) == self._purify_ver(new_ver): + logger.info( + "[%s] no update is needed, already %s", + fw["Firmware Name"], + fw["Firmware Version"], + ) + elif min_req_ver != "null" and self._purify_ver( + current_ver + ) < self._purify_ver(min_req_ver): + logger.error( + "[%s] current firmware %s doesn't meet " + "minimum active version %s", + fw["Firmware Name"], + fw["Firmware Version"], + min_req_ver, + ) + else: + logger.info( + "[%s] update current firmware %s to %s", + fw["Firmware Name"], + fw["Firmware Version"], + fw["Fwpkg Available"][spp]["version"], + ) + install_list.append( + self._download_fwpkg( + spp, fw["Fwpkg Available"][spp]["file"] + ) + ) + fw["targetVersion"] = fw["Fwpkg Available"][spp]["version"] + if install_list == []: + return False + + # check and clear the task queue to prevent blocking firmware flash + logger.info("check and clear iLO taskqueue") + rc, stdout, stderr = self.run_cmd("taskqueue", raise_stderr=False) + if "No tasks found" not in stdout: + self.run_cmd("taskqueue -c") + rc, stdout, stderr = self.run_cmd("taskqueue", raise_stderr=False) + if "No tasks found" not in stdout: + msg = ( + "there's still incomplete task(s) in task queue, " + f"which may impact firmware upgrade actions: {stdout}" + ) + logger.warning(msg) + + # start flashing firmware files in the install list + flash_result = dict() + for file in install_list: + self._login_ilo() + file_name = file.split("/")[-1] + logger.info("start flashing %s", file_name) + rc, stdout, stderr = self.run_cmd( + f"flashfwpkg --forceupload {file}", + raise_stderr=False, + timeout=1200, + ) + result = re.sub(r"Updating: .\r", "", stdout) + flash_result[file_name] = result + logger.info(result) + + # wait for iLO to complete reboot before proceed to next firmware + if "ilo will reboot" in stdout.lower(): + logger.info("wait until iLO complete reboot") + for retry in range(20): + time.sleep(10) + if ( + subprocess.check_output( + f"ping {self.bmc_ip} -c 5 > /dev/null; echo $?", + stderr=subprocess.STDOUT, + shell=True, + ) + .decode() + .strip() + == "0" + ): + break + time.sleep(10) + return True + + def _download_fwpkg(self, spp, fw_file): + """ + Download fwpkg file from HPE repository to local dir /home/HPE_FW + + :param spp: spp release date + :param fw_file: fwpkg file name + :return: full path of downloaded fwpkg file + """ + url = f"{HPE_SDR_REPO}/{self.repo_name}/{spp}/{fw_file}" + FW_DIR = "/home/HPE_FW" + fw_file_path = os.path.join(FW_DIR, fw_file) + if not os.path.isdir(FW_DIR): + os.mkdir(FW_DIR) + if os.path.isfile(fw_file_path): + logger.info("%s is already downloaded", fw_file) + return fw_file_path + logger.info("downloading %s", fw_file) + + html_request = requests.get(url) + if html_request.status_code != 200: + raise FirmwareUpdateError(f"Failed to download {url}") + with open(fw_file_path, "wb") as firmware_file: + firmware_file.write(html_request.content) + return fw_file_path + + def check_results(self) -> bool: + """ + Check if all firmware flash results are listed in iLO IML + + :return: `True` if all firmware flash results are listed, `False` + otherwise + """ + update_result = True + self._login_ilo() + fw_inventory = self._rawget_firmware_inventory() + for fw in self.fw_info: + if "targetVersion" not in fw: + continue + new_fw = next( + ( + new_fw + for new_fw in fw_inventory + if new_fw["Name"] == fw["Firmware Name"] + ), + None, + ) + if new_fw and self._purify_ver( + new_fw["Version"] + ) == self._purify_ver(fw["targetVersion"]): + logger.info( + "[%s] firmware flashed %s → %s", + fw["Firmware Name"], + fw["Firmware Version"], + new_fw["Version"], + ) + else: + logger.error( + "[%s] firmware update failed", fw["Firmware Name"] + ) + update_result = False + self._logout_ilo() + return update_result + + def upgrade(self): + """Upgrade HPE machine firmware with the latest SPP""" + target_spp = list(self.fwrepo_index.keys())[0] + return self._flash_fwpkg(target_spp) + + def downgrade(self, target_spp): + """Downgrade HPE machine firmware with the given (previous) SPP""" + return self._flash_fwpkg(target_spp) + + def reboot(self): + """Reboot HPE machine via iLO""" + logger.info("reboot DUT") + timeout_start = time.time() + # checking if Redfish resource is available after ilo reboot + while time.time() < timeout_start + 60: + self._login_ilo() + rc, stdout, stderr = self.run_cmd("types") + if "ComputerSystem" in stdout: + break + else: + self._logout_ilo() + self.run_cmd("reboot") + self._monitor_poststate("FinishedPost", self.reboot_timeout) + self.check_connectable(self.reboot_timeout) + + def _monitor_poststate(self, state: str, timeout: int): + """ + After HPE machine reboot, monitor the POST state to until the target + state is reached. + + :param state: target POST state + :param timeout: wait time for regaining DUT access + """ + cmd = [ + "select ComputerSystem --refresh", + "get Oem/Hpe/PostState --json", + ] + timeout_start = time.time() + while time.time() < timeout_start + timeout: + rc, stdout, stderr = self.run_cmd(cmd, raise_stderr=False) + if rc == 0 and state in stdout: + delta = time.time() - timeout_start + msg = f"HPE machine reaches {state} after {int(delta)}s" + logger.info(msg) + return + else: + time.sleep(10) + err_msg = f"HPE machine failed to reach {state} after {timeout}s" + raise FirmwareUpdateError(err_msg) diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_logger b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_logger new file mode 100755 index 00000000..a18e0f25 --- /dev/null +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_logger @@ -0,0 +1,15 @@ +import logging + +logger = logging.getLogger() + +fw1, fw2, min_req_ver = "1", "2", "3" + +logger.error( + "[%s] current firmware %s doesn't meet" + "minimum active version %s" + % ( + fw1, + fw2, + min_req_ver, + ) +) diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_url b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_url new file mode 100755 index 00000000..5f7f760f --- /dev/null +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_url @@ -0,0 +1,60 @@ +import requests + +# from bs4 import BeautifulSoup +import re + +# URL of the HTML page +url = "https://downloads.linux.hpe.com/SDR/repo/fwpp-gen10/" # rlcp/firmware/" +INDEX_FILE = "fwrepodata/fwrepo.json" + +r = requests.get(url) +links = re.findall(r"\d{4}\.\d{2}\.\d{1,2}[\._]?[\w\._]*", r.text, re.I) +# print(links) +print(sorted(list(set(links)), reverse=True)) +r = requests.get(f"{url}/current/{INDEX_FILE}") +current_json = r.json() +# print(current_json) +for spp in sorted(list(set(links)), reverse=True): + print(f"processing {spp}...") + r = requests.get(f"{url}{spp}/{INDEX_FILE}") + spp_json = r.json() + for name in spp_json: + # print(spp_json[name]["target"]) + if spp_json[name].get("target") and isinstance( + spp_json[name]["target"], list + ): + # print("no update needed") + continue + elif name not in current_json: + # print(f"{name} not in current") + spp_json[name]["target"] = [spp_json[name]["target"]] + else: + # print("update") + spp_json[name]["target"] = current_json[name]["target"] + + for name in spp_json: + if not isinstance(spp_json[name]["target"], list): + print(name) + +# # Fetch HTML content from the URL +# response = requests.get(url) +# html_content = response.content + +# # Parse the HTML content using BeautifulSoup +# soup = BeautifulSoup(html_content, "html.parser") + +# # Find all 'a' tags within 'pre' tags +# pre_tags = soup.find_all("pre") + +# # Extract folder names with date using regular expressions +# folder_names_with_date = [] +# for pre_tag in pre_tags: +# a_tags = pre_tag.find_all("a", href=True) +# for a_tag in a_tags: +# href = a_tag["href"] +# match = re.search(r"(\d{4}\.\d{2}\.\d{1,2}[\._]?\w*)/", href) +# if match: +# folder_names_with_date.append(match.group(0)) + +# # Print the extracted folder names with date +# print(folder_names_with_date) diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/HPE_data.py b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/HPE_data.py new file mode 100644 index 00000000..9912baa7 --- /dev/null +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/HPE_data.py @@ -0,0 +1,148 @@ +"""This file provides HPE ilorest outputs for unit tests""" + +""" +ilorest rawget /redfish/v1/UpdateService/FirmwareInventory/ --expand --silent +""" +RAWGET_FIRMWARE_INVENTORY = """{ + "@odata.context": "/redfish/v1/$metadata#InventoryCollection", + "@odata.etag": "W9EA3BDF0", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/", + "@odata.type": "#InventoryCollection.InventoryCollection", + "Description": "Firmware Inventory Collection", + "Members": [ + { + "@odata.context": "/redfish/v1/$metadata#Inventory.Inventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/1/", + "@odata.type": "#Inventory.v1_2_0.Inventory", + "Description": "SystemBMC", + "Id": "1", + "Name": "iLO 5", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOInventory", + "@odata.type": "#HpeiLOInventory.v2_1_0.HpeiLOInventory", + "DeviceClass": "2f317b9d-c9e3-4d76-bff6-b9d0d085a952", + "DeviceContext": "System Board", + "Targets": [ + "4764a662-b342-4fc7-9ce9-258c5d99e815", + "c0bcf2b9-1141-49af-aab8-c73791f0349c" + ] + } + }, + "Status": { + "Health": "OK", + "State": "Enabled" + }, + "Updateable": true, + "Version": "2.96 Aug 17 2023" + }, + { + "@odata.context": "/redfish/v1/$metadata#Inventory.Inventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/2/", + "@odata.type": "#Inventory.v1_2_0.Inventory", + "Description": "SystemRomActive", + "Id": "2", + "Name": "System ROM", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOInventory", + "@odata.type": "#HpeiLOInventory.v2_1_0.HpeiLOInventory", + "DeviceClass": "aa148d2e-6e09-453e-bc6f-63baa5f5ccc4", + "DeviceContext": "System Board", + "Targets": [ + "00000000-0000-0000-0000-000000000205", + "00000000-0000-0000-0000-000001553330" + ] + } + }, + "Status": { + "Health": "OK", + "State": "Enabled" + }, + "Updateable": true, + "Version": "U30 v2.90 (07/20/2023)" + }, + { + "@odata.context": "/redfish/v1/$metadata#Inventory.Inventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/3/", + "@odata.type": "#Inventory.v1_2_0.Inventory", + "Description": "PlatformDefinitionTable", + "Id": "3", + "Name": "Intelligent Platform Abstraction Data", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOInventory", + "@odata.type": "#HpeiLOInventory.v2_1_0.HpeiLOInventory", + "DeviceClass": "b8f46d06-85db-465c-94fb-d106e61378ed", + "DeviceContext": "System Board", + "Targets": [ + "00000000-0000-0000-0000-000000000205", + "00000000-0000-0000-0000-000001553330" + ] + } + }, + "Updateable": true, + "Version": "16.5.0 Build 53" + }, + { + "@odata.context": "/redfish/v1/$metadata#Inventory.Inventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/4/", + "@odata.type": "#Inventory.v1_2_0.Inventory", + "Description": "SystemProgrammableLogicDevice", + "Id": "4", + "Name": "System Programmable Logic Device", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOInventory", + "@odata.type": "#HpeiLOInventory.v2_1_0.HpeiLOInventory", + "DeviceClass": "b1ad439a-9dd1-41c1-a496-2da9313f1f07", + "DeviceContext": "System Board", + "Targets": [ + "00000000-0000-0000-0000-000000000205" + ] + } + }, + "Status": { + "Health": "OK", + "State": "Enabled" + }, + "Updateable": true, + "Version": "0x31" + }, + { + "@odata.context": "/redfish/v1/$metadata#Inventory.Inventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/5/", + "@odata.type": "#Inventory.v1_2_0.Inventory", + "Description": "PowerManagementController", + "Id": "5", + "Name": "Power Management Controller Firmware", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOInventory", + "@odata.type": "#HpeiLOInventory.v2_1_0.HpeiLOInventory", + "DeviceClass": "9e48a28a-586c-4519-8405-a04f84e27f0f", + "DeviceContext": "System Board", + "Targets": [ + "00000000-0000-0000-0000-000000000205", + "00000000-0000-0000-0000-000000504d05" + ] + } + }, + "Updateable": true, + "Version": "1.1.0" + } + ], + "Members@odata.count": 24, + "Name": "Firmware Inventory Collection" +} +""" + +"""ilorest systeminfo --system --json""" +SYSTEMINFO_SYSTEM = """{ + "system": { + "Bios Version": "U30 v2.90 (07/20/2023)", + "Model": "HPE ProLiant DL380 Gen10", + "Serial Number": "2M20520660" + } +} +""" diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/mock_hpe_fwpp-gen10.html b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/mock_hpe_fwpp-gen10.html new file mode 100644 index 00000000..65178b02 --- /dev/null +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/mock_hpe_fwpp-gen10.html @@ -0,0 +1,98 @@ + + + + +HPE Software Delivery Repository + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+

Repository Listing

+ + Software Delivery Repository   |   + Getting Started   |   + FAQ  |  + Repositories + +
+
+
Icon  Name                             Last modified      Size  
[PARENTDIR] Parent Directory - +[DIR] 2019.12.0/ 2020-03-11 14:32 - +[DIR] 2019.12.0_hotfix_1/ 2020-03-26 18:24 - +[DIR] 2020.03.0/ 2020-06-23 19:03 - +[DIR] 2020.03.0_hotfix_1/ 2020-11-19 15:07 - +[DIR] 2020.03.2/ 2020-06-23 19:03 - +[DIR] 2020.09.0/ 2020-10-19 15:58 - +[DIR] 2020.09.0_hotfix_1/ 2021-03-30 14:33 - +[DIR] 2021.04.0/ 2021-04-19 18:02 - +[DIR] 2021.10.0/ 2021-11-01 14:33 - +[DIR] 2022.03.0/ 2022-04-06 16:43 - +[DIR] 2022.03.0_supspp_rhel9.0_x86_64/ 2022-06-29 15:07 - +[DIR] 2022.03.1/ 2022-09-23 16:02 - +[DIR] 2022.09.1/ 2022-10-05 15:04 - +[DIR] 2023.03.00.00/ 2023-04-06 16:12 - +[DIR] 2023.09.00.00/ 2023-09-13 16:55 - +[DIR] 2023.09.00.01/ 2023-11-08 14:24 - +[DIR] 2023.09.00.02/ 2023-12-19 09:35 - +[DIR] 2023.09.00.03/ 2023-12-26 03:53 - +[DIR] 2023.09.00.04/ 2024-02-06 07:24 - +[   ] GPG-KEY-FirmwarePackforProLiant 2020-01-06 20:52 1.0K +[DIR] RedHat/ 2023-12-26 05:25 - +[DIR] SuSE/ 2020-01-06 20:46 - +[DIR] current/ 2024-03-28 06:23 - +[DIR] next/ 2024-02-06 07:37 - +
+ + +
+ +
+
+ + diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/raw_firmwareinventory b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/raw_firmwareinventory new file mode 100644 index 00000000..fa3209d0 --- /dev/null +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/raw_firmwareinventory @@ -0,0 +1,497 @@ +{ + "@odata.context": "/redfish/v1/$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection", + "@odata.etag": 'W/"9EA3BDF0"', + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/", + "@odata.type": "#SoftwareInventoryCollection.SoftwareInventoryCollection", + "Description": "Firmware Inventory Collection", + "Members": [ + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/1/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "SystemBMC", + "Id": "1", + "Name": "iLO 5", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "2f317b9d-c9e3-4d76-bff6-b9d0d085a952", + "DeviceContext": "System Board", + "Targets": [ + "4764a662-b342-4fc7-9ce9-258c5d99e815", + "c0bcf2b9-1141-49af-aab8-c73791f0349c", + ], + } + }, + "Status": {"Health": "OK", "State": "Enabled"}, + "Updateable": true, + "Version": "2.96 Aug 17 2023", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/2/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "SystemRomActive", + "Id": "2", + "Name": "System ROM", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "aa148d2e-6e09-453e-bc6f-63baa5f5ccc4", + "DeviceContext": "System Board", + "Targets": [ + "00000000-0000-0000-0000-000000000205", + "00000000-0000-0000-0000-000001553330", + ], + } + }, + "Status": {"Health": "OK", "State": "Enabled"}, + "Updateable": true, + "Version": "U30 v2.90 (07/20/2023)", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/3/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "PlatformDefinitionTable", + "Id": "3", + "Name": "Intelligent Platform Abstraction Data", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "b8f46d06-85db-465c-94fb-d106e61378ed", + "DeviceContext": "System Board", + "Targets": [ + "00000000-0000-0000-0000-000000000205", + "00000000-0000-0000-0000-000001553330", + ], + } + }, + "Updateable": true, + "Version": "16.5.0 Build 53", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/4/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "SystemProgrammableLogicDevice", + "Id": "4", + "Name": "System Programmable Logic Device", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "b1ad439a-9dd1-41c1-a496-2da9313f1f07", + "DeviceContext": "System Board", + "Targets": ["00000000-0000-0000-0000-000000000205"], + } + }, + "Status": {"Health": "OK", "State": "Enabled"}, + "Updateable": true, + "Version": "0x31", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/5/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "PowerManagementController", + "Id": "5", + "Name": "Power Management Controller Firmware", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "9e48a28a-586c-4519-8405-a04f84e27f0f", + "DeviceContext": "System Board", + "Targets": [ + "00000000-0000-0000-0000-000000000205", + "00000000-0000-0000-0000-000000504d05", + ], + } + }, + "Updateable": true, + "Version": "1.1.0", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/6/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "NVMeBackplane", + "Id": "6", + "Name": "NVMe Backplane Firmware", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "3653aa90-7089-453a-899c-792827a50d67", + "DeviceContext": "System Board", + "Targets": [ + "00000000-0000-0000-0000-000000000205", + "00000000-0000-0000-0000-000049535320", + ], + } + }, + "Updateable": true, + "Version": "1.24", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/7/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "PowerSupplies", + "Id": "7", + "Name": "Power Supply Firmware", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "6bb86077-0275-4614-aae1-86618e8b1c27", + "DeviceContext": "Bay 1", + "Targets": ["0302b505-0002-0000-0000-0cf38db966ea"], + } + }, + "Updateable": true, + "Version": "2.00", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/8/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "PowerSupplies", + "Id": "8", + "Name": "Power Supply Firmware", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "6bb86077-0275-4614-aae1-86618e8b1c27", + "DeviceContext": "Bay 2", + "Targets": ["0302b505-0002-0000-0000-0cf38db966ea"], + } + }, + "Updateable": true, + "Version": "2.00", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/9/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "InnovationEngineFirmware", + "Id": "9", + "Name": "Innovation Engine (IE) Firmware", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "c734e171-8721-48c9-9ed6-d5bc7da5ef8d", + "DeviceContext": "System Board", + "Targets": [ + "00000000-0000-0000-0000-000000000205", + "a6b1a447-382a-5a4f-3c10-3c100a000303", + ], + } + }, + "Status": {"Health": "OK", "State": "Enabled"}, + "Updateable": true, + "Version": "0.2.3.0", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/10/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "SPSFirmwareVersionData", + "Id": "10", + "Name": "Server Platform Services (SPS) Firmware", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "b34e5677-21dc-45d3-872b-42f76fee9053", + "DeviceContext": "System Board", + "Targets": [ + "00000000-0000-0000-0000-000000000205", + "a6b1a447-382a-5a4f-3c10-86800a000101", + ], + } + }, + "Status": {"Health": "OK", "State": "Enabled"}, + "Updateable": true, + "Version": "4.1.5.2", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/11/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "SPSFirmwareDescriptor", + "Id": "11", + "Name": "Server Platform Services (SPS) Descriptor", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "3f30a329-d03c-46b8-8f0e-9567fad4ea9f", + "DeviceContext": "System Board", + "Targets": ["00000000-0000-0000-0000-000000000205"], + } + }, + "Updateable": true, + "Version": "1.2 0", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/12/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "SystemRomBackup", + "Id": "12", + "Name": "Redundant System ROM", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": null, + "DeviceContext": "System Board", + } + }, + "Updateable": true, + "Version": "U30 v2.76 (02/09/2023)", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/13/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "Intelligent Provisioning", + "Id": "13", + "Name": "Intelligent Provisioning", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "ac963eeb-ed78-4f36-c18c-29d85f34a0ac", + "DeviceContext": "System Board", + } + }, + "Updateable": true, + "Version": "3.50.100", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/14/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "PowerManagementControllerBootloader", + "Id": "14", + "Name": "Power Management Controller FW Bootloader", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": null, + "DeviceContext": "System Board", + } + }, + "Updateable": true, + "Version": "1.1", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/15/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "15b31015159000d3", + "Id": "15", + "Name": "HPE Eth 10/25Gb 2p 640FLR-SFP28 Adptr", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": null, + "DeviceContext": "Embedded ALOM", + "DeviceInstance": "PciRoot(0x3)/Pci(0x2,0x0)/Pci(0x0,0x0)", + "Targets": ["a6b1a447-382a-5a4f-15b3-1015159000d3"], + } + }, + "Updateable": false, + "Version": "14.32.1010", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/16/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "9005028f103c0654", + "Id": "16", + "Name": "HPE Smart Array E208i-a SR Gen10", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": null, + "DeviceContext": "Embedded RAID", + "DeviceInstance": "PciRoot(0x3)/Pci(0x0,0x0)/Pci(0x0,0x0)", + "Targets": ["a6b1a447-382a-5a4f-9005-028f103c0654"], + } + }, + "Updateable": true, + "Version": "6.22", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/17/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "10de1eb810de12a2", + "Id": "17", + "Name": "NVIDIA Tesla T4", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": null, + "DeviceContext": "PCI-E Slot 2", + "DeviceInstance": "PciRoot(0x2)/Pci(0x0,0x0)/Pci(0x0,0x0)", + "Targets": ["a6b1a447-382a-5a4f-10de-1eb810de12a2"], + } + }, + "Updateable": false, + "Version": "90.04.96.00.01", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/18/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "10de1eb810de12a2", + "Id": "18", + "Name": "NVIDIA Tesla T4", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": null, + "DeviceContext": "PCI-E Slot 3", + "DeviceInstance": "PciRoot(0x1)/Pci(0x0,0x0)/Pci(0x0,0x0)", + "Targets": ["a6b1a447-382a-5a4f-10de-1eb810de12a2"], + } + }, + "Updateable": false, + "Version": "90.04.96.00.01", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/19/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "10de1eb810de12a2", + "Id": "19", + "Name": "NVIDIA Tesla T4", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": null, + "DeviceContext": "PCI-E Slot 5", + "DeviceInstance": "PciRoot(0x7)/Pci(0x0,0x0)/Pci(0x0,0x0)", + "Targets": ["a6b1a447-382a-5a4f-10de-1eb810de12a2"], + } + }, + "Updateable": false, + "Version": "90.04.96.00.01", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/20/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "10de1eb810de12a2", + "Id": "20", + "Name": "NVIDIA Tesla T4", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": null, + "DeviceContext": "PCI-E Slot 6", + "DeviceInstance": "PciRoot(0x8)/Pci(0x0,0x0)/Pci(0x0,0x0)", + "Targets": ["a6b1a447-382a-5a4f-10de-1eb810de12a2"], + } + }, + "Updateable": false, + "Version": "90.04.96.00.01", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/21/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "102b0538159000e4", + "Id": "21", + "Name": "Embedded Video Controller", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": null, + "DeviceContext": "Embedded Device", + "DeviceInstance": "PciRoot(0x0)/Pci(0x1C,0x4)/Pci(0x0,0x1)", + "Targets": ["a6b1a447-382a-5a4f-102b-0538159000e4"], + } + }, + "Updateable": false, + "Version": "2.5", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/22/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "Samsung SSD 983 DCT 960GB", + "Id": "22", + "Name": "NVMe Drive", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "f6de0320-2e0f-489a-b238-6dd8ae7c3811", + "DeviceContext": "NVMe Drive Port 5B Box 1 Bay 1", + "Targets": ["532340a5-6d61-7573-6e67-20532a9e3acf"], + } + }, + "Updateable": false, + "Version": "EDA5302Q", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/23/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "Samsung SSD 983 DCT 960GB", + "Id": "23", + "Name": "NVMe Drive", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "f6de0320-2e0f-489a-b238-6dd8ae7c3811", + "DeviceContext": "NVMe Drive Port 5B Box 1 Bay 2", + "Targets": ["532340a5-6d61-7573-6e67-20532a9e3acf"], + } + }, + "Updateable": false, + "Version": "EDA5302Q", + }, + { + "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", + "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/24/", + "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", + "Description": "Universal Backplane Manager", + "Id": "24", + "Name": "HPE 2SFF NVMe/SAS/uFF Backplane", + "Oem": { + "Hpe": { + "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", + "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", + "DeviceClass": "4149ebb7-d64b-4654-b679-4280f349ea50", + "DeviceContext": "Box=1", + "Targets": ["9675b54e-1c96-44c3-a7a1-901500000000"], + } + }, + "Updateable": true, + "Version": "1.24", + }, + ], + "Members@odata.count": 24, + "Name": "Firmware Inventory Collection", +} diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/test_HPE.py b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/test_HPE.py new file mode 100644 index 00000000..29adb919 --- /dev/null +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/test_HPE.py @@ -0,0 +1,143 @@ +"""Test HPEDevice""" + +import unittest +import json +import os +from unittest.mock import patch, Mock +from testflinger_device_connectors.fw_devices import ( + HPEDevice, + FirmwareUpdateError, +) +from testflinger_device_connectors.fw_devices.HPE.tests import HPE_data + +get_fw_cmd = "rawget /redfish/v1/UpdateService/FirmwareInventory/" + +get_sysinfo_cmd = "systeminfo --system --json" + + +class TestHPEDevice(unittest.TestCase): + def test_init_invalid_bmc_ip(self): + """ + Test if FirmwareUpdateError raises given a invalid BMC IP address + """ + with self.assertRaises(FirmwareUpdateError): + HPEDevice("", "", "300.0.0.0", "", "") + + def test_init_null_bmc_ip(self): + """ + Test if FirmwareUpdateError raises given a null BMC IP address + """ + with self.assertRaises(FirmwareUpdateError): + HPEDevice("", "", "", "", "") + + def test_purify_ver(self): + """Test if _purify_ver is functional""" + + with patch( + "testflinger_device_connectors.fw_devices.HPEDevice." + "_install_ilorest" + ) as mock1, patch( + "testflinger_device_connectors.fw_devices.HPEDevice._login_ilo" + ) as mock2: + mock1.return_value = None + mock2.return_value = None + device = HPEDevice("", "", "127.0.0.1", "", "") + self.assertEqual( + device._purify_ver("U30 v2.76 (02/09/2023)"), + device._purify_ver("2.76_02-09-2023"), + ) + self.assertEqual( + device._purify_ver("4.1.4.901"), + device._purify_ver("04.01.04.901"), + ) + self.assertEqual( + device._purify_ver("2.96 Aug 17 2023"), + device._purify_ver("2.96"), + ) + self.assertNotEqual( + device._purify_ver("U30 v2.76 (02/09/2023)"), + device._purify_ver("2.76_02-90-2023"), + ) + self.assertNotEqual( + device._purify_ver("4.1.4.901"), + device._purify_ver("04.010.04.901"), + ) + self.assertEqual( + device._purify_ver("08.65.08"), + device._purify_ver("8.65.08"), + ) + + def mock_run_cmd(*args, **kwargs): + """ + Mock run_cmd for ilorest calls + """ + if get_fw_cmd in args[1]: + return 0, HPE_data.RAWGET_FIRMWARE_INVENTORY, "" + elif args[1] == get_sysinfo_cmd: + return 0, HPE_data.SYSTEMINFO_SYSTEM, "" + else: + return 0, "", "" + + def test_get_fw_info(self): + """ + Test if all raw FirmwareInventory data transferred to HPEDevice.fw_info + """ + with patch( + "testflinger_device_connectors.fw_devices.HPEDevice." + "_install_ilorest" + ) as mock1, patch( + "testflinger_device_connectors.fw_devices.HPEDevice._login_ilo" + ) as mock2: + mock1.return_value = None + mock2.return_value = None + device = HPEDevice("", "", "127.0.0.1", "", "") + with patch( + "testflinger_device_connectors.fw_devices.HPEDevice.run_cmd" + ) as mock1: + mock1.side_effect = self.mock_run_cmd + device.get_fw_info() + + for member in json.loads(HPE_data.RAWGET_FIRMWARE_INVENTORY)[ + "Members" + ]: + self.assertTrue( + any(member["Name"] in fw.values() for fw in device.fw_info) + ) + + def mock_download_fwrepo(*args, **kwargs): + with open( + os.path.join( + os.path.dirname(__file__), "mock_hpe_fwpp-gen10.html" + ), + "r", + ) as file: + fwrepo = file.read() + mock_response = Mock() + mock_response.text = fwrepo + return mock_response + + def test_flash_fwpkg(self): + """ + Test if FirmwareUpdateError is raised given a non-supported SPP version + """ + with patch( + "testflinger_device_connectors.fw_devices.HPEDevice." + "_install_ilorest" + ) as mock1, patch( + "testflinger_device_connectors.fw_devices.HPEDevice._login_ilo" + ) as mock2: + mock1.return_value = None + mock2.return_value = None + device = HPEDevice("", "", "127.0.0.1", "", "") + + with patch( + "testflinger_device_connectors.fw_devices.HPEDevice.run_cmd" + ) as mock1, patch( + "testflinger_device_connectors.fw_devices.HPEDevice." + "_download_fwrepo" + ) as mock2: + mock1.side_effect = self.mock_run_cmd + mock2.side_effect = self.mock_download_fwrepo + device._get_hpe_fw_repo() + with self.assertRaises(FirmwareUpdateError): + device._flash_fwpkg("2023.09.10.04") diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/LVFS.py b/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/LVFS.py index 2d2ddd1e..5638f44d 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/LVFS.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/LVFS.py @@ -5,13 +5,15 @@ import time import logging from typing import Tuple -from testflinger_device_connectors.fw_devices.base import AbstractDevice -from enum import Enum, auto - -logger = logging.getLogger() +from testflinger_device_connectors.fw_devices.base import ( + AbstractDevice, + SSH_OPTS, + FirmwareUpdateError, +) +from enum import Enum, auto -SSH_OPTS = "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" +logger = logging.getLogger(__name__) class LVFSDevice(AbstractDevice): @@ -33,13 +35,7 @@ def run_cmd( :param timeout: timeout for the command response :returns: return code, stdout, stderr """ - if self.password == "": - ssh_cmd = f'ssh -t {SSH_OPTS} {self.user}@{self.ipaddr} "{cmd}"' - else: - ssh_cmd = ( - f"sshpass -p {self.password} ssh -t {SSH_OPTS} " - + f' {self.user}@{self.ipaddr} "{cmd}"' - ) + ssh_cmd = f'ssh -t {SSH_OPTS} {self.user}@{self.ipaddr} "{cmd}"' try: r = subprocess.run( ssh_cmd, @@ -49,7 +45,7 @@ def run_cmd( ) except subprocess.TimeoutExpired as e: if raise_stderr: - raise e + raise FirmwareUpdateError(e.output) else: return 124, f"command timeout after {timeout}s", "" rc, stdout, stderr = ( @@ -59,7 +55,7 @@ def run_cmd( ) if raise_stderr and rc != 0: err_msg = f"Failed to execute {cmd}:\n [{rc}] {stdout} {stderr}" - raise RuntimeError(err_msg) + raise FirmwareUpdateError(err_msg) return rc, stdout, stderr def get_fw_info(self): @@ -200,7 +196,7 @@ def downgrade(self) -> bool: raise_stderr=False, ) if not (rc == 0 or (rc == 1 and "already exists" in stderr)): - raise RuntimeError( + raise FirmwareUpdateError( f"[{dev_name}] fail to download firmware file from" f" LVFS target: {prev_ver['Uri']}\nerror: {stdout}" ) @@ -282,40 +278,6 @@ def check_results(self) -> bool: return fwupd_result - def check_connectable(self, timeout: int): - """ - After DUT reboot, check if SSH to DUT works within a given timeout - period - - :param timeout: wait time for regaining DUT access - """ - logger.info( - "check and wait for %ss until %s is SSHable", timeout, self.ipaddr - ) - status = "1" - timeout_start = time.time() - - while status != "0" and time.time() < timeout_start + timeout: - try: - status = subprocess.check_output( - f"ssh {SSH_OPTS} {self.user}@{self.ipaddr} " - + "/bin/true 2>/dev/null; echo $?", - shell=True, - universal_newlines=True, - timeout=10, - ).strip() - except ( - subprocess.TimeoutExpired, - subprocess.CalledProcessError, - ): - pass - if status != "0": - err_msg = f"Failed to SSH to {self.ipaddr} after {timeout}s" - logger.error(err_msg) - raise RuntimeError(err_msg) - delta = time.time() - timeout_start - logger.info("%s is SSHable after %ds", self.ipaddr, int(delta)) - def reboot(self): """Reboot the DUT from OS""" logger.info("reboot DUT") diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/tests/test_LVFS.py b/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/tests/test_LVFS.py index f340d1c5..54927289 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/tests/test_LVFS.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/tests/test_LVFS.py @@ -29,7 +29,7 @@ def test_upgradable(self): "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" ) as mock_path: mock_path.side_effect = self.mock_run_cmd - device = LVFSDevice("", "", "") + device = LVFSDevice("", "") device._parse_fwupd_raw(fwupd_data.GET_DEVICES_RESPONSE_DATA) self.assertTrue(device.upgrade()) self.assertFalse(device.downgrade()) @@ -44,7 +44,7 @@ def test_downgradable(self): "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" ) as mock_path: mock_path.side_effect = self.mock_run_cmd - device = LVFSDevice("", "", "") + device = LVFSDevice("", "") device_info = json.loads(fwupd_data.GET_DEVICES_RESPONSE_DATA) device_info["Devices"][5]["Version"] = "2.91" @@ -63,7 +63,7 @@ def test_check_results_failed_state(self): "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" ) as mock_path: mock_path.side_effect = self.mock_run_cmd - device = LVFSDevice("", "", "") + device = LVFSDevice("", "") device._parse_fwupd_raw(fwupd_data.GET_DEVICES_RESPONSE_DATA) device.fw_info[2]["targetVersion"] = "2.90" device_results = json.loads(fwupd_data.GET_RESULTS_RESPONSE_DATA) @@ -77,7 +77,7 @@ def test_check_results_mismatched_version(self): "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" ) as mock_path: mock_path.side_effect = self.mock_run_cmd - device = LVFSDevice("", "", "") + device = LVFSDevice("", "") device._parse_fwupd_raw(fwupd_data.GET_DEVICES_RESPONSE_DATA) device.fw_info[2]["targetVersion"] = "2.91" self.assertFalse(device.check_results()) @@ -89,7 +89,7 @@ def test_check_results_good(self): "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" ) as mock_path: mock_path.side_effect = self.mock_run_cmd - device = LVFSDevice("", "", "") + device = LVFSDevice("", "") device._parse_fwupd_raw(fwupd_data.GET_DEVICES_RESPONSE_DATA) device_results = json.loads(fwupd_data.GET_RESULTS_RESPONSE_DATA) device_results["UpdateState"] = ( @@ -109,7 +109,7 @@ def test_check_results_error(self): "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" ) as mock_path: mock_path.side_effect = self.mock_run_cmd - device = LVFSDevice("", "", "") + device = LVFSDevice("", "") device._parse_fwupd_raw(fwupd_data.GET_DEVICES_RESPONSE_DATA) device.fw_info[2]["targetVersion"] = "2.90" device_results = json.loads( diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/OEM/OEM.py b/device-connectors/src/testflinger_device_connectors/fw_devices/OEM/OEM.py deleted file mode 100644 index 08ce144b..00000000 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/OEM/OEM.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Device classes for flashing firmware on device with OEM-specific methods""" - -from testflinger_device_connectors.fw_devices.base import AbstractDevice - - -class OEMDevice(AbstractDevice): - """Device class for devices that are not supported by LVFS-fwupd""" - - fw_update_type = "OEM-defined" - - -class HPEDevice(OEMDevice): - """Place-holder for device class for HPE server""" - - fw_update_type = "OEM-defined" - vendor = "HPE" diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/__init__.py b/device-connectors/src/testflinger_device_connectors/fw_devices/__init__.py index b36b1e23..a4cf4f37 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/__init__.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/__init__.py @@ -1,12 +1,13 @@ -from testflinger_device_connectors.fw_devices.base import AbstractDevice +from testflinger_device_connectors.fw_devices.base import ( + FirmwareUpdateError, + AbstractDevice, + OEMDevice, +) from testflinger_device_connectors.fw_devices.LVFS.LVFS import ( LVFSDevice, FwupdUpdateState, ) -from testflinger_device_connectors.fw_devices.OEM.OEM import ( - OEMDevice, - HPEDevice, -) +from testflinger_device_connectors.fw_devices.HPE.HPE import HPEDevice __all__ = [ "AbstractDevice", @@ -14,4 +15,5 @@ "OEMDevice", "HPEDevice", "FwupdUpdateState", + "FirmwareUpdateError", ] diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/base.py b/device-connectors/src/testflinger_device_connectors/fw_devices/base.py index 95f5a786..7e676083 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/base.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/base.py @@ -1,16 +1,25 @@ """Base class for flashing firmware on devices""" +import time +import subprocess +import logging from abc import ABC, abstractmethod +logger = logging.getLogger(__name__) +SSH_OPTS = "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" + + +class FirmwareUpdateError(Exception): + pass + class AbstractDevice(ABC): fw_update_type = "" vendor = "" - def __init__(self, ipaddr: str, user: str, password: str): + def __init__(self, ipaddr: str, user: str): self.ipaddr = ipaddr self.user = user - self.password = password self.fw_info = [] @abstractmethod @@ -33,12 +42,46 @@ def downgrade(self): def check_results(self): raise NotImplementedError("Please, implement the check_results method") - @abstractmethod - def check_connectable(self): - raise NotImplementedError( - "Please, implement the check_connectable method" - ) - @abstractmethod def reboot(self): raise NotImplementedError("Please, implement the reboot method") + + def check_connectable(self, timeout: int): + """ + After DUT reboot, check if SSH to DUT works within a given timeout + period + + :param timeout: wait time for regaining DUT access + """ + logger.info( + "check and wait for %ds until %s is SSHable", timeout, self.ipaddr + ) + status = "1" + timeout_start = time.time() + + while status != "0" and time.time() < timeout_start + timeout: + try: + status = subprocess.check_output( + f"ssh {SSH_OPTS} {self.user}@{self.ipaddr} " + + "/bin/true 2>/dev/null; echo $?", + shell=True, + universal_newlines=True, + timeout=10, + ).strip() + except ( + subprocess.TimeoutExpired, + subprocess.CalledProcessError, + ): + pass + if status != "0": + err_msg = f"Failed to SSH to {self.ipaddr} after {timeout}s" + logger.error(err_msg) + raise FirmwareUpdateError(err_msg) + delta = time.time() - timeout_start + logger.info("%s is SSHable after %ss", self.ipaddr, int(delta)) + + +class OEMDevice(AbstractDevice): + """Device class for devices that are not supported by LVFS-fwupd""" + + fw_update_type = "OEM-defined" diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/dmi.py b/device-connectors/src/testflinger_device_connectors/fw_devices/dmi.py index d82b5880..af3dab90 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/dmi.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/dmi.py @@ -4,13 +4,13 @@ class Dmi: chassis = ( ("Undefined", "unknown"), # 0x00 - ("Other", "unknown"), # 0x01 + ("Other", "unknown"), ("Unknown", "unknown"), ("Desktop", "LVFS"), # 0x03 ("Low Profile Desktop", "unknown"), ("Pizza Box", "unknown"), ("Mini Tower", "unknown"), - ("Tower", "unknown"), + ("Tower", "OEM-defined"), ("Portable", "unknown"), ("Laptop", "unknown"), # 0x09 ("Notebook", "unknown"), # 0x0A @@ -20,7 +20,7 @@ class Dmi: ("Sub Notebook", "unknown"), ("Space-saving", "unknown"), ("Lunch Box", "unknown"), - ("Main Server Chassis", "unknown"), # 0x11 + ("Main Server Chassis", "OEM-defined"), # 0x11 ("Expansion Chassis", "unknown"), ("Sub Chassis", "unknown"), ("Bus Expansion Chassis", "unknown"), @@ -28,10 +28,10 @@ class Dmi: ("RAID Chassis", "unknown"), ("Rack Mount Chassis", "OEM-defined,LVFS"), # 0x17 ("Sealed-case PC", "unknown"), - ("Multi-system", "unknown"), + ("Multi-system", "OEM-defined"), ("CompactPCI", "unknonw"), ("AdvancedTCA", "unknown"), - ("Blade", "server"), + ("Blade", "OEM-defined"), ("Blade Enclosure", "unknown"), ("Tablet", "unknown"), ("Convertible", "unknown"), # 0x1F diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/firmware_update.py b/device-connectors/src/testflinger_device_connectors/fw_devices/firmware_update.py index 5bbdb9df..4687c942 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/firmware_update.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/firmware_update.py @@ -2,15 +2,16 @@ import subprocess import logging +import json from testflinger_device_connectors.fw_devices.dmi import Dmi from testflinger_device_connectors.fw_devices import ( AbstractDevice, LVFSDevice, OEMDevice, + FirmwareUpdateError, ) -logger = logging.getLogger() - +logger = logging.getLogger(__name__) SSH_OPTS = "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" @@ -21,19 +22,16 @@ def all_subclasses(cls): ] -def detect_device( - ip: str, user: str, password: str = "", **options -) -> AbstractDevice: +def detect_device(ip: str, user: str, config: dict) -> AbstractDevice: """ Detect device's firmware upgrade type by checking on DMI data :param ip: DUT IP :param user: DUT user - :param password: DUT password (default=blank) :return: device class object :rtype: an instance of a class that implements AbstractDevice """ - temp_device = LVFSDevice(ip, user, password) + temp_device = LVFSDevice(ip, user) run_ssh = temp_device.run_cmd devices = all_subclasses(AbstractDevice) @@ -48,7 +46,7 @@ def detect_device( ) except subprocess.CalledProcessError as err: logger.error(err.output) - raise RuntimeError(err.output) + raise FirmwareUpdateError(err.output) err_msg = "" if rc1 != 0: @@ -61,7 +59,7 @@ def detect_device( + err_msg ) logger.error(err_msg) - raise RuntimeError(err_msg) + raise FirmwareUpdateError(err_msg) type_index = int(type_string) upgrade_type = Dmi.chassis_types[type_index] @@ -81,10 +79,35 @@ def detect_device( logger.info("%s is a %s %s", ip, vendor_string, dev.__name__) except IndexError: logger.error(err_msg) - raise RuntimeError(err_msg) + raise FirmwareUpdateError(err_msg) if issubclass(dev, LVFSDevice): - return dev(ip, user, password) + return dev(ip, user) elif issubclass(dev, OEMDevice): - logger.info(err_msg) - raise RuntimeError(err_msg) + # get BMC info from MAAS + try: + cmd = [ + f"maas {config['maas_user']} " + f"node power-parameters {config['node_id']}" + ] + out = subprocess.check_output( + cmd, + shell=True, + universal_newlines=True, + ).strip() + bmc_info = json.loads(out) + return dev( + ip, + user, + bmc_info["power_address"], + bmc_info["power_user"], + bmc_info["power_pass"], + ) + except KeyError: + raise FirmwareUpdateError( + "MAAS info isn't provided in config file" + ) + except subprocess.CalledProcessError: + err_msg = f"maas error running: {' '.join(cmd)}" + logger.error(err_msg) + raise FirmwareUpdateError(err_msg) diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/tests/test_firmware_update.py b/device-connectors/src/testflinger_device_connectors/fw_devices/tests/test_firmware_update.py index bf224458..27d6a024 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/tests/test_firmware_update.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/tests/test_firmware_update.py @@ -3,7 +3,10 @@ import unittest import pytest from unittest.mock import patch -from testflinger_device_connectors.fw_devices import LVFSDevice +from testflinger_device_connectors.fw_devices import ( + LVFSDevice, + FirmwareUpdateError, +) from testflinger_device_connectors.fw_devices.firmware_update import ( detect_device, ) @@ -82,46 +85,43 @@ def test_detect_device_supported(self): def test_detect_device_unsupported(self): """Test if detects_device exits while given a unsupported device""" - with pytest.raises(RuntimeError) as pytest_wrapped_e: + with pytest.raises(FirmwareUpdateError) as pytest_wrapped_e: with patch( "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" ) as mock_path: mock_path.side_effect = self.mock_run_cmd_unsupported detect_device("", "", "") - self.assertEqual(pytest_wrapped_e.type, RuntimeError) - self.assertIn( - "is not in current support scope", - str(pytest_wrapped_e.value), - ) + self.assertIn( + "is not in current support scope", + str(pytest_wrapped_e.value), + ) def test_detect_device_fail(self): """ Test if detects_device exits while given a device without dmi data """ - with pytest.raises(RuntimeError) as pytest_wrapped_e: + with pytest.raises(FirmwareUpdateError) as pytest_wrapped_e: with patch( "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" ) as mock_path: mock_path.side_effect = self.mock_run_cmd_fail detect_device("", "", "") - self.assertEqual(pytest_wrapped_e.type, RuntimeError) - self.assertIn( - "Unable to detect device vendor/type due to lacking of dmi info", - str(pytest_wrapped_e.value), - ) + self.assertIn( + "Unable to detect device vendor/type due to lacking of dmi", + str(pytest_wrapped_e.value), + ) def test_detect_device_nossh(self): """ Test if detects_device exits while given an unreachable device """ - with pytest.raises(RuntimeError) as pytest_wrapped_e: + with pytest.raises(FirmwareUpdateError) as pytest_wrapped_e: with patch( "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" ) as mock_path: mock_path.side_effect = self.mock_run_cmd_nossh detect_device("", "", "") - self.assertEqual(pytest_wrapped_e.type, RuntimeError) - self.assertIn( - "Unable to detect device vendor/type due to lacking of dmi info", - str(pytest_wrapped_e.value), - ) + self.assertIn( + "Unable to detect device vendor/type due to lacking of dmi", + str(pytest_wrapped_e.value), + ) From 0e4f0264718a70addcf45a11dde13f63ae32d169 Mon Sep 17 00:00:00 2001 From: nancyc12 Date: Tue, 16 Apr 2024 15:35:39 +0800 Subject: [PATCH 02/10] runtime bugs fixing --- .../devices/__init__.py | 2 +- .../fw_devices/HPE/HPE.py | 49 ++++++++++--------- .../fw_devices/HPE/tests/test_HPE.py | 38 +++++--------- .../fw_devices/LVFS/tests/test_LVFS.py | 25 +++------- .../fw_devices/base.py | 5 ++ .../fw_devices/firmware_update.py | 1 + .../fw_devices/tests/test_firmware_update.py | 38 +++++++------- 7 files changed, 73 insertions(+), 85 deletions(-) diff --git a/device-connectors/src/testflinger_device_connectors/devices/__init__.py b/device-connectors/src/testflinger_device_connectors/devices/__init__.py index 9fc816c8..0a159aa0 100644 --- a/device-connectors/src/testflinger_device_connectors/devices/__init__.py +++ b/device-connectors/src/testflinger_device_connectors/devices/__init__.py @@ -180,7 +180,7 @@ def firmware_update(self, args): "The firmware version did not update successfully" ) except Exception as e: - logger.error("Firmware Update failed: ", e.output) + logger.error("Firmware Update failed: ", str(e)) exitcode = 1 finally: logger.info("END firmware_update") diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py index b246c401..b770221e 100755 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py @@ -24,7 +24,7 @@ "gen10": "fwpp-gen10/", "gen11": "fwpp-gen11/", } -INDEX_FILE = "fwrepodata/fwrepo.json" +INDEX_FILE = "/fwrepodata/fwrepo.json" class HPEDevice(OEMDevice): @@ -57,6 +57,10 @@ def __init__( def _install_ilorest(self): """Install stable/current ilorest deb from HPE SDR""" + rc, stdout, stderr = self.run_cmd("--version", raise_stderr=False) + if rc == 0: + logger.info("successfully installed %s", stdout) + return install_cmd = [ f"curl -fsSL {HPE_SDR}hpePublicKey2048_key1.pub" " | sudo gpg --dearmor | sudo tee" @@ -73,7 +77,7 @@ def _install_ilorest(self): shell=True, capture_output=True, ) - rc, stdout, stderr = self.run_cmd("--version") + rc, stdout, stderr = self.run_cmd("--version", raise_stderr=False) if rc == 0: logger.info("successfully installed %s", stdout) else: @@ -135,6 +139,8 @@ def _repo_search(self, device_cls: str, targets: list) -> list: for spp, json_index in self.fwrepo_index.items(): temp_fw = {} for fw_file in json_index: + if ".fwpkg" not in fw_file: + continue if any( t in str(json_index[fw_file]["target"]) for t in targets ) and ( @@ -158,14 +164,12 @@ def _rawget_firmware_inventory(self): ) return json.loads(stdout)["Members"] - def _download_fwrepo(self, url): + def _download_file(self, url): err_msg = "" for _ in range(3): r = requests.get(url) if r.status_code != 200: - err_msg = ( - f"Failed to download HPE fwrepo {url}: {r.status_code}" - ) + err_msg = f"Failed to download {url}: {r.status_code}" logging.error(err_msg) else: return r @@ -183,11 +187,13 @@ def _get_hpe_fw_repo(self): for x in list(FW_REPOS.keys()) if x in dev_model.lower() ][0] - logger.info("HPE server model: %s", self.repo_name) + logger.info( + "HPE firmware repository: %s%s", HPE_SDR_REPO, self.repo_name + ) self.repo_url = HPE_SDR_REPO + self.repo_name links, fwrepo_index_init = [], {} - r = self._download_fwrepo(self.repo_url) + r = self._download_file(self.repo_url) links = re.findall( r"\d{4}\.\d{2}\.\d{1,2}[\._]?[\w\._]*", r.text, re.I ) @@ -195,8 +201,8 @@ def _get_hpe_fw_repo(self): "Available firmware options: %s", sorted(list(set(links)), reverse=True), ) - current_url = f"{self.repo_url}current/{INDEX_FILE}" - self.fwrepo_current = self._download_fwrepo(current_url).json() + current_url = f"{self.repo_url}current{INDEX_FILE}" + self.fwrepo_current = self._download_file(current_url).json() for spp in sorted(list(set(links)), reverse=True): fwrepo_index_init[spp] = {} self.fwrepo_index = fwrepo_index_init @@ -228,8 +234,6 @@ def get_fw_info(self): ) ) self.fw_info = server_fw_info - logger.info("firmware on HPE machine:\n%s", self.fw_info) - self._get_hpe_fw_repo() def _purify_ver(self, ver_string: str) -> str: @@ -254,7 +258,7 @@ def _update_fw_info(self, spp: str): :param spp: HPE SPP released date = repo folder name """ - fwrepo_url = self.HPE_SDR_REPO + self.repo_name + spp + INDEX_FILE + fwrepo_url = f"{HPE_SDR_REPO}{self.repo_name}{spp}{INDEX_FILE}" for retry in range(3): r = requests.get(fwrepo_url) if r.status_code != 200: @@ -299,12 +303,13 @@ def _update_fw_info(self, spp: str): ( update_prio.index(x) for x in update_prio - if x in fw["Name"].lower() + if x in fw["Firmware Name"].lower() ), 5, ) temp_fw_info = sorted(self.fw_info, key=lambda x: x["Update Order"]) self.fw_info = temp_fw_info + logger.info("firmware updatable on HPE machine:\n%s", self.fw_info) def _flash_fwpkg(self, spp: str) -> bool: """ @@ -327,8 +332,8 @@ def _flash_fwpkg(self, spp: str) -> bool: # compare current and target firmware version for each component and # only do the necessary and valid update - self._update_fw_info(spp) logger.info("start flashing all firmware with files in SPP %s", spp) + self._update_fw_info(spp) install_list = [] for fw in self.fw_info: if fw.get("Fwpkg Available", {}).get(spp): @@ -424,7 +429,7 @@ def _download_fwpkg(self, spp, fw_file): :param fw_file: fwpkg file name :return: full path of downloaded fwpkg file """ - url = f"{HPE_SDR_REPO}/{self.repo_name}/{spp}/{fw_file}" + url = f"{HPE_SDR_REPO}{self.repo_name}{spp}/{fw_file}" FW_DIR = "/home/HPE_FW" fw_file_path = os.path.join(FW_DIR, fw_file) if not os.path.isdir(FW_DIR): @@ -432,13 +437,10 @@ def _download_fwpkg(self, spp, fw_file): if os.path.isfile(fw_file_path): logger.info("%s is already downloaded", fw_file) return fw_file_path - logger.info("downloading %s", fw_file) - - html_request = requests.get(url) - if html_request.status_code != 200: - raise FirmwareUpdateError(f"Failed to download {url}") + logger.info("downloading %s", url) + r = self._download_file(url) with open(fw_file_path, "wb") as firmware_file: - firmware_file.write(html_request.content) + firmware_file.write(r.content) return fw_file_path def check_results(self) -> bool: @@ -491,9 +493,10 @@ def downgrade(self, target_spp): def reboot(self): """Reboot HPE machine via iLO""" logger.info("reboot DUT") + ilo_reboot_timeout = 300 timeout_start = time.time() # checking if Redfish resource is available after ilo reboot - while time.time() < timeout_start + 60: + while time.time() < timeout_start + ilo_reboot_timeout: self._login_ilo() rc, stdout, stderr = self.run_cmd("types") if "ComputerSystem" in stdout: diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/test_HPE.py b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/test_HPE.py index 29adb919..f8de7d9d 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/test_HPE.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/test_HPE.py @@ -10,8 +10,8 @@ ) from testflinger_device_connectors.fw_devices.HPE.tests import HPE_data +HPEDevice_path = "testflinger_device_connectors.fw_devices.HPEDevice" get_fw_cmd = "rawget /redfish/v1/UpdateService/FirmwareInventory/" - get_sysinfo_cmd = "systeminfo --system --json" @@ -33,11 +33,8 @@ def test_init_null_bmc_ip(self): def test_purify_ver(self): """Test if _purify_ver is functional""" - with patch( - "testflinger_device_connectors.fw_devices.HPEDevice." - "_install_ilorest" - ) as mock1, patch( - "testflinger_device_connectors.fw_devices.HPEDevice._login_ilo" + with patch(f"{HPEDevice_path}._install_ilorest") as mock1, patch( + f"{HPEDevice_path}._login_ilo" ) as mock2: mock1.return_value = None mock2.return_value = None @@ -82,18 +79,13 @@ def test_get_fw_info(self): """ Test if all raw FirmwareInventory data transferred to HPEDevice.fw_info """ - with patch( - "testflinger_device_connectors.fw_devices.HPEDevice." - "_install_ilorest" - ) as mock1, patch( - "testflinger_device_connectors.fw_devices.HPEDevice._login_ilo" + with patch(f"{HPEDevice_path}._install_ilorest") as mock1, patch( + f"{HPEDevice_path}._login_ilo" ) as mock2: mock1.return_value = None mock2.return_value = None device = HPEDevice("", "", "127.0.0.1", "", "") - with patch( - "testflinger_device_connectors.fw_devices.HPEDevice.run_cmd" - ) as mock1: + with patch(f"{HPEDevice_path}.run_cmd") as mock1: mock1.side_effect = self.mock_run_cmd device.get_fw_info() @@ -104,7 +96,7 @@ def test_get_fw_info(self): any(member["Name"] in fw.values() for fw in device.fw_info) ) - def mock_download_fwrepo(*args, **kwargs): + def mock_download_file(*args, **kwargs): with open( os.path.join( os.path.dirname(__file__), "mock_hpe_fwpp-gen10.html" @@ -120,24 +112,18 @@ def test_flash_fwpkg(self): """ Test if FirmwareUpdateError is raised given a non-supported SPP version """ - with patch( - "testflinger_device_connectors.fw_devices.HPEDevice." - "_install_ilorest" - ) as mock1, patch( - "testflinger_device_connectors.fw_devices.HPEDevice._login_ilo" + with patch(f"{HPEDevice_path}._install_ilorest") as mock1, patch( + f"{HPEDevice_path}._login_ilo" ) as mock2: mock1.return_value = None mock2.return_value = None device = HPEDevice("", "", "127.0.0.1", "", "") - with patch( - "testflinger_device_connectors.fw_devices.HPEDevice.run_cmd" - ) as mock1, patch( - "testflinger_device_connectors.fw_devices.HPEDevice." - "_download_fwrepo" + with patch(f"{HPEDevice_path}.run_cmd") as mock1, patch( + f"{HPEDevice_path}._download_file" ) as mock2: mock1.side_effect = self.mock_run_cmd - mock2.side_effect = self.mock_download_fwrepo + mock2.side_effect = self.mock_download_file device._get_hpe_fw_repo() with self.assertRaises(FirmwareUpdateError): device._flash_fwpkg("2023.09.10.04") diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/tests/test_LVFS.py b/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/tests/test_LVFS.py index 54927289..2a1dffb6 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/tests/test_LVFS.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/LVFS/tests/test_LVFS.py @@ -9,6 +9,7 @@ ) from testflinger_device_connectors.fw_devices.LVFS.tests import fwupd_data +LVFSDevice_path = "testflinger_device_connectors.fw_devices.LVFSDevice" device_results = json.loads(fwupd_data.GET_RESULTS_RESPONSE_DATA) @@ -25,9 +26,7 @@ def test_upgradable(self): Test if upgrade function returns True. And test if downgrade function returns False. """ - with patch( - "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" - ) as mock_path: + with patch(f"{LVFSDevice_path}.run_cmd") as mock_path: mock_path.side_effect = self.mock_run_cmd device = LVFSDevice("", "") device._parse_fwupd_raw(fwupd_data.GET_DEVICES_RESPONSE_DATA) @@ -40,9 +39,7 @@ def test_downgradable(self): Test if upgrade function returns False. And test if downgrade function returns True. """ - with patch( - "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" - ) as mock_path: + with patch(f"{LVFSDevice_path}.run_cmd") as mock_path: mock_path.side_effect = self.mock_run_cmd device = LVFSDevice("", "") @@ -59,9 +56,7 @@ def test_downgradable(self): def test_check_results_failed_state(self): """Validate UpdateState check in check_results""" global device_results - with patch( - "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" - ) as mock_path: + with patch(f"{LVFSDevice_path}.run_cmd") as mock_path: mock_path.side_effect = self.mock_run_cmd device = LVFSDevice("", "") device._parse_fwupd_raw(fwupd_data.GET_DEVICES_RESPONSE_DATA) @@ -73,9 +68,7 @@ def test_check_results_failed_state(self): def test_check_results_mismatched_version(self): """Validate version check in check_results""" global device_results - with patch( - "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" - ) as mock_path: + with patch(f"{LVFSDevice_path}.run_cmd") as mock_path: mock_path.side_effect = self.mock_run_cmd device = LVFSDevice("", "") device._parse_fwupd_raw(fwupd_data.GET_DEVICES_RESPONSE_DATA) @@ -85,9 +78,7 @@ def test_check_results_mismatched_version(self): def test_check_results_good(self): """Test if check_results works with a valid case""" global device_results - with patch( - "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" - ) as mock_path: + with patch(f"{LVFSDevice_path}.run_cmd") as mock_path: mock_path.side_effect = self.mock_run_cmd device = LVFSDevice("", "") device._parse_fwupd_raw(fwupd_data.GET_DEVICES_RESPONSE_DATA) @@ -105,9 +96,7 @@ def test_check_results_error(self): get-results``` """ global device_results - with patch( - "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" - ) as mock_path: + with patch(f"{LVFSDevice_path}.run_cmd") as mock_path: mock_path.side_effect = self.mock_run_cmd device = LVFSDevice("", "") device._parse_fwupd_raw(fwupd_data.GET_DEVICES_RESPONSE_DATA) diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/base.py b/device-connectors/src/testflinger_device_connectors/fw_devices/base.py index 7e676083..52a65d4f 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/base.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/base.py @@ -61,6 +61,11 @@ def check_connectable(self, timeout: int): while status != "0" and time.time() < timeout_start + timeout: try: + subprocess.run( + f"ping {self.ipaddr} -c 5", + stdout=subprocess.DEVNULL, + shell=True, + ) status = subprocess.check_output( f"ssh {SSH_OPTS} {self.user}@{self.ipaddr} " + "/bin/true 2>/dev/null; echo $?", diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/firmware_update.py b/device-connectors/src/testflinger_device_connectors/fw_devices/firmware_update.py index 4687c942..137976e4 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/firmware_update.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/firmware_update.py @@ -36,6 +36,7 @@ def detect_device(ip: str, user: str, config: dict) -> AbstractDevice: devices = all_subclasses(AbstractDevice) try: + temp_device.check_connectable(60) dmi_chassis_vendor = "sudo cat /sys/class/dmi/id/chassis_vendor" dmi_chassis_type = "sudo cat /sys/class/dmi/id/chassis_type" rc1, vendor_string, stderr1 = run_ssh( diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/tests/test_firmware_update.py b/device-connectors/src/testflinger_device_connectors/fw_devices/tests/test_firmware_update.py index 27d6a024..c5faf888 100644 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/tests/test_firmware_update.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/tests/test_firmware_update.py @@ -11,7 +11,7 @@ detect_device, ) - +LVFSDevice_path = "testflinger_device_connectors.fw_devices.LVFSDevice" vendor_cmd = "sudo cat /sys/class/dmi/id/chassis_vendor" type_cmd = "sudo cat /sys/class/dmi/id/chassis_type" @@ -76,20 +76,22 @@ def mock_run_cmd_nossh(*args, **kwargs): def test_detect_device_supported(self): """Test if detects_device returns a correct device class""" - with patch( - "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" - ) as mock_path: - mock_path.side_effect = self.mock_run_cmd_supported + with patch(f"{LVFSDevice_path}.run_cmd") as mock1, patch( + f"{LVFSDevice_path}.check_connectable" + ) as mock2: + mock1.side_effect = self.mock_run_cmd_supported + mock2.return_value = None device = detect_device("", "", "") self.assertTrue(isinstance(device, LVFSDevice)) def test_detect_device_unsupported(self): """Test if detects_device exits while given a unsupported device""" with pytest.raises(FirmwareUpdateError) as pytest_wrapped_e: - with patch( - "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" - ) as mock_path: - mock_path.side_effect = self.mock_run_cmd_unsupported + with patch(f"{LVFSDevice_path}.run_cmd") as mock1, patch( + f"{LVFSDevice_path}.check_connectable" + ) as mock2: + mock1.side_effect = self.mock_run_cmd_unsupported + mock2.return_value = None detect_device("", "", "") self.assertIn( "is not in current support scope", @@ -101,10 +103,11 @@ def test_detect_device_fail(self): Test if detects_device exits while given a device without dmi data """ with pytest.raises(FirmwareUpdateError) as pytest_wrapped_e: - with patch( - "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" - ) as mock_path: - mock_path.side_effect = self.mock_run_cmd_fail + with patch(f"{LVFSDevice_path}.run_cmd") as mock1, patch( + f"{LVFSDevice_path}.check_connectable" + ) as mock2: + mock1.side_effect = self.mock_run_cmd_fail + mock2.return_value = None detect_device("", "", "") self.assertIn( "Unable to detect device vendor/type due to lacking of dmi", @@ -116,10 +119,11 @@ def test_detect_device_nossh(self): Test if detects_device exits while given an unreachable device """ with pytest.raises(FirmwareUpdateError) as pytest_wrapped_e: - with patch( - "testflinger_device_connectors.fw_devices.LVFSDevice.run_cmd" - ) as mock_path: - mock_path.side_effect = self.mock_run_cmd_nossh + with patch(f"{LVFSDevice_path}.run_cmd") as mock1, patch( + f"{LVFSDevice_path}.check_connectable" + ) as mock2: + mock1.side_effect = self.mock_run_cmd_nossh + mock2.return_value = None detect_device("", "", "") self.assertIn( "Unable to detect device vendor/type due to lacking of dmi", From bc68088673118be82bf4800d63cc9833bb97937d Mon Sep 17 00:00:00 2001 From: nancyc12 Date: Tue, 16 Apr 2024 17:35:02 +0800 Subject: [PATCH 03/10] add error handling for reboot and _download_file --- .../fw_devices/HPE/HPE.py | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py index b770221e..08af3962 100755 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py @@ -165,16 +165,18 @@ def _rawget_firmware_inventory(self): return json.loads(stdout)["Members"] def _download_file(self, url): - err_msg = "" + err_msg = f"Failed to download {url}" for _ in range(3): - r = requests.get(url) + try: + r = requests.get(url) + except requests.exceptions.ConnectionError as e: + logging.error(e.output) + continue if r.status_code != 200: - err_msg = f"Failed to download {url}: {r.status_code}" logging.error(err_msg) else: return r - if err_msg: - raise FirmwareUpdateError(err_msg) + raise FirmwareUpdateError(err_msg) def _get_hpe_fw_repo(self): """ @@ -492,17 +494,19 @@ def downgrade(self, target_spp): def reboot(self): """Reboot HPE machine via iLO""" - logger.info("reboot DUT") ilo_reboot_timeout = 300 timeout_start = time.time() # checking if Redfish resource is available after ilo reboot + logger.info("check iLO access") while time.time() < timeout_start + ilo_reboot_timeout: self._login_ilo() rc, stdout, stderr = self.run_cmd("types") if "ComputerSystem" in stdout: + logger.info("iLO connection checked") break else: self._logout_ilo() + logger.info("reboot DUT") self.run_cmd("reboot") self._monitor_poststate("FinishedPost", self.reboot_timeout) self.check_connectable(self.reboot_timeout) @@ -521,13 +525,19 @@ def _monitor_poststate(self, state: str, timeout: int): ] timeout_start = time.time() while time.time() < timeout_start + timeout: - rc, stdout, stderr = self.run_cmd(cmd, raise_stderr=False) - if rc == 0 and state in stdout: - delta = time.time() - timeout_start - msg = f"HPE machine reaches {state} after {int(delta)}s" - logger.info(msg) - return + try: + rc, stdout, stderr = self.run_cmd( + cmd, raise_stderr=False, timeout=10 + ) + except subprocess.TimeoutExpired: + continue else: + if rc == 0 and state in stdout: + delta = time.time() - timeout_start + msg = f"HPE machine reaches {state} after {int(delta)}s" + logger.info(msg) + return + finally: time.sleep(10) err_msg = f"HPE machine failed to reach {state} after {timeout}s" raise FirmwareUpdateError(err_msg) From a202a80d87fe1962144b9705a04fb2127c5f011e Mon Sep 17 00:00:00 2001 From: nancyc12 Date: Tue, 16 Apr 2024 17:48:31 +0800 Subject: [PATCH 04/10] remove unused files --- .../fw_devices/HPE/test_logger | 15 ----- .../fw_devices/HPE/test_url | 60 ------------------- 2 files changed, 75 deletions(-) delete mode 100755 device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_logger delete mode 100755 device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_url diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_logger b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_logger deleted file mode 100755 index a18e0f25..00000000 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_logger +++ /dev/null @@ -1,15 +0,0 @@ -import logging - -logger = logging.getLogger() - -fw1, fw2, min_req_ver = "1", "2", "3" - -logger.error( - "[%s] current firmware %s doesn't meet" - "minimum active version %s" - % ( - fw1, - fw2, - min_req_ver, - ) -) diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_url b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_url deleted file mode 100755 index 5f7f760f..00000000 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/test_url +++ /dev/null @@ -1,60 +0,0 @@ -import requests - -# from bs4 import BeautifulSoup -import re - -# URL of the HTML page -url = "https://downloads.linux.hpe.com/SDR/repo/fwpp-gen10/" # rlcp/firmware/" -INDEX_FILE = "fwrepodata/fwrepo.json" - -r = requests.get(url) -links = re.findall(r"\d{4}\.\d{2}\.\d{1,2}[\._]?[\w\._]*", r.text, re.I) -# print(links) -print(sorted(list(set(links)), reverse=True)) -r = requests.get(f"{url}/current/{INDEX_FILE}") -current_json = r.json() -# print(current_json) -for spp in sorted(list(set(links)), reverse=True): - print(f"processing {spp}...") - r = requests.get(f"{url}{spp}/{INDEX_FILE}") - spp_json = r.json() - for name in spp_json: - # print(spp_json[name]["target"]) - if spp_json[name].get("target") and isinstance( - spp_json[name]["target"], list - ): - # print("no update needed") - continue - elif name not in current_json: - # print(f"{name} not in current") - spp_json[name]["target"] = [spp_json[name]["target"]] - else: - # print("update") - spp_json[name]["target"] = current_json[name]["target"] - - for name in spp_json: - if not isinstance(spp_json[name]["target"], list): - print(name) - -# # Fetch HTML content from the URL -# response = requests.get(url) -# html_content = response.content - -# # Parse the HTML content using BeautifulSoup -# soup = BeautifulSoup(html_content, "html.parser") - -# # Find all 'a' tags within 'pre' tags -# pre_tags = soup.find_all("pre") - -# # Extract folder names with date using regular expressions -# folder_names_with_date = [] -# for pre_tag in pre_tags: -# a_tags = pre_tag.find_all("a", href=True) -# for a_tag in a_tags: -# href = a_tag["href"] -# match = re.search(r"(\d{4}\.\d{2}\.\d{1,2}[\._]?\w*)/", href) -# if match: -# folder_names_with_date.append(match.group(0)) - -# # Print the extracted folder names with date -# print(folder_names_with_date) From 294ffd2cd0697e2938c541e509cf0bf3302def10 Mon Sep 17 00:00:00 2001 From: nancyc12 Date: Tue, 16 Apr 2024 17:59:51 +0800 Subject: [PATCH 05/10] remove unused file --- .../HPE/tests/raw_firmwareinventory | 497 ------------------ 1 file changed, 497 deletions(-) delete mode 100644 device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/raw_firmwareinventory diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/raw_firmwareinventory b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/raw_firmwareinventory deleted file mode 100644 index fa3209d0..00000000 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/tests/raw_firmwareinventory +++ /dev/null @@ -1,497 +0,0 @@ -{ - "@odata.context": "/redfish/v1/$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection", - "@odata.etag": 'W/"9EA3BDF0"', - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/", - "@odata.type": "#SoftwareInventoryCollection.SoftwareInventoryCollection", - "Description": "Firmware Inventory Collection", - "Members": [ - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/1/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "SystemBMC", - "Id": "1", - "Name": "iLO 5", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "2f317b9d-c9e3-4d76-bff6-b9d0d085a952", - "DeviceContext": "System Board", - "Targets": [ - "4764a662-b342-4fc7-9ce9-258c5d99e815", - "c0bcf2b9-1141-49af-aab8-c73791f0349c", - ], - } - }, - "Status": {"Health": "OK", "State": "Enabled"}, - "Updateable": true, - "Version": "2.96 Aug 17 2023", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/2/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "SystemRomActive", - "Id": "2", - "Name": "System ROM", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "aa148d2e-6e09-453e-bc6f-63baa5f5ccc4", - "DeviceContext": "System Board", - "Targets": [ - "00000000-0000-0000-0000-000000000205", - "00000000-0000-0000-0000-000001553330", - ], - } - }, - "Status": {"Health": "OK", "State": "Enabled"}, - "Updateable": true, - "Version": "U30 v2.90 (07/20/2023)", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/3/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "PlatformDefinitionTable", - "Id": "3", - "Name": "Intelligent Platform Abstraction Data", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "b8f46d06-85db-465c-94fb-d106e61378ed", - "DeviceContext": "System Board", - "Targets": [ - "00000000-0000-0000-0000-000000000205", - "00000000-0000-0000-0000-000001553330", - ], - } - }, - "Updateable": true, - "Version": "16.5.0 Build 53", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/4/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "SystemProgrammableLogicDevice", - "Id": "4", - "Name": "System Programmable Logic Device", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "b1ad439a-9dd1-41c1-a496-2da9313f1f07", - "DeviceContext": "System Board", - "Targets": ["00000000-0000-0000-0000-000000000205"], - } - }, - "Status": {"Health": "OK", "State": "Enabled"}, - "Updateable": true, - "Version": "0x31", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/5/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "PowerManagementController", - "Id": "5", - "Name": "Power Management Controller Firmware", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "9e48a28a-586c-4519-8405-a04f84e27f0f", - "DeviceContext": "System Board", - "Targets": [ - "00000000-0000-0000-0000-000000000205", - "00000000-0000-0000-0000-000000504d05", - ], - } - }, - "Updateable": true, - "Version": "1.1.0", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/6/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "NVMeBackplane", - "Id": "6", - "Name": "NVMe Backplane Firmware", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "3653aa90-7089-453a-899c-792827a50d67", - "DeviceContext": "System Board", - "Targets": [ - "00000000-0000-0000-0000-000000000205", - "00000000-0000-0000-0000-000049535320", - ], - } - }, - "Updateable": true, - "Version": "1.24", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/7/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "PowerSupplies", - "Id": "7", - "Name": "Power Supply Firmware", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "6bb86077-0275-4614-aae1-86618e8b1c27", - "DeviceContext": "Bay 1", - "Targets": ["0302b505-0002-0000-0000-0cf38db966ea"], - } - }, - "Updateable": true, - "Version": "2.00", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/8/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "PowerSupplies", - "Id": "8", - "Name": "Power Supply Firmware", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "6bb86077-0275-4614-aae1-86618e8b1c27", - "DeviceContext": "Bay 2", - "Targets": ["0302b505-0002-0000-0000-0cf38db966ea"], - } - }, - "Updateable": true, - "Version": "2.00", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/9/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "InnovationEngineFirmware", - "Id": "9", - "Name": "Innovation Engine (IE) Firmware", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "c734e171-8721-48c9-9ed6-d5bc7da5ef8d", - "DeviceContext": "System Board", - "Targets": [ - "00000000-0000-0000-0000-000000000205", - "a6b1a447-382a-5a4f-3c10-3c100a000303", - ], - } - }, - "Status": {"Health": "OK", "State": "Enabled"}, - "Updateable": true, - "Version": "0.2.3.0", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/10/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "SPSFirmwareVersionData", - "Id": "10", - "Name": "Server Platform Services (SPS) Firmware", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "b34e5677-21dc-45d3-872b-42f76fee9053", - "DeviceContext": "System Board", - "Targets": [ - "00000000-0000-0000-0000-000000000205", - "a6b1a447-382a-5a4f-3c10-86800a000101", - ], - } - }, - "Status": {"Health": "OK", "State": "Enabled"}, - "Updateable": true, - "Version": "4.1.5.2", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/11/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "SPSFirmwareDescriptor", - "Id": "11", - "Name": "Server Platform Services (SPS) Descriptor", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "3f30a329-d03c-46b8-8f0e-9567fad4ea9f", - "DeviceContext": "System Board", - "Targets": ["00000000-0000-0000-0000-000000000205"], - } - }, - "Updateable": true, - "Version": "1.2 0", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/12/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "SystemRomBackup", - "Id": "12", - "Name": "Redundant System ROM", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": null, - "DeviceContext": "System Board", - } - }, - "Updateable": true, - "Version": "U30 v2.76 (02/09/2023)", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/13/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "Intelligent Provisioning", - "Id": "13", - "Name": "Intelligent Provisioning", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "ac963eeb-ed78-4f36-c18c-29d85f34a0ac", - "DeviceContext": "System Board", - } - }, - "Updateable": true, - "Version": "3.50.100", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/14/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "PowerManagementControllerBootloader", - "Id": "14", - "Name": "Power Management Controller FW Bootloader", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": null, - "DeviceContext": "System Board", - } - }, - "Updateable": true, - "Version": "1.1", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/15/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "15b31015159000d3", - "Id": "15", - "Name": "HPE Eth 10/25Gb 2p 640FLR-SFP28 Adptr", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": null, - "DeviceContext": "Embedded ALOM", - "DeviceInstance": "PciRoot(0x3)/Pci(0x2,0x0)/Pci(0x0,0x0)", - "Targets": ["a6b1a447-382a-5a4f-15b3-1015159000d3"], - } - }, - "Updateable": false, - "Version": "14.32.1010", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/16/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "9005028f103c0654", - "Id": "16", - "Name": "HPE Smart Array E208i-a SR Gen10", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": null, - "DeviceContext": "Embedded RAID", - "DeviceInstance": "PciRoot(0x3)/Pci(0x0,0x0)/Pci(0x0,0x0)", - "Targets": ["a6b1a447-382a-5a4f-9005-028f103c0654"], - } - }, - "Updateable": true, - "Version": "6.22", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/17/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "10de1eb810de12a2", - "Id": "17", - "Name": "NVIDIA Tesla T4", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": null, - "DeviceContext": "PCI-E Slot 2", - "DeviceInstance": "PciRoot(0x2)/Pci(0x0,0x0)/Pci(0x0,0x0)", - "Targets": ["a6b1a447-382a-5a4f-10de-1eb810de12a2"], - } - }, - "Updateable": false, - "Version": "90.04.96.00.01", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/18/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "10de1eb810de12a2", - "Id": "18", - "Name": "NVIDIA Tesla T4", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": null, - "DeviceContext": "PCI-E Slot 3", - "DeviceInstance": "PciRoot(0x1)/Pci(0x0,0x0)/Pci(0x0,0x0)", - "Targets": ["a6b1a447-382a-5a4f-10de-1eb810de12a2"], - } - }, - "Updateable": false, - "Version": "90.04.96.00.01", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/19/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "10de1eb810de12a2", - "Id": "19", - "Name": "NVIDIA Tesla T4", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": null, - "DeviceContext": "PCI-E Slot 5", - "DeviceInstance": "PciRoot(0x7)/Pci(0x0,0x0)/Pci(0x0,0x0)", - "Targets": ["a6b1a447-382a-5a4f-10de-1eb810de12a2"], - } - }, - "Updateable": false, - "Version": "90.04.96.00.01", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/20/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "10de1eb810de12a2", - "Id": "20", - "Name": "NVIDIA Tesla T4", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": null, - "DeviceContext": "PCI-E Slot 6", - "DeviceInstance": "PciRoot(0x8)/Pci(0x0,0x0)/Pci(0x0,0x0)", - "Targets": ["a6b1a447-382a-5a4f-10de-1eb810de12a2"], - } - }, - "Updateable": false, - "Version": "90.04.96.00.01", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/21/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "102b0538159000e4", - "Id": "21", - "Name": "Embedded Video Controller", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": null, - "DeviceContext": "Embedded Device", - "DeviceInstance": "PciRoot(0x0)/Pci(0x1C,0x4)/Pci(0x0,0x1)", - "Targets": ["a6b1a447-382a-5a4f-102b-0538159000e4"], - } - }, - "Updateable": false, - "Version": "2.5", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/22/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "Samsung SSD 983 DCT 960GB", - "Id": "22", - "Name": "NVMe Drive", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "f6de0320-2e0f-489a-b238-6dd8ae7c3811", - "DeviceContext": "NVMe Drive Port 5B Box 1 Bay 1", - "Targets": ["532340a5-6d61-7573-6e67-20532a9e3acf"], - } - }, - "Updateable": false, - "Version": "EDA5302Q", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/23/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "Samsung SSD 983 DCT 960GB", - "Id": "23", - "Name": "NVMe Drive", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "f6de0320-2e0f-489a-b238-6dd8ae7c3811", - "DeviceContext": "NVMe Drive Port 5B Box 1 Bay 2", - "Targets": ["532340a5-6d61-7573-6e67-20532a9e3acf"], - } - }, - "Updateable": false, - "Version": "EDA5302Q", - }, - { - "@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory", - "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/24/", - "@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory", - "Description": "Universal Backplane Manager", - "Id": "24", - "Name": "HPE 2SFF NVMe/SAS/uFF Backplane", - "Oem": { - "Hpe": { - "@odata.context": "/redfish/v1/$metadata#HpeiLOSoftwareInventory.HpeiLOSoftwareInventory", - "@odata.type": "#HpeiLOSoftwareInventory.v2_1_0.HpeiLOSoftwareInventory", - "DeviceClass": "4149ebb7-d64b-4654-b679-4280f349ea50", - "DeviceContext": "Box=1", - "Targets": ["9675b54e-1c96-44c3-a7a1-901500000000"], - } - }, - "Updateable": true, - "Version": "1.24", - }, - ], - "Members@odata.count": 24, - "Name": "Firmware Inventory Collection", -} From f7cb73a32530cb379a091152448b89cf45bc8200 Mon Sep 17 00:00:00 2001 From: nancyc12 Date: Tue, 16 Apr 2024 19:22:18 +0800 Subject: [PATCH 06/10] update doc for firmware update on HPE machines --- docs/reference/test-phases.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/reference/test-phases.rst b/docs/reference/test-phases.rst index 96e4bf14..2cc0e894 100644 --- a/docs/reference/test-phases.rst +++ b/docs/reference/test-phases.rst @@ -67,7 +67,8 @@ To trigger the firmware update phase, provide the following section in the job d Variables in ``firmware_update_data``: -* ``version``: The desired firmware level on the device. Currently the only supported value is ``latest``, which upgrades all components in the device with the latest firmware release. +* ``version``: The desired firmware level on the device. Currently the only shared supported value among different machines is ``latest``, which upgrades all components in the device with the latest firmware release. For HPE server machines, user can specify a model-based release version string referring to [HPE Gen10](https://downloads.linux.hpe.com/SDR/repo/fwpp-gen10/), [HPE Gen11](https://downloads.linux.hpe.com/SDR/repo/fwpp-gen11/) and [HPE RL](https://downloads.linux.hpe.com/SDR/repo/rlcp/firmware/) +firmware repositories. For example, ``2023.09.00.04`` is applicable for HPE Gen10 server machines. * ``ignore_failure``: If set to false, Testflinger agent will suspend the job if firmware_update phase return a status other than 0, which implies there's a failure during firmware_update phase. If set to true, the job will continue regardless the status of firmware_update phase. The default value is ``false``. If either ``firmware_update_command`` is missing from the agent configuration, or the ``firmware_update_data`` section is missing from the job, this phase will be skipped. From 98569fe3c85faf72b5c5296a6aa04d5df1e57553 Mon Sep 17 00:00:00 2001 From: nancyc12 Date: Tue, 16 Apr 2024 19:53:31 +0800 Subject: [PATCH 07/10] update wordlist --- docs/.wordlist.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/.wordlist.txt b/docs/.wordlist.txt index 547e0353..9254d654 100644 --- a/docs/.wordlist.txt +++ b/docs/.wordlist.txt @@ -22,9 +22,13 @@ EFI EKS EMMC favicon +fwpp Git GitHub Grafana +HPE +hpe +https IAM init installable @@ -41,6 +45,7 @@ kvm Lenovo lenovo lifecycle +linux logfile LTS LVM @@ -73,13 +78,17 @@ provisionable provisioner ReadMe readthedocs +repo reST reStructuredText +RL +rlcp roadmap RPI RTD runtime SDWire +SDR SecureBoot SKU SQA From 4fc41d9816bea963c146d85a2da134ee5237e653 Mon Sep 17 00:00:00 2001 From: nancyc12 Date: Tue, 16 Apr 2024 19:56:44 +0800 Subject: [PATCH 08/10] update doc --- docs/reference/test-phases.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/reference/test-phases.rst b/docs/reference/test-phases.rst index 2cc0e894..4ed1c8a6 100644 --- a/docs/reference/test-phases.rst +++ b/docs/reference/test-phases.rst @@ -67,8 +67,7 @@ To trigger the firmware update phase, provide the following section in the job d Variables in ``firmware_update_data``: -* ``version``: The desired firmware level on the device. Currently the only shared supported value among different machines is ``latest``, which upgrades all components in the device with the latest firmware release. For HPE server machines, user can specify a model-based release version string referring to [HPE Gen10](https://downloads.linux.hpe.com/SDR/repo/fwpp-gen10/), [HPE Gen11](https://downloads.linux.hpe.com/SDR/repo/fwpp-gen11/) and [HPE RL](https://downloads.linux.hpe.com/SDR/repo/rlcp/firmware/) -firmware repositories. For example, ``2023.09.00.04`` is applicable for HPE Gen10 server machines. +* ``version``: The desired firmware level on the device. Currently the only shared supported value among different machines is ``latest``, which upgrades all components in the device with the latest firmware release. For HPE server machines, user can specify a model-based release version string referring to [HPE Gen10](https://downloads.linux.hpe.com/SDR/repo/fwpp-gen10/), [HPE Gen11](https://downloads.linux.hpe.com/SDR/repo/fwpp-gen11/) and [HPE RL](https://downloads.linux.hpe.com/SDR/repo/rlcp/firmware/) firmware repositories. For example, ``2023.09.00.04`` is applicable for HPE Gen10 server machines. * ``ignore_failure``: If set to false, Testflinger agent will suspend the job if firmware_update phase return a status other than 0, which implies there's a failure during firmware_update phase. If set to true, the job will continue regardless the status of firmware_update phase. The default value is ``false``. If either ``firmware_update_command`` is missing from the agent configuration, or the ``firmware_update_data`` section is missing from the job, this phase will be skipped. From c949fbc6d338ab2a8e5a7933b83e6bbd17791d52 Mon Sep 17 00:00:00 2001 From: nancyc12 Date: Wed, 17 Apr 2024 11:33:22 +0800 Subject: [PATCH 09/10] bug fix --- .../src/testflinger_device_connectors/fw_devices/HPE/HPE.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py index 08af3962..a62a8264 100755 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py @@ -170,7 +170,7 @@ def _download_file(self, url): try: r = requests.get(url) except requests.exceptions.ConnectionError as e: - logging.error(e.output) + logging.error(err_msg) continue if r.status_code != 200: logging.error(err_msg) @@ -526,9 +526,11 @@ def _monitor_poststate(self, state: str, timeout: int): timeout_start = time.time() while time.time() < timeout_start + timeout: try: + self._login_ilo() rc, stdout, stderr = self.run_cmd( cmd, raise_stderr=False, timeout=10 ) + self._logout_ilo() except subprocess.TimeoutExpired: continue else: From d2b4500e224ba88afacd1cfabca3b60a817daca6 Mon Sep 17 00:00:00 2001 From: nancyc12 Date: Wed, 17 Apr 2024 11:44:33 +0800 Subject: [PATCH 10/10] bug fix --- .../src/testflinger_device_connectors/fw_devices/HPE/HPE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py index a62a8264..2cb38c43 100755 --- a/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py +++ b/device-connectors/src/testflinger_device_connectors/fw_devices/HPE/HPE.py @@ -169,7 +169,7 @@ def _download_file(self, url): for _ in range(3): try: r = requests.get(url) - except requests.exceptions.ConnectionError as e: + except requests.exceptions.ConnectionError: logging.error(err_msg) continue if r.status_code != 200: