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