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