1#!/usr/bin/env python 2 3import requests 4import urllib.request 5from urllib3.exceptions import InsecureRequestWarning 6import json 7import secrets 8import string 9 10from robot.api import logger 11from robot.libraries.BuiltIn import BuiltIn 12from robot.api.deco import keyword 13 14 15class redfish_request(object): 16 17 @staticmethod 18 def generate_clientid(): 19 r""" 20 Generate 10 character unique id. 21 22 e.g. "oMBhLv2Q9e" 23 24 """ 25 26 clientid = ''.join(secrets.choice( 27 string.ascii_letters + string.digits) for i in range(10)) 28 clientid = ''.join(str(i) for i in clientid) 29 30 return clientid 31 32 @staticmethod 33 def form_url(url): 34 r""" 35 Form a complete path for user url. 36 37 Description of argument(s): 38 url Url passed by user e.g. /redfish/v1/Systems/system. 39 """ 40 41 openbmc_host = \ 42 BuiltIn().get_variable_value("${OPENBMC_HOST}", default="") 43 https_port = BuiltIn().get_variable_value("${HTTPS_PORT}", default="") 44 form_url = \ 45 "https://" + str(openbmc_host) + ":" + str(https_port) + str(url) 46 47 return form_url 48 49 @staticmethod 50 def log_console(response): 51 r""" 52 Print function for console. 53 54 Description of argument(s): 55 response Response from requests. 56 """ 57 58 logger.console(msg='', newline=True) 59 logger.info("Response : [%s]" % response.status_code, 60 also_console=True) 61 logger.console(msg='', newline=True) 62 63 def request_login(self, headers, url, credential, timeout=10): 64 r""" 65 Redfish request to create a session. 66 67 Description of argument(s): 68 headers By default headers is assigned as application/json. 69 If user assign the headers, 70 then default headers is not considered. 71 url Requested path from user. 72 credential User has to assign the credential like username and 73 password. 74 UserName = xxxxxxxx Password = xxxxxxxx 75 Client id, user need to assign None in order to auto 76 generate, else user can assign any value. 77 timeout By default timeout is set to 10 seconds. 78 If user assign the timeout, then default timeout 79 value is not considered. 80 """ 81 82 if headers == "None": 83 headers = dict() 84 headers['Content-Type'] = 'application/json' 85 86 client_id = credential['Oem']['OpenBMC'].get('ClientID', "None") 87 88 if "None" == client_id: 89 self.clientid = redfish_request.generate_clientid() 90 credential['Oem']['OpenBMC']['ClientID'] = self.clientid 91 92 logger.console(msg='', newline=True) 93 requests.packages.urllib3.\ 94 disable_warnings(category=InsecureRequestWarning) 95 response = redfish_request.request_post(self, headers=headers, 96 url=url, data=credential) 97 98 return response 99 100 def request_get(self, headers, url, timeout=10, verify=False): 101 r""" 102 Redfish get request. 103 104 Description of argument(s): 105 headers By default headers is assigned as application/json. 106 If user assign the headers, then default headers is not 107 considered. 108 url Requested path from user. 109 timeout By default timeout is set to 10 seconds. 110 If user assign the timeout, then default timeout value 111 is not considered. 112 verify By default verify is set to false means no certificate 113 verification is performed 114 else in case of true, certificate needs to be verified. 115 If user assign the verify, then default verify value 116 is not considered. 117 """ 118 119 if headers.get('Content-Type', None) is None: 120 headers['Content-Type'] = 'application/json' 121 122 url = redfish_request.form_url(url) 123 124 logger.console(msg='', newline=True) 125 msg = "Request Method : GET ,headers = " + \ 126 json.dumps(headers) + " ,uri = " + str(url) + " ,timeout = " + \ 127 str(timeout) + " ,verify = " + str(verify) 128 logger.info(msg, also_console=True) 129 130 response = requests.get(url, headers=headers, 131 timeout=timeout, verify=verify) 132 redfish_request.log_console(response) 133 134 return response 135 136 def request_patch(self, headers, url, data=None, timeout=10, verify=False): 137 r""" 138 Redfish patch request. 139 140 Description of argument(s): 141 headers By default headers is assigned as application/json. 142 If user assign the headers, then default headers is not 143 considered. 144 url Requested path from user. 145 data By default data is None. 146 If user assign the data, then default data value is not 147 considered. 148 timeout By default timeout is set to 10 seconds. 149 If user assign the timeout, then default timeout value 150 is not considered. 151 verify By default verify is set to false means no certificate 152 verification is performed 153 else in case of true, certificate needs to be verified. 154 If user assign the verify, then default verify value 155 is not considered. 156 """ 157 158 if headers.get('Content-Type', None) is None: 159 headers['Content-Type'] = 'application/json' 160 161 url = redfish_request.form_url(url) 162 163 logger.console(msg='', newline=True) 164 msg = "Request Method : PATCH ,headers = " + \ 165 json.dumps(headers) + " ,uri = " + str(url) + " ,data = " + \ 166 json.dumps(data) + " ,timeout = " + str(timeout) + \ 167 " ,verify = " + str(verify) 168 logger.info(msg, also_console=True) 169 170 response = requests.patch(url, headers=headers, data=data, 171 timeout=timeout, verify=verify) 172 redfish_request.log_console(response) 173 174 return response 175 176 def request_post(self, headers, url, data=None, timeout=10, verify=False): 177 r""" 178 Redfish post request. 179 180 Description of argument(s): 181 headers By default headers is assigned as application/json. 182 If user assign the headers, then default headers is not 183 considered. 184 url Requested path from user. 185 data By default data is None. 186 If user assign the data, then default data value is not 187 considered. 188 timeout By default timeout is set to 10 seconds. 189 If user assign the timeout, then default timeout value 190 is not considered. 191 verify By default verify is set to false means no 192 certificate verification is performed 193 else in case of true, certificate needs to be verified. 194 If user assign the verify, then default verify value 195 is not considered. 196 """ 197 198 if headers.get('Content-Type', None) is None: 199 headers['Content-Type'] = 'application/json' 200 201 url = redfish_request.form_url(url) 202 203 logger.console(msg='', newline=True) 204 msg = "Request Method : POST ,headers = " + \ 205 json.dumps(headers) + " ,uri = " + str(url) + " ,data = " + \ 206 json.dumps(data) + " ,timeout = " + str(timeout) + \ 207 " ,verify = " + str(verify) 208 logger.info(msg, also_console=True) 209 210 response = requests.post(url, headers=headers, data=json.dumps(data), 211 timeout=timeout, verify=verify) 212 redfish_request.log_console(response) 213 214 return response 215 216 def request_put(self, headers, url, files=None, data=None, 217 timeout=10, verify=False): 218 r""" 219 Redfish put request. 220 221 Description of argument(s): 222 headers By default headers is assigned as application/json. 223 If user assign the headers, then default headers is not 224 considered. 225 url Requested path from user. 226 files By default files is None. 227 If user assign the files, then default files value 228 is not considered. 229 data By default data is None. 230 If user pass the data, then default data value is not 231 considered. 232 timeout By default timeout is set to 10 seconds. 233 If user pass the timeout, then default timeout value 234 is not considered. 235 verify By default verify is set to false means no 236 certificate verification is performed 237 else in case of true, certificate needs to be verified. 238 If user assign the verify, then default verify value 239 is not considered. 240 """ 241 242 if headers.get('Content-Type', None) is None: 243 headers['Content-Type'] = 'application/json' 244 245 url = redfish_request.form_url(url) 246 247 logger.console(msg='', newline=True) 248 msg = "Request Method : PUT ,headers = " + \ 249 json.dumps(headers) + " ,uri = " + str(url) + " ,data = " + \ 250 json.dumps(data) + " ,timeout = " + str(timeout) + \ 251 " ,verify = " + str(verify) 252 logger.info(msg, also_console=True) 253 254 response = requests.put(url, headers=headers, files=files, data=data, 255 timeout=timeout, verify=verify) 256 redfish_request.log_console(response) 257 258 return response 259 260 def request_delete(self, headers, url, data=None, timeout=10, verify=False): 261 r""" 262 Redfish delete request. 263 264 Description of argument(s): 265 headers By default headers is assigned as application/json. 266 If user pass the headers then default header is not 267 considered. 268 url Requested path from user. 269 data By default data is None. 270 If user pass the data, then default data value is not 271 considered. 272 timeout By default timeout is set to 10 seconds. 273 If user pass the timeout, then default timeout value 274 is not considered. 275 verify By default verify is set to false means no 276 certificate verification is performed 277 else in case of true, certificate needs to be verified. 278 If user assign the verify, then default verify value 279 is not considered. 280 """ 281 282 if headers.get('Content-Type', None) is None: 283 headers['Content-Type'] = 'application/json' 284 285 url = redfish_request.form_url(url) 286 287 logger.console(msg='', newline=True) 288 msg = "Request Method : DELETE ,headers = " + \ 289 json.dumps(headers) + " ,uri = " + str(url) + " ,data = " + \ 290 json.dumps(data) + " ,timeout = " + str(timeout) + \ 291 " ,verify = " + str(verify) 292 logger.console(msg='', newline=True) 293 294 response = requests.delete(url, headers=headers, data=data, 295 timeout=timeout, verify=verify) 296 redfish_request.log_console(response) 297 298 return response 299 300 @staticmethod 301 def dict_parse(variable, lookup_dict): 302 r""" 303 Find a variable in dict. 304 305 Description of argument(s): 306 variable Variable that need to be searched in dict. 307 lookup_dict Disctionay contains variables. 308 """ 309 310 result = lookup_dict.get(variable, None) 311 return result 312 313 @staticmethod 314 def get_target_actions(target_attribute, response): 315 r""" 316 Get target entry of the searched target attribute. 317 318 Description of argument(s): 319 target_attribute Name of the attribute (e.g. 'Manager.Reset'). 320 response Response from url. 321 322 'Actions' : { 323 '#Manager.Reset' : { 324 '@Redfish.ActionInfo' : '/redfish/v1/Managers/bmc/ResetActionInfo', 325 'target' : '/redfish/v1/Managers/bmc/Actions/Manager.Reset' 326 } 327 } 328 """ 329 330 lookup_list = ["Actions", "#" + attribute, "target"] 331 for lookup_item in lookup_list: 332 response = redfish_request.dict_parse(lookup_item, response) 333 if response is not None and type(response) is dict(): 334 continue 335 else: 336 return response 337 return None 338 339 @staticmethod 340 def get_attribute(attribute, data): 341 r""" 342 Get resource attribute. 343 344 Description of argument(s): 345 attribute Pass the attribute needs to be searched. 346 data Pass the request response. 347 """ 348 349 value = data.get(attribute, None) 350 return value 351