blob: 79d2aaab9a3f1946b7779768f4193a362a5cdb18 [file] [log] [blame]
George Keishinge62d8b02018-11-29 12:01:56 -06001#!/usr/bin/env python
2
3r"""
4Using python based redfish library.
5Refer: https://github.com/DMTF/python-redfish-library
6"""
7
8import redfish
9import json
George Keishing2296e8c2019-02-01 05:49:58 -060010from robot.libraries.BuiltIn import BuiltIn
George Keishinge62d8b02018-11-29 12:01:56 -060011
12
13class HTTPSBadRequestError(Exception):
14 r"""
15 BMC redfish generic raised method for error(s).
16 """
17 pass
18
19
20class bmc_redfish(object):
21
George Keishing46e64a32019-02-05 22:45:10 -060022 ROBOT_LIBRARY_SCOPE = "TEST SUITE"
George Keishing2823d2a2019-02-05 22:19:19 -060023 ROBOT_EXIT_ON_FAILURE = True
George Keishinge62d8b02018-11-29 12:01:56 -060024
25 def __init__(self, hostname, username, password, *args, **kwargs):
26 r"""
27 Establish session connection to host.
28
29 Description of argument(s):
30 hostname The host name or IP address of the server.
31 username The username to be used to connect to the server.
32 password The password to be used to connect to the server.
33 args/kwargs Additional parms which are passed directly
34 to the redfish_client function.
35 """
George Keishinge62d8b02018-11-29 12:01:56 -060036 self._base_url_ = "https://" + hostname
37 self._username_ = username
38 self._password_ = password
39 self._default_prefix_ = "/redfish/v1"
George Keishinge62d8b02018-11-29 12:01:56 -060040
41 def __enter__(self):
42 return self
43
George Keishing2823d2a2019-02-05 22:19:19 -060044 def __del__(self):
George Keishing46e64a32019-02-05 22:45:10 -060045 del self
George Keishinge62d8b02018-11-29 12:01:56 -060046
47 def login(self, *args, **kwargs):
48 r"""
49 Call the corresponding RestClientBase method and return the result.
50
51 Description of argument(s):
52 args/kwargs These are passed directly to the corresponding
53 RestClientBase method.
54 """
George Keishing4c394012019-02-01 06:03:02 -060055
56 for arg in args:
57 hostname = self._base_url_.strip("https://")
58 # Class object constructor reinitialized.
59 self.__init__(hostname=hostname,
60 username=arg['username'],
61 password=arg['password'])
62
63 self._robj_ = redfish.redfish_client(base_url=self._base_url_,
64 username=self._username_,
65 password=self._password_,
66 default_prefix=self._default_prefix_)
George Keishinge62d8b02018-11-29 12:01:56 -060067 self._robj_.login(auth=redfish.AuthMethod.SESSION)
George Keishing4c394012019-02-01 06:03:02 -060068 self._session_location_ = self._robj_.get_session_location()
George Keishinge62d8b02018-11-29 12:01:56 -060069
70 def get(self, resource_path, *args, **kwargs):
71 r"""
72 Perform a GET request and return response.
73
74 Description of argument(s):
George Keishing6510cfb2019-01-31 12:28:36 -060075 resource_path URI resource absolute path (e.g. "/redfish/v1/Systems/1").
George Keishinge62d8b02018-11-29 12:01:56 -060076 args/kwargs These are passed directly to the corresponding
77 RestClientBase method.
78 """
George Keishing6510cfb2019-01-31 12:28:36 -060079 self._rest_response_ = self._robj_.get(resource_path, *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -060080 return self._rest_response_
81
82 def post(self, resource_path, *args, **kwargs):
83 r"""
84 Perform a POST request.
85
86 Description of argument(s):
87 resource_path URI resource relative path
88 (e.g. "Systems/1/Actions/ComputerSystem.Reset").
89 args/kwargs These are passed directly to the corresponding
90 RestClientBase method.
91 """
92 self._rest_response_ = self._robj_.post('/redfish/v1/' + resource_path,
93 *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -060094 return self._rest_response_
95
96 def patch(self, resource_path, *args, **kwargs):
97 r"""
98 Perform a POST request.
99
100 Description of argument(s):
101 resource_path URI resource relative path
102 args/kwargs These are passed directly to the corresponding
103 RestClientBase method.
104 """
105 self._rest_response_ = self._robj_.patch('/redfish/v1/' + resource_path,
106 *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -0600107 return self._rest_response_
108
109 def put(self, resource_path, actions, attr_data):
110 r"""
111 Perform a PUT request.
112
113 Description of argument(s):
114 resource_path URI resource relative path.
115 args/kwargs These are passed directly to the corresponding
116 RestClientBase method.
117 """
118 self._rest_response_ = self._robj_.put('/redfish/v1/' + resource_path,
119 *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -0600120 return self._rest_response_
121
122 def delete(self, resource_path):
123 r"""
124 Perform a DELETE request.
125
126 Description of argument(s):
George Keishing5d467552019-02-08 23:30:48 -0600127 resource_path URI resource absolute path
George Keishinge62d8b02018-11-29 12:01:56 -0600128 (e.g. "/redfish/v1/SessionService/Sessions/8d1a9wiiNL").
129 """
130 self._rest_response_ = self._robj_.delete(resource_path)
George Keishinge62d8b02018-11-29 12:01:56 -0600131 return self._rest_response_
132
133 def logout(self):
134 r"""
135 Logout redfish connection session.
136 """
137 self._robj_.logout()
138
George Keishing83933762019-02-02 04:50:08 -0600139 def get_attribute(self, resource_path, attribute):
140 r"""
141 Perform a GET request and return attribute value.
142
143 Description of argument(s):
144 resource_path URI resource absolute path (e.g. "/redfish/v1/Systems/1").
145 attribute Property name (e.g. "PowerState").
146 """
147
148 resp = self._robj_.get(resource_path)
149
150 if attribute in resp.dict:
151 return resp.dict[attribute]
152
153 return None
154
George Keishinge62d8b02018-11-29 12:01:56 -0600155 def list_request(self, resource_path):
156 r"""
157 Perform a GET list request and return available resource paths.
158
159 Description of argument(s):
George Keishing8cccbd72019-02-12 13:04:24 -0600160 resource_path URI resource absolute path
161 (e.g. "/redfish/v1/SessionService/Sessions").
George Keishinge62d8b02018-11-29 12:01:56 -0600162 """
163
George Keishinge62d8b02018-11-29 12:01:56 -0600164 global resource_list
165 resource_list = []
George Keishing2296e8c2019-02-01 05:49:58 -0600166
George Keishing8cccbd72019-02-12 13:04:24 -0600167 self._rest_response_ = self._robj_.get(resource_path)
George Keishing2296e8c2019-02-01 05:49:58 -0600168
169 # Return empty list.
170 if self._rest_response_.status != 200:
171 return resource_list
172
George Keishinge62d8b02018-11-29 12:01:56 -0600173 self.walk_nested_dict(self._rest_response_.dict)
174
175 if not resource_list:
176 return uri_path
177
178 for resource in resource_list:
179 self._rest_response_ = self._robj_.get(resource)
180 if self._rest_response_.status != 200:
181 continue
182 self.walk_nested_dict(self._rest_response_.dict)
183
184 resource_list.sort()
George Keishing5a73ee02019-01-28 08:21:47 -0600185 return resource_list
George Keishinge62d8b02018-11-29 12:01:56 -0600186
187 def enumerate_request(self, resource_path):
188 r"""
189 Perform a GET enumerate request and return available resource paths.
190
191 Description of argument(s):
George Keishing8cccbd72019-02-12 13:04:24 -0600192 resource_path URI resource absolute path
193 (e.g. "/redfish/v1/SessionService/Sessions").
George Keishinge62d8b02018-11-29 12:01:56 -0600194 """
195
George Keishing2296e8c2019-02-01 05:49:58 -0600196 url_list = self.list_request(resource_path)
George Keishinge62d8b02018-11-29 12:01:56 -0600197
198 resource_dict = {}
George Keishing2296e8c2019-02-01 05:49:58 -0600199
200 # Return empty dict.
201 if not url_list:
202 return resource_dict
203
204 for resource in url_list:
George Keishinge62d8b02018-11-29 12:01:56 -0600205 self._rest_response_ = self._robj_.get(resource)
206 if self._rest_response_.status != 200:
207 continue
208 resource_dict[resource] = self._rest_response_.dict
209
210 return json.dumps(resource_dict, sort_keys=True,
211 indent=4, separators=(',', ': '))
212
213 def walk_nested_dict(self, data):
214 r"""
215 Parse through the nested dictionary and get the resource id paths.
216
217 Description of argument(s):
218 data Nested dictionary data from response message.
219 """
220
221 for key, value in data.items():
222 if isinstance(value, dict):
223 self.walk_nested_dict(value)
224 else:
225 if 'Members' == key:
226 if isinstance(value, list):
227 for index in value:
228 if index['@odata.id'] not in resource_list:
229 resource_list.append(index['@odata.id'])
230 if '@odata.id' == key:
231 if value not in resource_list and not value.endswith('/'):
232 resource_list.append(value)