Add BIOS keywords to manage bmc via Redfish API
Implements BiosKeywords class to provide BIOS management capabilities for StarlingX test automation. The keywords support connecting to server BMCs using the Redfish API standard for hardware management. Key features: - Automatic system discovery and connection via BMC IP - Boot order configuration with override settings - System information retrieval (vendor, model, system ID) - Support for common boot devices (PXE, HDD, CD, USB, BIOS setup) The implementation uses the python-redfish library to communicate with BMC endpoints. Usage: lab_config = ConfigurationManager.get_lab_config() bm_password = lab_config.get_bm_password() node = lab_config.get_node(host_name) bm_ip = node.get_bm_ip() bm_username = node.get_bm_username() bios_keywords = BiosKeywords(bmc_ip=bm_ip, username=bm_username, password=bm_password) print(bios_keywords.get_boot_order()) bios_keywords.set_boot_order() print(bios_keywords.get_boot_order()) Test Plan: - Manual testing with Dell PowerEdge servers - Verified boot order changes via BMC interface - Tested system discovery and connection establishment Change-Id: I6efc4eec136f67730d14b225fe7a78b318c12eb8 Signed-off-by: Abhishek jaiswal <abhishek.jaiswal@windriver.com>
This commit is contained in:
1
Pipfile
1
Pipfile
@@ -33,3 +33,4 @@ sphinx = "==8.1.3"
|
|||||||
sphinx-autobuild = "==2024.2.4"
|
sphinx-autobuild = "==2024.2.4"
|
||||||
openstackdocstheme = "==3.4.1"
|
openstackdocstheme = "==3.4.1"
|
||||||
reno = "==4.1.0"
|
reno = "==4.1.0"
|
||||||
|
python-redfish = "==0.4.4"
|
||||||
|
8
Pipfile.lock
generated
8
Pipfile.lock
generated
@@ -865,6 +865,14 @@
|
|||||||
"markers": "python_version >= '3.8'",
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==8.1.1"
|
"version": "==8.1.1"
|
||||||
},
|
},
|
||||||
|
"python-redfish": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6c37652481dcd5b391e3741234b34f80ece3bcb62b07d9169f6ee3d6495c9e2f",
|
||||||
|
"sha256:ef5fbbf62cd8d474075c9844a369182c4e1b10dac2e7d4bd461f52c6f1e89ce8"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.4.4"
|
||||||
|
},
|
||||||
"pyyaml": {
|
"pyyaml": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff",
|
"sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff",
|
||||||
|
101
keywords/server/bios_keywords.py
Normal file
101
keywords/server/bios_keywords.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import redfish
|
||||||
|
|
||||||
|
from framework.logging.automation_logger import get_logger
|
||||||
|
from keywords.base_keyword import BaseKeyword
|
||||||
|
|
||||||
|
|
||||||
|
class BiosKeywords(BaseKeyword):
|
||||||
|
"""Keywords for BIOS operations using Redfish API."""
|
||||||
|
|
||||||
|
def __init__(self, bmc_ip: str, username: str, password: str):
|
||||||
|
"""Initialize Redfish client for Bios keywords.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bmc_ip (str): BMC IP address.
|
||||||
|
username (str): Username for authentication.
|
||||||
|
password (str): Password for authentication.
|
||||||
|
"""
|
||||||
|
self.bmc_ip = bmc_ip
|
||||||
|
self.username = username
|
||||||
|
self.password = password
|
||||||
|
self.system_id = None
|
||||||
|
self.vendor = None
|
||||||
|
self.model = None
|
||||||
|
|
||||||
|
self.redfish_client = redfish.redfish_client(
|
||||||
|
base_url=f"https://{self.bmc_ip}",
|
||||||
|
username=self.username,
|
||||||
|
password=self.password,
|
||||||
|
timeout=30,
|
||||||
|
default_prefix="/redfish/v1"
|
||||||
|
)
|
||||||
|
self.redfish_client.login(auth='session')
|
||||||
|
self.discover_system_info()
|
||||||
|
|
||||||
|
def discover_system_info(self):
|
||||||
|
"""Discover system ID from Redfish API."""
|
||||||
|
# Detect system ID
|
||||||
|
systems_resp = self.redfish_client.get("/redfish/v1/Systems")
|
||||||
|
|
||||||
|
if systems_resp.status != 200:
|
||||||
|
raise Exception(f"Failed to get systems: {systems_resp.status}")
|
||||||
|
|
||||||
|
members = systems_resp.dict.get("Members", [])
|
||||||
|
if not members:
|
||||||
|
raise Exception("No system members found in Redfish response")
|
||||||
|
self.system_id = list(members[0].values())[0] # e.g. /redfish/v1/Systems/System.Embedded.1
|
||||||
|
|
||||||
|
# Get system details
|
||||||
|
sys_info = self.get_system_info()
|
||||||
|
self.vendor = sys_info.get("Manufacturer", "Unknown")
|
||||||
|
self.model = sys_info.get("Model", "Unknown")
|
||||||
|
|
||||||
|
get_logger().log_info(f"Connected to {self.vendor} {self.model}, System ID: {self.system_id}")
|
||||||
|
|
||||||
|
def get_system_info(self):
|
||||||
|
"""Fetch system information"""
|
||||||
|
if not self.system_id:
|
||||||
|
raise Exception("Not connected to system")
|
||||||
|
|
||||||
|
resp = self.redfish_client.get(self.system_id)
|
||||||
|
if resp.status == 200:
|
||||||
|
# get_logger().log_info(f"system_info {resp.dict}")
|
||||||
|
return resp.dict
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to fetch system info: {resp.status}")
|
||||||
|
|
||||||
|
def get_boot_order(self):
|
||||||
|
"""Fetch current boot order and override settings"""
|
||||||
|
if not self.system_id:
|
||||||
|
raise Exception("Not connected to system")
|
||||||
|
|
||||||
|
resp = self.redfish_client.get(self.system_id)
|
||||||
|
if resp.status == 200:
|
||||||
|
return resp.dict.get("Boot", {})
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to fetch system info: {resp.status}")
|
||||||
|
|
||||||
|
return self.boot_order
|
||||||
|
|
||||||
|
def set_boot_order(self, device="Pxe", enabled="Once"):
|
||||||
|
"""Set boot order (override target device).
|
||||||
|
|
||||||
|
:param device (str): Boot device (e.g., "Pxe", "Hdd", "Cd", "Usb", "BiosSetup")
|
||||||
|
:param enabled (str): Boot override enabled mode ("Once", "Continuous", "Disabled")
|
||||||
|
"""
|
||||||
|
if not self.system_id:
|
||||||
|
raise Exception("Not connected to system")
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"Boot": {
|
||||||
|
"BootSourceOverrideTarget": device,
|
||||||
|
"BootSourceOverrideEnabled": enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.redfish_client.patch(self.system_id, body=payload)
|
||||||
|
|
||||||
|
if resp.status in [200, 204]:
|
||||||
|
get_logger().log_info(f"Boot device set to {device}, mode={enabled}")
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to set boot order: {resp.status}, {resp.text}")
|
Reference in New Issue
Block a user