blob: e2125ca2412c09796aadce78489086f0a44cf934 [file] [log] [blame]
George Keishinge7e91712021-09-03 11:28:44 -05001#!/usr/bin/env python3
Michael Walsh35139f92019-03-01 15:58:05 -06002
3r"""
4See redfish_plus class prolog below for details.
5"""
6
Patrick Williams57318182022-12-08 06:18:26 -06007from redfish.rest.v1 import HttpClient
George Keishinge635ddc2022-12-08 07:38:02 -06008import gen_print as gp
9import func_args as fa
10import requests
11import json
Patrick Williams57318182022-12-08 06:18:26 -060012from robot.libraries.BuiltIn import BuiltIn
Tony Lee05aa70b2021-01-28 19:18:27 +080013
George Keishinge635ddc2022-12-08 07:38:02 -060014
Tony Lee05aa70b2021-01-28 19:18:27 +080015host = BuiltIn().get_variable_value("${OPENBMC_HOST}")
16MTLS_ENABLED = BuiltIn().get_variable_value("${MTLS_ENABLED}")
17CERT_DIR_PATH = BuiltIn().get_variable_value("${CERT_DIR_PATH}")
18VALID_CERT = BuiltIn().get_variable_value("${VALID_CERT}")
Michael Walsh35139f92019-03-01 15:58:05 -060019
20
21def valid_http_status_code(status, valid_status_codes):
22 r"""
23 Raise exception if status is not found in the valid_status_codes list.
24
25 Description of argument(s):
26 status An HTTP status code (e.g. 200, 400, etc.).
Michael Walsh410b1782019-10-22 15:56:18 -050027 valid_status_codes A list of status codes that the caller considers acceptable. If this is
28 a null list, then any status code is considered acceptable. Note that
29 for the convenience of the caller, valid_status_codes may be either a
30 python list or a string which can be evaluated to become a python list
31 (e.g. "[200]").
Michael Walsh35139f92019-03-01 15:58:05 -060032 """
33
34 if type(valid_status_codes) is not list:
35 valid_status_codes = eval(valid_status_codes)
36 if len(valid_status_codes) == 0:
37 return
38 if status in valid_status_codes:
39 return
40
41 message = "The HTTP status code was not valid:\n"
42 message += gp.sprint_vars(status, valid_status_codes)
43 raise ValueError(message)
44
45
46class redfish_plus(HttpClient):
47 r"""
Michael Walsh410b1782019-10-22 15:56:18 -050048 redfish_plus is a wrapper for redfish rest that provides the following benefits vs. using redfish
49 directly:
Michael Walsh35139f92019-03-01 15:58:05 -060050
51 For rest_request functions (e.g. get, put, post, etc.):
52 - Function-call logging to stdout.
Michael Walsh410b1782019-10-22 15:56:18 -050053 - Automatic valid_status_codes processing (i.e. an exception will be raised if the rest response
54 status code is not as expected.
Michael Walsh35139f92019-03-01 15:58:05 -060055 - Easily used from robot programs.
56 """
57
George Keishinge635ddc2022-12-08 07:38:02 -060058 ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
Michael Walsh35139f92019-03-01 15:58:05 -060059
60 def rest_request(self, func, *args, **kwargs):
61 r"""
62 Perform redfish rest request and return response.
63
64 This function provides the following additional functionality.
Michael Walsh410b1782019-10-22 15:56:18 -050065 - The calling function's call line is logged to standard out (provided that global variable "quiet"
66 is not set).
Michael Walsh35139f92019-03-01 15:58:05 -060067 - The caller may include a valid_status_codes argument.
Michael Walsh410b1782019-10-22 15:56:18 -050068 - Callers may include inline python code strings to define arguments. This predominantly benefits
69 robot callers.
Michael Walsh2477e092019-05-17 15:48:56 -050070
71 For example, instead of calling like this:
72 ${data}= Create Dictionary HostName=${hostname}
73 Redfish.patch ${REDFISH_NW_PROTOCOL_URI} body=&{data}
74
75 Callers may do this:
76
77 Redfish.patch ${REDFISH_NW_PROTOCOL_URI}
78 ... body=[('HostName', '${hostname}')]
Michael Walsh35139f92019-03-01 15:58:05 -060079
80 Description of argument(s):
Michael Walsh410b1782019-10-22 15:56:18 -050081 func A reference to the parent class function which is to be called (e.g. get,
82 put, etc.).
83 args This is passed directly to the function referenced by the func argument
84 (see the documentation for the corresponding redfish HttpClient method
85 for details).
86 kwargs This is passed directly to the function referenced by the func argument
87 (see the documentation for the corresponding redfish HttpClient method
88 for details) with the following exception: If kwargs contains a
89 valid_status_codes key, it will be removed from kwargs and processed by
90 this function. This allows the caller to indicate what rest status codes
91 are acceptable. The default value is [200]. See the
92 valid_http_status_code function above for details.
Michael Walsh35139f92019-03-01 15:58:05 -060093
94 Example uses:
95
96 From a python program:
97
Michael Walsh410b1782019-10-22 15:56:18 -050098 response = bmc_redfish.get("/redfish/v1/Managers/bmc/EthernetInterfaces", [200, 201])
Michael Walsh35139f92019-03-01 15:58:05 -060099
Michael Walsh410b1782019-10-22 15:56:18 -0500100 If this call to the get method generates a response.status equal to anything other than 200 or 201,
101 an exception will be raised.
Michael Walsh35139f92019-03-01 15:58:05 -0600102
103 From a robot program:
104
105 BMC_Redfish.logout
Michael Walsh410b1782019-10-22 15:56:18 -0500106 ${response}= BMC_Redfish.Get /redfish/v1/Managers/bmc/EthernetInterfaces valid_status_codes=[401]
Michael Walsh35139f92019-03-01 15:58:05 -0600107
Michael Walsh410b1782019-10-22 15:56:18 -0500108 As part of a robot test, the programmer has logged out to verify that the get request will generate a
109 status code of 401 (i.e. "Unauthorized").
George Keishingc7c771e2021-03-30 13:27:27 -0500110
111 Timeout for GET/POST/PATCH/DELETE operations. By default 30 seconds, else user defined value.
112 Similarly, Max retry by default 10 attempt for the operation, else user defined value.
Michael Walsh35139f92019-03-01 15:58:05 -0600113 """
114 gp.qprint_executing(stack_frame_ix=3, style=gp.func_line_style_short)
Michael Walsh410b1782019-10-22 15:56:18 -0500115 # Convert python string object definitions to objects (mostly useful for robot callers).
Michael Walsh2477e092019-05-17 15:48:56 -0500116 args = fa.args_to_objects(args)
117 kwargs = fa.args_to_objects(kwargs)
George Keishinge635ddc2022-12-08 07:38:02 -0600118 timeout = kwargs.pop('timeout', 30)
George Keishingc7c771e2021-03-30 13:27:27 -0500119 self._timeout = timeout
George Keishinge635ddc2022-12-08 07:38:02 -0600120 max_retry = kwargs.pop('max_retry', 10)
George Keishingc7c771e2021-03-30 13:27:27 -0500121 self._max_retry = max_retry
George Keishinge635ddc2022-12-08 07:38:02 -0600122 valid_status_codes = kwargs.pop('valid_status_codes', [200])
Michael Walsh35139f92019-03-01 15:58:05 -0600123 response = func(*args, **kwargs)
124 valid_http_status_code(response.status, valid_status_codes)
125 return response
126
127 # Define rest function wrappers.
128 def get(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600129
130 if MTLS_ENABLED == 'True':
Tony Lee05aa70b2021-01-28 19:18:27 +0800131 return self.rest_request(self.get_with_mtls, *args, **kwargs)
132 else:
George Keishinge635ddc2022-12-08 07:38:02 -0600133 return self.rest_request(super(redfish_plus, self).get, *args,
134 **kwargs)
Michael Walsh35139f92019-03-01 15:58:05 -0600135
136 def head(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600137
138 if MTLS_ENABLED == 'True':
Tony Lee05aa70b2021-01-28 19:18:27 +0800139 return self.rest_request(self.head_with_mtls, *args, **kwargs)
140 else:
George Keishinge635ddc2022-12-08 07:38:02 -0600141 return self.rest_request(super(redfish_plus, self).head, *args,
142 **kwargs)
Michael Walsh35139f92019-03-01 15:58:05 -0600143
144 def post(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600145
146 if MTLS_ENABLED == 'True':
Tony Lee05aa70b2021-01-28 19:18:27 +0800147 return self.rest_request(self.post_with_mtls, *args, **kwargs)
148 else:
George Keishinge635ddc2022-12-08 07:38:02 -0600149 return self.rest_request(super(redfish_plus, self).post, *args,
150 **kwargs)
Michael Walsh35139f92019-03-01 15:58:05 -0600151
152 def put(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600153
154 if MTLS_ENABLED == 'True':
Tony Lee05aa70b2021-01-28 19:18:27 +0800155 return self.rest_request(self.put_with_mtls, *args, **kwargs)
156 else:
George Keishinge635ddc2022-12-08 07:38:02 -0600157 return self.rest_request(super(redfish_plus, self).put, *args,
158 **kwargs)
Michael Walsh35139f92019-03-01 15:58:05 -0600159
160 def patch(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600161
162 if MTLS_ENABLED == 'True':
Tony Lee05aa70b2021-01-28 19:18:27 +0800163 return self.rest_request(self.patch_with_mtls, *args, **kwargs)
164 else:
George Keishinge635ddc2022-12-08 07:38:02 -0600165 return self.rest_request(super(redfish_plus, self).patch, *args,
166 **kwargs)
Michael Walsh35139f92019-03-01 15:58:05 -0600167
168 def delete(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600169
170 if MTLS_ENABLED == 'True':
Tony Lee05aa70b2021-01-28 19:18:27 +0800171 return self.rest_request(self.delete_with_mtls, *args, **kwargs)
172 else:
George Keishinge635ddc2022-12-08 07:38:02 -0600173 return self.rest_request(super(redfish_plus, self).delete, *args,
174 **kwargs)
Michael Walsh35139f92019-03-01 15:58:05 -0600175
176 def __del__(self):
177 del self
Tony Lee05aa70b2021-01-28 19:18:27 +0800178
179 def get_with_mtls(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600180
181 cert_dict = kwargs.pop('certificate', {"certificate_name": VALID_CERT})
182 response = requests.get(url='https://' + host + args[0],
183 cert=CERT_DIR_PATH + '/' + cert_dict['certificate_name'],
184 verify=False,
185 headers={"Cache-Control": "no-cache"})
Tony Lee05aa70b2021-01-28 19:18:27 +0800186
187 response.status = response.status_code
188 if response.status == 200:
189 response.dict = json.loads(response.text)
190
191 return response
192
193 def post_with_mtls(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600194
195 cert_dict = kwargs.pop('certificate', {"certificate_name": VALID_CERT})
196 body = kwargs.pop('body', {})
197 response = requests.post(url='https://' + host + args[0],
198 json=body,
199 cert=CERT_DIR_PATH + '/' + cert_dict['certificate_name'],
200 verify=False,
201 headers={"Content-Type": "application/json"})
Tony Lee05aa70b2021-01-28 19:18:27 +0800202
203 response.status = response.status_code
204
205 return response
206
207 def patch_with_mtls(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600208
209 cert_dict = kwargs.pop('certificate', {"certificate_name": VALID_CERT})
210 body = kwargs.pop('body', {})
211 response = requests.patch(url='https://' + host + args[0],
212 json=body,
213 cert=CERT_DIR_PATH + '/' + cert_dict['certificate_name'],
214 verify=False,
215 headers={"Content-Type": "application/json"})
Tony Lee05aa70b2021-01-28 19:18:27 +0800216
217 response.status = response.status_code
218
219 return response
220
221 def delete_with_mtls(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600222
223 cert_dict = kwargs.pop('certificate', {"certificate_name": VALID_CERT})
224 response = requests.delete(url='https://' + host + args[0],
225 cert=CERT_DIR_PATH + '/' + cert_dict['certificate_name'],
226 verify=False,
227 headers={"Content-Type": "application/json"})
Tony Lee05aa70b2021-01-28 19:18:27 +0800228
229 response.status = response.status_code
230
231 return response
232
233 def put_with_mtls(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600234
235 cert_dict = kwargs.pop('certificate', {"certificate_name": VALID_CERT})
236 body = kwargs.pop('body', {})
237 response = requests.put(url='https://' + host + args[0],
238 json=body,
239 cert=CERT_DIR_PATH + '/' + cert_dict['certificate_name'],
240 verify=False,
241 headers={"Content-Type": "application/json"})
Tony Lee05aa70b2021-01-28 19:18:27 +0800242
243 response.status = response.status_code
244
245 return response
246
247 def head_with_mtls(self, *args, **kwargs):
George Keishinge635ddc2022-12-08 07:38:02 -0600248
249 cert_dict = kwargs.pop('certificate', {"certificate_name": VALID_CERT})
250 body = kwargs.pop('body', {})
251 response = requests.head(url='https://' + host + args[0],
252 json=body,
253 cert=CERT_DIR_PATH + '/' + cert_dict['certificate_name'],
254 verify=False,
255 headers={"Content-Type": "application/json"})
Tony Lee05aa70b2021-01-28 19:18:27 +0800256
257 response.status = response.status_code
258
259 return response