1#!/usr/bin/env python
2
3r"""
4BMC redfish utility functions.
5"""
6
7import json
8from robot.libraries.BuiltIn import BuiltIn
9import gen_print as gp
10
11
12class bmc_redfish_utils(object):
13
14    def __init__(self):
15        r"""
16        Initialize the bmc_redfish_utils object.
17        """
18        # Obtain a reference to the global redfish object.
19        self._redfish_ = BuiltIn().get_library_instance('redfish')
20
21    def get_redfish_session_info(self):
22        r"""
23        Returns redfish sessions info dictionary.
24
25        {
26            'key': 'yLXotJnrh5nDhXj5lLiH' ,
27            'location': '/redfish/v1/SessionService/Sessions/nblYY4wlz0'
28        }
29        """
30        session_dict = {
31            "key": self._redfish_.get_session_key(),
32            "location": self._redfish_.get_session_location()
33        }
34        return session_dict
35
36    def get_attribute(self, resource_path, attribute):
37        r"""
38        Get resource attribute.
39
40        Description of argument(s):
41        resource_path               URI resource absolute path (e.g.
42                                    "/redfish/v1/Systems/1").
43        attribute                   Name of the attribute (e.g. 'PowerState').
44        """
45
46        resp = self._redfish_.get(resource_path)
47        if attribute in resp.dict:
48            return resp.dict[attribute]
49
50        return None
51
52    def get_properties(self, resource_path):
53        r"""
54        Returns dictionary of attributes for the resource.
55
56        Description of argument(s):
57        resource_path               URI resource absolute path (e.g.
58                                    "/redfish/v1/Systems/1").
59        """
60
61        resp = self._redfish_.get(resource_path)
62        return resp.dict
63
64    def get_target_actions(self, resource_path, target_attribute):
65        r"""
66        Returns resource target entry of the searched target attribute.
67
68        Description of argument(s):
69        resource_path      URI resource absolute path
70                           (e.g. "/redfish/v1/Systems/system").
71        target_attribute   Name of the attribute (e.g. 'ComputerSystem.Reset').
72
73        Example:
74         "Actions": {
75         "#ComputerSystem.Reset": {
76          "ResetType@Redfish.AllowableValues": [
77            "On",
78            "ForceOff",
79            "GracefulRestart",
80            "GracefulShutdown"
81          ],
82          "target": "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"
83          }
84         }
85        """
86
87        global target_list
88        target_list = []
89
90        resp_dict = self.get_attribute(resource_path, "Actions")
91        if resp_dict is None:
92            return None
93
94        # Recursively search the "target" key in the nested dictionary.
95        # Populate the target_list of target entries.
96        self.get_key_value_nested_dict(resp_dict, "target")
97
98        # Return the matching target URL entry.
99        for target in target_list:
100            # target "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"
101            if target_attribute in target:
102                return target
103
104        return None
105
106    def get_member_list(self, resource_path):
107        r"""
108        Perform a GET list request and return available members entries.
109
110        Description of argument(s):
111        resource_path  URI resource absolute path
112                       (e.g. "/redfish/v1/SessionService/Sessions").
113
114        "Members": [
115            {
116              "@odata.id": "/redfish/v1/SessionService/Sessions/Z5HummWPZ7"
117            }
118            {
119              "@odata.id": "/redfish/v1/SessionService/Sessions/46CmQmEL7H"
120            }
121          ],
122        """
123
124        member_list = []
125        resp_list_dict = self.get_attribute(resource_path, "Members")
126        if resp_list_dict is None:
127            return member_list
128
129        for member_id in range(0, len(resp_list_dict)):
130            member_list.append(resp_list_dict[member_id]["@odata.id"])
131
132        return member_list
133
134    def list_request(self, resource_path):
135        r"""
136        Perform a GET list request and return available resource paths.
137
138        Description of argument(s):
139        resource_path  URI resource absolute path
140                       (e.g. "/redfish/v1/SessionService/Sessions").
141        """
142
143        gp.qprint_executing(style=gp.func_line_style_short)
144
145        # Set quiet variable to keep subordinate get() calls quiet.
146        quiet = 1
147
148        global resource_list
149        resource_list = []
150        self._rest_response_ = \
151            self._redfish_.get(resource_path,
152                               valid_status_codes=[200, 404, 500])
153
154        # Return empty list.
155        if self._rest_response_.status != 200:
156            return resource_list
157
158        self.walk_nested_dict(self._rest_response_.dict)
159
160        if not resource_list:
161            return uri_path
162
163        for resource in resource_list:
164            self._rest_response_ = \
165                self._redfish_.get(resource,
166                                   valid_status_codes=[200, 404, 500])
167            if self._rest_response_.status != 200:
168                continue
169            self.walk_nested_dict(self._rest_response_.dict)
170
171        resource_list.sort()
172        return resource_list
173
174    def enumerate_request(self, resource_path):
175        r"""
176        Perform a GET enumerate request and return available resource paths.
177
178        Description of argument(s):
179        resource_path  URI resource absolute path
180                       (e.g. "/redfish/v1/SessionService/Sessions").
181        """
182
183        gp.qprint_executing(style=gp.func_line_style_short)
184
185        # Set quiet variable to keep subordinate get() calls quiet.
186        quiet = 1
187
188        url_list = self.list_request(resource_path)
189
190        resource_dict = {}
191
192        # Return empty dict.
193        if not url_list:
194            return resource_dict
195
196        for resource in url_list:
197            # JsonSchemas data are not required in enumeration.
198            # Example: '/redfish/v1/JsonSchemas/' and sub resources.
199            if 'JsonSchemas' in resource:
200                continue
201            self._rest_response_ = \
202                self._redfish_.get(resource,
203                                   valid_status_codes=[200, 404, 500])
204            if self._rest_response_.status != 200:
205                continue
206            resource_dict[resource] = self._rest_response_.dict
207
208        return json.dumps(resource_dict, sort_keys=True,
209                          indent=4, separators=(',', ': '))
210
211    def walk_nested_dict(self, data):
212        r"""
213        Parse through the nested dictionary and get the resource id paths.
214
215        Description of argument(s):
216        data    Nested dictionary data from response message.
217        """
218
219        for key, value in data.items():
220            if isinstance(value, dict):
221                self.walk_nested_dict(value)
222            else:
223                if 'Members' == key:
224                    if isinstance(value, list):
225                        for index in value:
226                            if index['@odata.id'] not in resource_list:
227                                resource_list.append(index['@odata.id'])
228                if '@odata.id' == key:
229                    if value not in resource_list and not value.endswith('/'):
230                        resource_list.append(value)
231
232    def get_key_value_nested_dict(self, data, key):
233        r"""
234        Parse through the nested dictionary and get the searched key value.
235
236        Description of argument(s):
237        data    Nested dictionary data from response message.
238        key     Search dictionary key element.
239        """
240
241        for k, v in data.items():
242            if isinstance(v, dict):
243                self.get_key_value_nested_dict(v, key)
244
245            if k == key:
246                target_list.append(v)
247