1#!/usr/bin/env python
2
3r"""
4See class prolog below for details.
5"""
6
7import sys
8import re
9from redfish_plus import redfish_plus
10from robot.libraries.BuiltIn import BuiltIn
11
12import func_args as fa
13import gen_print as gp
14
15
16class bmc_redfish(redfish_plus):
17    r"""
18    bmc_redfish is a child class of redfish_plus that is designed to provide
19    benefits specifically for using redfish to communicate with an OpenBMC.
20
21    See the prologs of the methods below for details.
22    """
23
24    def __init__(self, *args, **kwargs):
25        r"""
26        Do BMC-related redfish initialization.
27
28        Presently, older versions of BMC code may not support redfish
29        requests.  This can lead to unsightly error text being printed out for
30        programs that may use lib/bmc_redfish_resource.robot even though they
31        don't necessarily intend to make redfish requests.
32
33        This class method will make an attempt to tolerate this situation.  At
34        some future point, when all BMCs can be expected to support redfish,
35        this class method may be considered for deletion.  If it is deleted,
36        the self.__inited__ test code in the login() class method below should
37        likewise be deleted.
38        """
39        self.__inited__ = False
40        try:
41            super(bmc_redfish, self).__init__(*args, **kwargs)
42            self.__inited__ = True
43        except ValueError as get_exception:
44            except_type, except_value, except_traceback = sys.exc_info()
45            regex = r"The HTTP status code was not valid:[\r\n]+status:[ ]+502"
46            result = re.match(regex, str(except_value), flags=re.MULTILINE)
47            if not result:
48                gp.lprint_var(except_type)
49                gp.lprint_varx("except_value", str(except_value))
50                raise(get_exception)
51        BuiltIn().set_global_variable("${REDFISH_SUPPORTED}", self.__inited__)
52
53    def login(self, *args, **kwargs):
54        r"""
55        Assign BMC default values for username, password and auth arguments
56        and call parent class login method.
57
58        Description of argument(s):
59        args                        See parent class method prolog for details.
60        kwargs                      See parent class method prolog for details.
61        """
62
63        if not self.__inited__:
64            message = "bmc_redfish.__init__() was never successfully run.  It "
65            message += "is likely that the target BMC firmware code level "
66            message += "does not support redfish.\n"
67            raise ValueError(message)
68        # Assign default values for username, password, auth where necessary.
69        openbmc_username = BuiltIn().get_variable_value("${OPENBMC_USERNAME}")
70        openbmc_password = BuiltIn().get_variable_value("${OPENBMC_PASSWORD}")
71        username, args, kwargs = fa.pop_arg(openbmc_username, *args, **kwargs)
72        password, args, kwargs = fa.pop_arg(openbmc_password, *args, **kwargs)
73        auth, args, kwargs = fa.pop_arg('session', *args, **kwargs)
74
75        super(bmc_redfish, self).login(username, password, auth,
76                                       *args, **kwargs)
77
78    def get_properties(self, *args, **kwargs):
79        r"""
80        Return dictionary of attributes for a given path.
81
82        The difference between calling this function and calling get()
83        directly is that this function returns ONLY the dictionary portion of
84        the response object.
85
86        Example robot code:
87
88        ${properties}=  Get Properties  /redfish/v1/Systems/system/
89        Rprint Vars  properties
90
91        Output:
92
93        properties:
94          [PowerState]:      Off
95          [Processors]:
96            [@odata.id]:     /redfish/v1/Systems/system/Processors
97          [SerialNumber]:    1234567
98          ...
99
100        Description of argument(s):
101        args                        See parent class get() prolog for details.
102        kwargs                      See parent class get() prolog for details.
103        """
104
105        resp = self.get(*args, **kwargs)
106        return resp.dict if hasattr(resp, 'dict') else {}
107
108    def get_attribute(self, path, attribute, default=None, *args, **kwargs):
109        r"""
110        Get and return the named attribute from the properties for a given
111        path.
112
113        This method has the following advantages over calling get_properties
114        directly:
115        - The caller can specify a default value to be returned if the
116          attribute does not exist.
117
118        Example robot code:
119
120        ${attribute}=  Get Attribute  /redfish/v1/AccountService
121        ...  MaxPasswordLength  default=600
122        Rprint Vars  attribute
123
124        Output:
125
126        attribute:           31
127
128        Description of argument(s):
129        path                        The path (e.g.
130                                    "/redfish/v1/AccountService").
131        attribute                   The name of the attribute to be retrieved
132                                    (e.g. "MaxPasswordLength").
133        default                     The default value to be returned if the
134                                    attribute does not exist (e.g. "").
135        args                        See parent class get() prolog for details.
136        kwargs                      See parent class get() prolog for details.
137        """
138
139        return self.get_properties(path, *args, **kwargs).get(attribute,
140                                                              default)
141
142    def get_session_info(self):
143        r"""
144        Get and return session info as a tuple consisting of session_key and
145        session_location.
146        """
147
148        return self.get_session_key(), self.get_session_location()
149