blob: 47ef3c688aafb16ebd6da231206481b70e469373 [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:
George Keishingf8acde92019-04-19 19:46:48 +000074 "Actions": {
75 "#ComputerSystem.Reset": {
76 "ResetType@Redfish.AllowableValues": [
George Keishing7ec45932019-02-27 14:02:16 -060077 "On",
78 "ForceOff",
79 "GracefulRestart",
80 "GracefulShutdown"
George Keishingf8acde92019-04-19 19:46:48 +000081 ],
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 {
George Keishingf8acde92019-04-19 19:46:48 +0000116 "@odata.id": "/redfish/v1/SessionService/Sessions/Z5HummWPZ7"
George Keishingdabf38f2019-03-10 09:52:40 -0500117 }
118 {
George Keishingf8acde92019-04-19 19:46:48 +0000119 "@odata.id": "/redfish/v1/SessionService/Sessions/46CmQmEL7H"
George Keishingdabf38f2019-03-10 09:52:40 -0500120 }
George Keishingf8acde92019-04-19 19:46:48 +0000121 ],
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
George Keishingf8acde92019-04-19 19:46:48 +0000140 (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_ = \
George Keishingf8acde92019-04-19 19:46:48 +0000151 self._redfish_.get(resource_path,
152 valid_status_codes=[200, 404, 500])
George Keishingf2613b72019-02-13 12:45:59 -0600153
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:
Michael Walshc86a2f72019-03-19 13:24:37 -0500164 self._rest_response_ = \
George Keishingf8acde92019-04-19 19:46:48 +0000165 self._redfish_.get(resource,
166 valid_status_codes=[200, 404, 500])
George Keishingf2613b72019-02-13 12:45:59 -0600167 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
George Keishingf8acde92019-04-19 19:46:48 +0000180 (e.g. "/redfish/v1/SessionService/Sessions").
George Keishingf2613b72019-02-13 12:45:59 -0600181 """
182
Michael Walshc86a2f72019-03-19 13:24:37 -0500183 gp.qprint_executing(style=gp.func_line_style_short)
184
185 # Set quiet variable to keep subordinate get() calls quiet.
186 quiet = 1
187
George Keishingf8acde92019-04-19 19:46:48 +0000188 url_list = self.list_request(resource_path)
George Keishingf2613b72019-02-13 12:45:59 -0600189
George Keishingf8acde92019-04-19 19:46:48 +0000190 resource_dict = {}
George Keishingf2613b72019-02-13 12:45:59 -0600191
George Keishingf8acde92019-04-19 19:46:48 +0000192 # Return empty dict.
193 if not url_list:
194 return resource_dict
George Keishingf2613b72019-02-13 12:45:59 -0600195
George Keishingf8acde92019-04-19 19:46:48 +0000196 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
George Keishingf2613b72019-02-13 12:45:59 -0600207
George Keishingf8acde92019-04-19 19:46:48 +0000208 return json.dumps(resource_dict, sort_keys=True,
George Keishingf2613b72019-02-13 12:45:59 -0600209 indent=4, separators=(',', ': '))
210
George Keishingf8acde92019-04-19 19:46:48 +0000211 def walk_nested_dict(self, data):
George Keishingf2613b72019-02-13 12:45:59 -0600212 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):
George Keishingf8acde92019-04-19 19:46:48 +0000225 for index in value:
226 if index['@odata.id'] not in resource_list:
227 resource_list.append(index['@odata.id'])
George Keishingf2613b72019-02-13 12:45:59 -0600228 if '@odata.id' == key:
George Keishingf8acde92019-04-19 19:46:48 +0000229 if value not in resource_list and not value.endswith('/'):
230 resource_list.append(value)
George Keishing7ec45932019-02-27 14:02:16 -0600231
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)