blob: 9df9cdfde90d3f2872474517de6955e6f367a7fa [file] [log] [blame]
George Keishingf2613b72019-02-13 12:45:59 -06001#!/usr/bin/env python
2
3r"""
4BMC redfish utility functions.
5"""
6
7import json
8from robot.libraries.BuiltIn import BuiltIn
Michael Walshc86a2f72019-03-19 13:24:37 -05009import gen_print as gp
George Keishingf2613b72019-02-13 12:45:59 -060010
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
George Keishing374e6842019-02-20 08:57:18 -060021 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 = {
George Keishing97c93942019-03-04 12:45:07 -060031 "key": self._redfish_.get_session_key(),
32 "location": self._redfish_.get_session_location()
George Keishing374e6842019-02-20 08:57:18 -060033 }
34 return session_dict
35
George Keishingf2613b72019-02-13 12:45:59 -060036 def get_attribute(self, resource_path, attribute):
37 r"""
38 Get resource attribute.
39
40 Description of argument(s):
Michael Walshc86a2f72019-03-19 13:24:37 -050041 resource_path URI resource absolute path (e.g.
42 "/redfish/v1/Systems/1").
43 attribute Name of the attribute (e.g. 'PowerState').
George Keishingf2613b72019-02-13 12:45:59 -060044 """
45
46 resp = self._redfish_.get(resource_path)
47 if attribute in resp.dict:
48 return resp.dict[attribute]
49
50 return None
51
George Keishingc3c05c22019-02-19 01:04:54 -060052 def get_properties(self, resource_path):
53 r"""
54 Returns dictionary of attributes for the resource.
55
56 Description of argument(s):
Michael Walshc86a2f72019-03-19 13:24:37 -050057 resource_path URI resource absolute path (e.g.
58 "/redfish/v1/Systems/1").
George Keishingc3c05c22019-02-19 01:04:54 -060059 """
60
61 resp = self._redfish_.get(resource_path)
62 return resp.dict
63
George Keishing7ec45932019-02-27 14:02:16 -060064 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
George Keishingf8acde92019-04-19 19:46:48 +000070 (e.g. "/redfish/v1/Systems/system").
George Keishing7ec45932019-02-27 14:02:16 -060071 target_attribute Name of the attribute (e.g. 'ComputerSystem.Reset').
72
73 Example:
Anusha Dathatri62dfb862019-04-23 06:52:16 -050074 "Actions": {
75 "#ComputerSystem.Reset": {
76 "ResetType@Redfish.AllowableValues": [
George Keishing7ec45932019-02-27 14:02:16 -060077 "On",
78 "ForceOff",
79 "GracefulRestart",
80 "GracefulShutdown"
Anusha Dathatri62dfb862019-04-23 06:52:16 -050081 ],
82 "target": "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"
83 }
84 }
George Keishing7ec45932019-02-27 14:02:16 -060085 """
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
George Keishingdabf38f2019-03-10 09:52:40 -0500106 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
George Keishingf8acde92019-04-19 19:46:48 +0000112 (e.g. "/redfish/v1/SessionService/Sessions").
George Keishingdabf38f2019-03-10 09:52:40 -0500113
114 "Members": [
115 {
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500116 "@odata.id": "/redfish/v1/SessionService/Sessions/Z5HummWPZ7"
George Keishingdabf38f2019-03-10 09:52:40 -0500117 }
118 {
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500119 "@odata.id": "/redfish/v1/SessionService/Sessions/46CmQmEL7H"
George Keishingdabf38f2019-03-10 09:52:40 -0500120 }
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500121 ],
George Keishingdabf38f2019-03-10 09:52:40 -0500122 """
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
George Keishingf2613b72019-02-13 12:45:59 -0600134 def list_request(self, resource_path):
135 r"""
136 Perform a GET list request and return available resource paths.
George Keishingf2613b72019-02-13 12:45:59 -0600137 Description of argument(s):
138 resource_path URI resource absolute path
George Keishingf8acde92019-04-19 19:46:48 +0000139 (e.g. "/redfish/v1/SessionService/Sessions").
George Keishingf2613b72019-02-13 12:45:59 -0600140 """
Michael Walshc86a2f72019-03-19 13:24:37 -0500141 gp.qprint_executing(style=gp.func_line_style_short)
Michael Walshc86a2f72019-03-19 13:24:37 -0500142 # Set quiet variable to keep subordinate get() calls quiet.
143 quiet = 1
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500144 self.__pending_enumeration = set()
Michael Walshc86a2f72019-03-19 13:24:37 -0500145 self._rest_response_ = \
George Keishingf8acde92019-04-19 19:46:48 +0000146 self._redfish_.get(resource_path,
147 valid_status_codes=[200, 404, 500])
George Keishingf2613b72019-02-13 12:45:59 -0600148
149 # Return empty list.
150 if self._rest_response_.status != 200:
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500151 return self.__pending_enumeration
George Keishingf2613b72019-02-13 12:45:59 -0600152 self.walk_nested_dict(self._rest_response_.dict)
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500153 if not self.__pending_enumeration:
154 return resource_path
155 for resource in self.__pending_enumeration.copy():
Michael Walshc86a2f72019-03-19 13:24:37 -0500156 self._rest_response_ = \
George Keishingf8acde92019-04-19 19:46:48 +0000157 self._redfish_.get(resource,
158 valid_status_codes=[200, 404, 500])
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500159
George Keishingf2613b72019-02-13 12:45:59 -0600160 if self._rest_response_.status != 200:
161 continue
162 self.walk_nested_dict(self._rest_response_.dict)
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500163 return list(sorted(self.__pending_enumeration))
George Keishingf2613b72019-02-13 12:45:59 -0600164
Michael Walsh37e028f2019-05-22 16:16:32 -0500165 def enumerate_request(self, resource_path, return_json=1):
George Keishingf2613b72019-02-13 12:45:59 -0600166 r"""
167 Perform a GET enumerate request and return available resource paths.
168
169 Description of argument(s):
Michael Walsh37e028f2019-05-22 16:16:32 -0500170 resource_path URI resource absolute path (e.g.
171 "/redfish/v1/SessionService/Sessions").
172 return_json Indicates whether the result should be
173 returned as a json string or as a
174 dictionary.
George Keishingf2613b72019-02-13 12:45:59 -0600175 """
176
Michael Walshc86a2f72019-03-19 13:24:37 -0500177 gp.qprint_executing(style=gp.func_line_style_short)
178
Michael Walsh37e028f2019-05-22 16:16:32 -0500179 return_json = int(return_json)
180
Michael Walshc86a2f72019-03-19 13:24:37 -0500181 # Set quiet variable to keep subordinate get() calls quiet.
182 quiet = 1
183
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500184 # Variable to hold enumerated data.
185 self.__result = {}
George Keishingf2613b72019-02-13 12:45:59 -0600186
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500187 # Variable to hold the pending list of resources for which enumeration.
188 # is yet to be obtained.
189 self.__pending_enumeration = set()
George Keishingf2613b72019-02-13 12:45:59 -0600190
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500191 self.__pending_enumeration.add(resource_path)
George Keishingf2613b72019-02-13 12:45:59 -0600192
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500193 # Variable having resources for which enumeration is completed.
194 enumerated_resources = set()
George Keishingf2613b72019-02-13 12:45:59 -0600195
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500196 resources_to_be_enumerated = (resource_path,)
197
198 while resources_to_be_enumerated:
199 for resource in resources_to_be_enumerated:
200 # JsonSchemas data are not required in enumeration.
201 # Example: '/redfish/v1/JsonSchemas/' and sub resources.
202 if 'JsonSchemas' in resource:
203 continue
204
205 self._rest_response_ = \
206 self._redfish_.get(resource, valid_status_codes=[200, 404, 500])
207 # Enumeration is done for available resources ignoring the
208 # ones for which response is not obtained.
209 if self._rest_response_.status != 200:
210 continue
211
212 self.walk_nested_dict(self._rest_response_.dict, url=resource)
213
214 enumerated_resources.update(set(resources_to_be_enumerated))
215 resources_to_be_enumerated = \
216 tuple(self.__pending_enumeration - enumerated_resources)
217
Michael Walsh37e028f2019-05-22 16:16:32 -0500218 if return_json:
219 return json.dumps(self.__result, sort_keys=True,
220 indent=4, separators=(',', ': '))
221 else:
222 return self.__result
George Keishingf2613b72019-02-13 12:45:59 -0600223
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500224 def walk_nested_dict(self, data, url=''):
George Keishingf2613b72019-02-13 12:45:59 -0600225 r"""
226 Parse through the nested dictionary and get the resource id paths.
George Keishingf2613b72019-02-13 12:45:59 -0600227 Description of argument(s):
228 data Nested dictionary data from response message.
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500229 url Resource for which the response is obtained in data.
George Keishingf2613b72019-02-13 12:45:59 -0600230 """
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500231 url = url.rstrip('/')
George Keishingf2613b72019-02-13 12:45:59 -0600232
233 for key, value in data.items():
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500234
235 # Recursion if nested dictionary found.
George Keishingf2613b72019-02-13 12:45:59 -0600236 if isinstance(value, dict):
237 self.walk_nested_dict(value)
238 else:
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500239 # Value contains a list of dictionaries having member data.
George Keishingf2613b72019-02-13 12:45:59 -0600240 if 'Members' == key:
241 if isinstance(value, list):
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500242 for memberDict in value:
243 self.__pending_enumeration.add(memberDict['@odata.id'])
George Keishingf2613b72019-02-13 12:45:59 -0600244 if '@odata.id' == key:
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500245 value = value.rstrip('/')
246 # Data for the given url.
247 if value == url:
248 self.__result[url] = data
249 # Data still needs to be looked up,
250 else:
251 self.__pending_enumeration.add(value)
George Keishing7ec45932019-02-27 14:02:16 -0600252
253 def get_key_value_nested_dict(self, data, key):
254 r"""
255 Parse through the nested dictionary and get the searched key value.
256
257 Description of argument(s):
258 data Nested dictionary data from response message.
259 key Search dictionary key element.
260 """
261
262 for k, v in data.items():
263 if isinstance(v, dict):
264 self.get_key_value_nested_dict(v, key)
265
266 if k == key:
267 target_list.append(v)