1#!/usr/bin/env python
2
3r"""
4See redfish_plus class prolog below for details.
5"""
6
7from redfish.rest.v1 import HttpClient
8import gen_print as gp
9import func_args as fa
10
11
12def valid_http_status_code(status, valid_status_codes):
13    r"""
14    Raise exception if status is not found in the valid_status_codes list.
15
16    Description of argument(s):
17    status                          An HTTP status code (e.g. 200, 400, etc.).
18    valid_status_codes              A list of status codes that the caller considers acceptable.  If this is
19                                    a null list, then any status code is considered acceptable.  Note that
20                                    for the convenience of the caller, valid_status_codes may be either a
21                                    python list or a string which can be evaluated to become a python list
22                                    (e.g. "[200]").
23    """
24
25    if type(valid_status_codes) is not list:
26        valid_status_codes = eval(valid_status_codes)
27    if len(valid_status_codes) == 0:
28        return
29    if status in valid_status_codes:
30        return
31
32    message = "The HTTP status code was not valid:\n"
33    message += gp.sprint_vars(status, valid_status_codes)
34    raise ValueError(message)
35
36
37class redfish_plus(HttpClient):
38    r"""
39    redfish_plus is a wrapper for redfish rest that provides the following benefits vs. using redfish
40    directly:
41
42    For rest_request functions (e.g. get, put, post, etc.):
43        - Function-call logging to stdout.
44        - Automatic valid_status_codes processing (i.e. an exception will be raised if the rest response
45          status code is not as expected.
46        - Easily used from robot programs.
47    """
48
49    ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
50
51    def rest_request(self, func, *args, **kwargs):
52        r"""
53        Perform redfish rest request and return response.
54
55        This function provides the following additional functionality.
56        - The calling function's call line is logged to standard out (provided that global variable "quiet"
57          is not set).
58        - The caller may include a valid_status_codes argument.
59        - Callers may include inline python code strings to define arguments.  This predominantly benefits
60          robot callers.
61
62          For example, instead of calling like this:
63            ${data}=  Create Dictionary  HostName=${hostname}
64            Redfish.patch  ${REDFISH_NW_PROTOCOL_URI}  body=&{data}
65
66          Callers may do this:
67
68            Redfish.patch  ${REDFISH_NW_PROTOCOL_URI}
69            ...  body=[('HostName', '${hostname}')]
70
71        Description of argument(s):
72        func                        A reference to the parent class function which is to be called (e.g. get,
73                                    put, etc.).
74        args                        This is passed directly to the function referenced by the func argument
75                                    (see the documentation for the corresponding redfish HttpClient method
76                                    for details).
77        kwargs                      This is passed directly to the function referenced by the func argument
78                                    (see the documentation for the corresponding redfish HttpClient method
79                                    for details) with the following exception:  If kwargs contains a
80                                    valid_status_codes key, it will be removed from kwargs and processed by
81                                    this function.  This allows the caller to indicate what rest status codes
82                                    are acceptable.  The default value is [200].  See the
83                                    valid_http_status_code function above for details.
84
85        Example uses:
86
87        From a python program:
88
89        response = bmc_redfish.get("/redfish/v1/Managers/bmc/EthernetInterfaces", [200, 201])
90
91        If this call to the get method generates a response.status equal to anything other than 200 or 201,
92        an exception will be raised.
93
94        From a robot program:
95
96        BMC_Redfish.logout
97        ${response}=  BMC_Redfish.Get  /redfish/v1/Managers/bmc/EthernetInterfaces  valid_status_codes=[401]
98
99        As part of a robot test, the programmer has logged out to verify that the get request will generate a
100        status code of 401 (i.e. "Unauthorized").
101        """
102        gp.qprint_executing(stack_frame_ix=3, style=gp.func_line_style_short)
103        # Convert python string object definitions to objects (mostly useful for robot callers).
104        args = fa.args_to_objects(args)
105        kwargs = fa.args_to_objects(kwargs)
106        valid_status_codes = kwargs.pop('valid_status_codes', [200])
107        response = func(*args, **kwargs)
108        valid_http_status_code(response.status, valid_status_codes)
109        return response
110
111    # Define rest function wrappers.
112    def get(self, *args, **kwargs):
113        return self.rest_request(super(redfish_plus, self).get, *args,
114                                 **kwargs)
115
116    def head(self, *args, **kwargs):
117        return self.rest_request(super(redfish_plus, self).head, *args,
118                                 **kwargs)
119
120    def post(self, *args, **kwargs):
121        return self.rest_request(super(redfish_plus, self).post, *args,
122                                 **kwargs)
123
124    def put(self, *args, **kwargs):
125        return self.rest_request(super(redfish_plus, self).put, *args,
126                                 **kwargs)
127
128    def patch(self, *args, **kwargs):
129        return self.rest_request(super(redfish_plus, self).patch, *args,
130                                 **kwargs)
131
132    def delete(self, *args, **kwargs):
133        return self.rest_request(super(redfish_plus, self).delete, *args,
134                                 **kwargs)
135
136    def __del__(self):
137        del self
138