#!/usr/bin/env python3 import json import secrets import string import urllib.request import requests from robot.api import logger from robot.api.deco import keyword from robot.libraries.BuiltIn import BuiltIn from urllib3.exceptions import InsecureRequestWarning class redfish_request(object): @staticmethod def generate_clientid(): r""" Generate 10 character unique id. e.g. "oMBhLv2Q9e" """ clientid = "".join( secrets.choice(string.ascii_letters + string.digits) for i in range(10) ) clientid = "".join(str(i) for i in clientid) return clientid @staticmethod def form_url(url): r""" Form a complete path for user url. Description of argument(s): url Url passed by user e.g. /redfish/v1/Systems/system. """ openbmc_host = BuiltIn().get_variable_value( "${OPENBMC_HOST}", default="" ) https_port = BuiltIn().get_variable_value("${HTTPS_PORT}", default="") form_url = ( "https://" + str(openbmc_host) + ":" + str(https_port) + str(url) ) return form_url @staticmethod def log_console(response): r""" Print function for console. Description of argument(s): response Response from requests. """ logger.console(msg="", newline=True) logger.info( "Response : [%s]" % response.status_code, also_console=True ) logger.console(msg="", newline=True) def request_login(self, headers, url, credential, timeout=10): r""" Redfish request to create a session. Description of argument(s): headers By default headers is assigned as application/json. If user assign the headers, then default headers is not considered. url Requested path from user. credential User has to assign the credential like username and password. UserName = xxxxxxxx Password = xxxxxxxx Client id, user need to assign None in order to auto generate, else user can assign any value. timeout By default timeout is set to 10 seconds. If user assign the timeout, then default timeout value is not considered. """ if headers == "None": headers = dict() headers["Content-Type"] = "application/json" client_id = credential["Oem"]["OpenBMC"].get("ClientID", "None") if "None" == client_id: self.clientid = redfish_request.generate_clientid() credential["Oem"]["OpenBMC"]["ClientID"] = self.clientid logger.console(msg="", newline=True) requests.packages.urllib3.disable_warnings( category=InsecureRequestWarning ) response = redfish_request.request_post( self, headers=headers, url=url, data=credential ) return response def request_get(self, headers, url, timeout=10, verify=False): r""" Redfish get request. Description of argument(s): headers By default headers is assigned as application/json. If user assign the headers, then default headers is not considered. url Requested path from user. timeout By default timeout is set to 10 seconds. If user assign the timeout, then default timeout value is not considered. verify By default verify is set to false means no certificate verification is performed else in case of true, certificate needs to be verified. If user assign the verify, then default verify value is not considered. """ if headers.get("Content-Type", None) is None: headers["Content-Type"] = "application/json" url = redfish_request.form_url(url) logger.console(msg="", newline=True) msg = ( "Request Method : GET ,headers = " + json.dumps(headers) + " ,uri = " + str(url) + " ,timeout = " + str(timeout) + " ,verify = " + str(verify) ) logger.info(msg, also_console=True) response = requests.get( url, headers=headers, timeout=timeout, verify=verify ) redfish_request.log_console(response) return response def request_patch(self, headers, url, data=None, timeout=10, verify=False): r""" Redfish patch request. Description of argument(s): headers By default headers is assigned as application/json. If user assign the headers, then default headers is not considered. url Requested path from user. data By default data is None. If user assign the data, then default data value is not considered. timeout By default timeout is set to 10 seconds. If user assign the timeout, then default timeout value is not considered. verify By default verify is set to false means no certificate verification is performed else in case of true, certificate needs to be verified. If user assign the verify, then default verify value is not considered. """ if headers.get("Content-Type", None) is None: headers["Content-Type"] = "application/json" url = redfish_request.form_url(url) logger.console(msg="", newline=True) msg = ( "Request Method : PATCH ,headers = " + json.dumps(headers) + " ,uri = " + str(url) + " ,data = " + json.dumps(data) + " ,timeout = " + str(timeout) + " ,verify = " + str(verify) ) logger.info(msg, also_console=True) response = requests.patch( url, headers=headers, data=data, timeout=timeout, verify=verify ) redfish_request.log_console(response) return response def request_post(self, headers, url, data=None, timeout=10, verify=False): r""" Redfish post request. Description of argument(s): headers By default headers is assigned as application/json. If user assign the headers, then default headers is not considered. url Requested path from user. data By default data is None. If user assign the data, then default data value is not considered. timeout By default timeout is set to 10 seconds. If user assign the timeout, then default timeout value is not considered. verify By default verify is set to false means no certificate verification is performed else in case of true, certificate needs to be verified. If user assign the verify, then default verify value is not considered. """ if headers.get("Content-Type", None) is None: headers["Content-Type"] = "application/json" url = redfish_request.form_url(url) logger.console(msg="", newline=True) msg = ( "Request Method : POST ,headers = " + json.dumps(headers) + " ,uri = " + str(url) + " ,data = " + json.dumps(data) + " ,timeout = " + str(timeout) + " ,verify = " + str(verify) ) logger.info(msg, also_console=True) response = requests.post( url, headers=headers, data=json.dumps(data), timeout=timeout, verify=verify, ) redfish_request.log_console(response) return response def request_put( self, headers, url, files=None, data=None, timeout=10, verify=False ): r""" Redfish put request. Description of argument(s): headers By default headers is assigned as application/json. If user assign the headers, then default headers is not considered. url Requested path from user. files By default files is None. If user assign the files, then default files value is not considered. data By default data is None. If user pass the data, then default data value is not considered. timeout By default timeout is set to 10 seconds. If user pass the timeout, then default timeout value is not considered. verify By default verify is set to false means no certificate verification is performed else in case of true, certificate needs to be verified. If user assign the verify, then default verify value is not considered. """ if headers.get("Content-Type", None) is None: headers["Content-Type"] = "application/json" url = redfish_request.form_url(url) logger.console(msg="", newline=True) msg = ( "Request Method : PUT ,headers = " + json.dumps(headers) + " ,uri = " + str(url) + " ,data = " + json.dumps(data) + " ,timeout = " + str(timeout) + " ,verify = " + str(verify) ) logger.info(msg, also_console=True) response = requests.put( url, headers=headers, files=files, data=data, timeout=timeout, verify=verify, ) redfish_request.log_console(response) return response def request_delete( self, headers, url, data=None, timeout=10, verify=False ): r""" Redfish delete request. Description of argument(s): headers By default headers is assigned as application/json. If user pass the headers then default header is not considered. url Requested path from user. data By default data is None. If user pass the data, then default data value is not considered. timeout By default timeout is set to 10 seconds. If user pass the timeout, then default timeout value is not considered. verify By default verify is set to false means no certificate verification is performed else in case of true, certificate needs to be verified. If user assign the verify, then default verify value is not considered. """ if headers.get("Content-Type", None) is None: headers["Content-Type"] = "application/json" url = redfish_request.form_url(url) logger.console(msg="", newline=True) msg = ( "Request Method : DELETE ,headers = " + json.dumps(headers) + " ,uri = " + str(url) + " ,data = " + json.dumps(data) + " ,timeout = " + str(timeout) + " ,verify = " + str(verify) ) logger.console(msg="", newline=True) response = requests.delete( url, headers=headers, data=data, timeout=timeout, verify=verify ) redfish_request.log_console(response) return response @staticmethod def dict_parse(variable, lookup_dict): r""" Find a variable in dict. Description of argument(s): variable Variable that need to be searched in dict. lookup_dict Disctionay contains variables. """ result = lookup_dict.get(variable, None) return result @staticmethod def get_target_actions(target_attribute, response): r""" Get target entry of the searched target attribute. Description of argument(s): target_attribute Name of the attribute (e.g. 'Manager.Reset'). response Response from url. 'Actions' : { '#Manager.Reset' : { '@Redfish.ActionInfo' : '/redfish/v1/Managers/${MANAGER_ID}/ResetActionInfo', 'target' : '/redfish/v1/Managers/${MANAGER_ID}/Actions/Manager.Reset' } } """ lookup_list = ["Actions", "#" + attribute, "target"] for lookup_item in lookup_list: response = redfish_request.dict_parse(lookup_item, response) if response is not None and type(response) is dict(): continue else: return response return None @staticmethod def get_attribute(attribute, data): r""" Get resource attribute. Description of argument(s): attribute Pass the attribute needs to be searched. data Pass the request response. """ value = data.get(attribute, None) return value