blob: 1efc9d7d48f060423d1185926073d1cf2f025d97 [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
165 def enumerate_request(self, resource_path):
166 r"""
167 Perform a GET enumerate request and return available resource paths.
168
169 Description of argument(s):
170 resource_path URI resource absolute path
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500171 (e.g. "/redfish/v1/SessionService/Sessions").
George Keishingf2613b72019-02-13 12:45:59 -0600172 """
173
Michael Walshc86a2f72019-03-19 13:24:37 -0500174 gp.qprint_executing(style=gp.func_line_style_short)
175
176 # Set quiet variable to keep subordinate get() calls quiet.
177 quiet = 1
178
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500179 # Variable to hold enumerated data.
180 self.__result = {}
George Keishingf2613b72019-02-13 12:45:59 -0600181
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500182 # Variable to hold the pending list of resources for which enumeration.
183 # is yet to be obtained.
184 self.__pending_enumeration = set()
George Keishingf2613b72019-02-13 12:45:59 -0600185
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500186 self.__pending_enumeration.add(resource_path)
George Keishingf2613b72019-02-13 12:45:59 -0600187
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500188 # Variable having resources for which enumeration is completed.
189 enumerated_resources = set()
George Keishingf2613b72019-02-13 12:45:59 -0600190
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500191 resources_to_be_enumerated = (resource_path,)
192
193 while resources_to_be_enumerated:
194 for resource in resources_to_be_enumerated:
195 # JsonSchemas data are not required in enumeration.
196 # Example: '/redfish/v1/JsonSchemas/' and sub resources.
197 if 'JsonSchemas' in resource:
198 continue
199
200 self._rest_response_ = \
201 self._redfish_.get(resource, valid_status_codes=[200, 404, 500])
202 # Enumeration is done for available resources ignoring the
203 # ones for which response is not obtained.
204 if self._rest_response_.status != 200:
205 continue
206
207 self.walk_nested_dict(self._rest_response_.dict, url=resource)
208
209 enumerated_resources.update(set(resources_to_be_enumerated))
210 resources_to_be_enumerated = \
211 tuple(self.__pending_enumeration - enumerated_resources)
212
213 return json.dumps(self.__result, sort_keys=True,
George Keishingf2613b72019-02-13 12:45:59 -0600214 indent=4, separators=(',', ': '))
215
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500216 def walk_nested_dict(self, data, url=''):
George Keishingf2613b72019-02-13 12:45:59 -0600217 r"""
218 Parse through the nested dictionary and get the resource id paths.
George Keishingf2613b72019-02-13 12:45:59 -0600219 Description of argument(s):
220 data Nested dictionary data from response message.
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500221 url Resource for which the response is obtained in data.
George Keishingf2613b72019-02-13 12:45:59 -0600222 """
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500223 url = url.rstrip('/')
George Keishingf2613b72019-02-13 12:45:59 -0600224
225 for key, value in data.items():
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500226
227 # Recursion if nested dictionary found.
George Keishingf2613b72019-02-13 12:45:59 -0600228 if isinstance(value, dict):
229 self.walk_nested_dict(value)
230 else:
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500231 # Value contains a list of dictionaries having member data.
George Keishingf2613b72019-02-13 12:45:59 -0600232 if 'Members' == key:
233 if isinstance(value, list):
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500234 for memberDict in value:
235 self.__pending_enumeration.add(memberDict['@odata.id'])
George Keishingf2613b72019-02-13 12:45:59 -0600236 if '@odata.id' == key:
Anusha Dathatri62dfb862019-04-23 06:52:16 -0500237 value = value.rstrip('/')
238 # Data for the given url.
239 if value == url:
240 self.__result[url] = data
241 # Data still needs to be looked up,
242 else:
243 self.__pending_enumeration.add(value)
George Keishing7ec45932019-02-27 14:02:16 -0600244
245 def get_key_value_nested_dict(self, data, key):
246 r"""
247 Parse through the nested dictionary and get the searched key value.
248
249 Description of argument(s):
250 data Nested dictionary data from response message.
251 key Search dictionary key element.
252 """
253
254 for k, v in data.items():
255 if isinstance(v, dict):
256 self.get_key_value_nested_dict(v, key)
257
258 if k == key:
259 target_list.append(v)