1#!/usr/bin/env python3
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