Files
test/framework/redfish/client/redfish_client.py
jpike b7fe87a346 Adding centralized redfish client api
Adding some basic classes around redfish client.

Change-Id: I5cd581470c0620845992263e323e3f3e1c9767f2
Signed-off-by: jpike <jason.pike@windriver.com>
2025-09-09 14:10:02 -04:00

131 lines
5.2 KiB
Python

import time
from typing import Any, Dict, Optional
import redfish
from redfish.rest.v1 import HttpClient
from framework.exceptions.redfish_client_unreachable_exception import RedFishClientUnreachable
from framework.logging.automation_logger import get_logger
class RedFishClient:
"""
Class for RedFish client
"""
def __init__(self, bmc_ip: str, username: str, password: str, timeout: int = 120):
self.bmc_ip = bmc_ip
self.username = username
self.password = password
self.timeout = timeout
self.client_obj = None
self.status_code: int = -1
def _get_connection(self) -> HttpClient:
"""
Gets the connection, creates one if it doesn't exist
Returns:
HttpClient: the connection
"""
if self.client_obj is None:
self.client_obj = self._connect()
return self.client_obj
def _connect(self) -> HttpClient:
"""
Create a connection
Returns:
HttpClient: the connection
"""
self.status_code = -1
end_time = time.time() + self.timeout
last_exception = None
while time.time() < end_time:
try:
get_logger().log_info(f"Getting a Redfish client to {self.bmc_ip} ....")
self.client_obj = redfish.redfish_client(base_url=f"https://{self.bmc_ip}", username=self.username, password=self.password, timeout=30)
self.client_obj.login(auth="session")
get_logger().log_info(f"Redfish client established for {self.bmc_ip} ....")
return self.client_obj
except Exception as e:
last_exception = e
get_logger().log_debug(f"Failed to establish a redfish client: {e}\n Retrying ...")
else:
err_msg = f"Failed to open a redfish client for server with ip: {self.bmc_ip} " f"and credentials {self.username}/{self.password}: {last_exception}"
get_logger().log_warning(err_msg)
raise RedFishClientUnreachable(err_msg)
def get(self, path: str, args: Optional[Dict[str, Any]] = None, headers: Optional[Dict[str, Any]] = None) -> Any:
"""
Executes the REST API GET request to query resources' data.
Args:
path (str): The URI identifying the resource
args (Optional[Dict[str, Any]]): Any additional arguments for the REST API HTTP method
headers (Optional[Dict[str, Any]]): Headers to be appended to the REST API GET request
Returns:
Any: Response object from the REST API call
"""
get_logger().log_debug("running RedFish API:\n" f"METHOD: GET\n" f"URL: {self.bmc_ip}{path}\n" f"ARGS: {args}\n" f"HEADERS: {headers}")
resp = self._get_connection().get(path=path, args=args, headers=headers)
end_time = time.time() + self.timeout
while resp.is_processing and time.time() < end_time:
time.sleep(1)
status = resp.status
get_logger().log_debug(f"Response from RedFish API on URL: {self.bmc_ip}{path}\n:" f"Status: {status}\n" f"Data: {resp.dict}")
self.status_code = resp.status
return resp
def post(self, path: str, args: Optional[Dict[str, Any]] = None, body: Optional[Dict[str, Any]] = None, headers: Optional[Dict[str, Any]] = None) -> Any:
"""
Executes the REST API POST request to create or use actions on resources.
Args:
path (str): The URI identifying the resource
args (Optional[Dict[str, Any]]): Any additional arguments for the REST API HTTP method
body (Optional[Dict[str, Any]]): The payload to be appended to the POST request
headers (Optional[Dict[str, Any]]): Headers to be appended to the REST API POST request
Returns:
Any: Response object from the REST API call
"""
get_logger().log_debug("running RedFish API:\n" f"METHOD: POST\n" f"URL: {self.bmc_ip}{path}\n" f"ARGS: {args}\n" f"BODY: {body}\n" f"HEADERS: {headers}")
resp = self._get_connection().post(path=path, args=args, body=body, headers=headers)
get_logger().log_debug(f"Response from RedFish API on URL: {self.bmc_ip}{path}\n:" f"Status: {resp.status}\n")
return resp
def patch(self, path: str, args: Optional[Dict[str, Any]] = None, body: Optional[Dict[str, Any]] = None, headers: Optional[Dict[str, Any]] = None) -> Any:
"""
Executes the REST API PATCH request to change or add properties on resources.
Args:
path (str): The URI identifying the resource
args (Optional[Dict[str, Any]]): Any additional arguments for the REST API HTTP method
body (Optional[Dict[str, Any]]): The payload to be appended to the PATCH request
headers (Optional[Dict[str, Any]]): Headers to be appended to the REST API PATCH request
Returns:
Any: Response object from the REST API call
"""
return self._get_connection().patch(path=path, args=args, body=body, headers=headers)
def get_status_code(self) -> int:
"""
Getter for status code
Returns:
int: The status code
"""
return self.status_code