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