blob: 2923b2e5b251c151b043ba3d402300463c1488e0 [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):
160 resource_path URI resource relative path (e.g. "Systems/1").
161 """
162
George Keishinge62d8b02018-11-29 12:01:56 -0600163 global resource_list
164 resource_list = []
George Keishing2296e8c2019-02-01 05:49:58 -0600165
166 self._rest_response_ = self._robj_.get('/redfish/v1/' + resource_path)
167
168 # Return empty list.
169 if self._rest_response_.status != 200:
170 return resource_list
171
George Keishinge62d8b02018-11-29 12:01:56 -0600172 self.walk_nested_dict(self._rest_response_.dict)
173
174 if not resource_list:
175 return uri_path
176
177 for resource in resource_list:
178 self._rest_response_ = self._robj_.get(resource)
179 if self._rest_response_.status != 200:
180 continue
181 self.walk_nested_dict(self._rest_response_.dict)
182
183 resource_list.sort()
George Keishing5a73ee02019-01-28 08:21:47 -0600184 return resource_list
George Keishinge62d8b02018-11-29 12:01:56 -0600185
186 def enumerate_request(self, resource_path):
187 r"""
188 Perform a GET enumerate request and return available resource paths.
189
190 Description of argument(s):
191 resource_path URI resource relative path (e.g. "Systems/1").
192 """
193
George Keishing2296e8c2019-02-01 05:49:58 -0600194 url_list = self.list_request(resource_path)
George Keishinge62d8b02018-11-29 12:01:56 -0600195
196 resource_dict = {}
George Keishing2296e8c2019-02-01 05:49:58 -0600197
198 # Return empty dict.
199 if not url_list:
200 return resource_dict
201
202 for resource in url_list:
George Keishinge62d8b02018-11-29 12:01:56 -0600203 self._rest_response_ = self._robj_.get(resource)
204 if self._rest_response_.status != 200:
205 continue
206 resource_dict[resource] = self._rest_response_.dict
207
208 return json.dumps(resource_dict, sort_keys=True,
209 indent=4, separators=(',', ': '))
210
211 def walk_nested_dict(self, data):
212 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):
225 for index in value:
226 if index['@odata.id'] not in resource_list:
227 resource_list.append(index['@odata.id'])
228 if '@odata.id' == key:
229 if value not in resource_list and not value.endswith('/'):
230 resource_list.append(value)