blob: 4d421b5702fa625dc1f79f1f48f9367ce38495cc [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
Anusha Dathatriff9240b2019-04-02 05:14:46 -050070 (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 Dathatriff9240b2019-04-02 05:14:46 -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 Dathatriff9240b2019-04-02 05:14:46 -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
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500112 (e.g. "/redfish/v1/SessionService/Sessions").
George Keishingdabf38f2019-03-10 09:52:40 -0500113
114 "Members": [
115 {
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500116 "@odata.id": "/redfish/v1/SessionService/Sessions/Z5HummWPZ7"
George Keishingdabf38f2019-03-10 09:52:40 -0500117 }
118 {
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500119 "@odata.id": "/redfish/v1/SessionService/Sessions/46CmQmEL7H"
George Keishingdabf38f2019-03-10 09:52:40 -0500120 }
Anusha Dathatriff9240b2019-04-02 05:14:46 -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.
137
138 Description of argument(s):
139 resource_path URI resource absolute path
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500140 (e.g. "/redfish/v1/SessionService/Sessions").
George Keishingf2613b72019-02-13 12:45:59 -0600141 """
142
Michael Walshc86a2f72019-03-19 13:24:37 -0500143 gp.qprint_executing(style=gp.func_line_style_short)
144
145 # Set quiet variable to keep subordinate get() calls quiet.
146 quiet = 1
147
George Keishingf2613b72019-02-13 12:45:59 -0600148 global resource_list
149 resource_list = []
Michael Walshc86a2f72019-03-19 13:24:37 -0500150 self._rest_response_ = \
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500151 self._redfish_.get(resource_path, valid_status_codes=[200, 404, 500])
George Keishingf2613b72019-02-13 12:45:59 -0600152
153 # Return empty list.
154 if self._rest_response_.status != 200:
155 return resource_list
156
157 self.walk_nested_dict(self._rest_response_.dict)
158
159 if not resource_list:
160 return uri_path
161
162 for resource in resource_list:
Michael Walshc86a2f72019-03-19 13:24:37 -0500163 self._rest_response_ = \
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500164 self._redfish_.get(resource, valid_status_codes=[200, 404, 500])
George Keishingf2613b72019-02-13 12:45:59 -0600165 if self._rest_response_.status != 200:
166 continue
167 self.walk_nested_dict(self._rest_response_.dict)
168
169 resource_list.sort()
170 return resource_list
171
172 def enumerate_request(self, resource_path):
173 r"""
174 Perform a GET enumerate request and return available resource paths.
175
176 Description of argument(s):
177 resource_path URI resource absolute path
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500178 (e.g. "/redfish/v1/SessionService/Sessions").
George Keishingf2613b72019-02-13 12:45:59 -0600179 """
180
Michael Walshc86a2f72019-03-19 13:24:37 -0500181 gp.qprint_executing(style=gp.func_line_style_short)
182
183 # Set quiet variable to keep subordinate get() calls quiet.
184 quiet = 1
185
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500186 # Variable to hold enumerated data.
187 self.__result = {}
George Keishingf2613b72019-02-13 12:45:59 -0600188
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500189 # Variable to hold the pending list of resources for which enumeration.
190 # is yet to be obtained.
191 self.__pending_enumeration = set()
George Keishingf2613b72019-02-13 12:45:59 -0600192
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500193 self.__pending_enumeration.add(resource_path)
George Keishingf2613b72019-02-13 12:45:59 -0600194
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500195 # Variable having resources for which enumeration is completed.
196 enumerated_resources = set()
George Keishingf2613b72019-02-13 12:45:59 -0600197
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500198 resources_to_be_enumerated = (resource_path,)
199
200 while resources_to_be_enumerated:
201 for resource in resources_to_be_enumerated:
202 # JsonSchemas data are not required in enumeration.
203 # Example: '/redfish/v1/JsonSchemas/' and sub resources.
204 if 'JsonSchemas' in resource:
205 continue
206
207 self._rest_response_ = \
208 self._redfish_.get(resource, valid_status_codes=[200, 404, 500])
209 # Enumeration is done for available resources ignoring the
210 # ones for which response is not obtained.
211 if self._rest_response_.status != 200:
212 continue
213
214 self.walk_nested_dict(self._rest_response_.dict, resource)
215
216 enumerated_resources.update(set(resources_to_be_enumerated))
217 resources_to_be_enumerated = \
218 tuple(self.__pending_enumeration - enumerated_resources)
219
220 return json.dumps(self.__result, sort_keys=True,
George Keishingf2613b72019-02-13 12:45:59 -0600221 indent=4, separators=(',', ': '))
222
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500223 def walk_nested_dict(self, data, url=''):
George Keishingf2613b72019-02-13 12:45:59 -0600224 r"""
225 Parse through the nested dictionary and get the resource id paths.
226
227 Description of argument(s):
228 data Nested dictionary data from response message.
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500229 url Resource for which the response is obtained in data.
George Keishingf2613b72019-02-13 12:45:59 -0600230 """
231
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500232 url = url.rstrip('/')
George Keishingf2613b72019-02-13 12:45:59 -0600233 for key, value in data.items():
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500234 # Recursion if nested dictionary found.
George Keishingf2613b72019-02-13 12:45:59 -0600235 if isinstance(value, dict):
236 self.walk_nested_dict(value)
237 else:
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500238 # Value contains a list of dictionaries having member data.
George Keishingf2613b72019-02-13 12:45:59 -0600239 if 'Members' == key:
240 if isinstance(value, list):
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500241 for memberDict in value:
242 self.__pending_enumeration.add(memberDict['@odata.id'])
George Keishingf2613b72019-02-13 12:45:59 -0600243 if '@odata.id' == key:
Anusha Dathatriff9240b2019-04-02 05:14:46 -0500244 value = value.rstrip('/')
245 # Data for the given url.
246 if value == url:
247 self.__result[url] = data
248 # Data still needs to be looked up,
249 else:
250 self.__pending_enumeration.add(value)
George Keishing7ec45932019-02-27 14:02:16 -0600251
252 def get_key_value_nested_dict(self, data, key):
253 r"""
254 Parse through the nested dictionary and get the searched key value.
255
256 Description of argument(s):
257 data Nested dictionary data from response message.
258 key Search dictionary key element.
259 """
260
261 for k, v in data.items():
262 if isinstance(v, dict):
263 self.get_key_value_nested_dict(v, key)
264
265 if k == key:
266 target_list.append(v)