blob: 0619ca5a6222976830ec2d679d12b37040933880 [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
22 ROBOT_LIBRARY_SCOPE = "GLOBAL"
23
24 def __init__(self, hostname, username, password, *args, **kwargs):
25 r"""
26 Establish session connection to host.
27
28 Description of argument(s):
29 hostname The host name or IP address of the server.
30 username The username to be used to connect to the server.
31 password The password to be used to connect to the server.
32 args/kwargs Additional parms which are passed directly
33 to the redfish_client function.
34 """
35
36 self._base_url_ = "https://" + hostname
37 self._username_ = username
38 self._password_ = password
39 self._default_prefix_ = "/redfish/v1"
40 self._robj_ = \
41 redfish.redfish_client(base_url=self._base_url_,
42 username=self._username_,
43 password=self._password_,
44 default_prefix=self._default_prefix_,
45 *args, **kwargs)
46 self._robj_.login(auth=redfish.AuthMethod.SESSION)
47 self._session_location_ = self._robj_.get_session_location()
48
49 def __enter__(self):
50 return self
51
52 def __exit__(self, exception_type, exception_value, traceback):
53 self._robj_.logout()
54
55 def login(self, *args, **kwargs):
56 r"""
57 Call the corresponding RestClientBase method and return the result.
58
59 Description of argument(s):
60 args/kwargs These are passed directly to the corresponding
61 RestClientBase method.
62 """
63 self._robj_.__init__(self._base_url_, self._username_, self._password_)
64 self._robj_.login(auth=redfish.AuthMethod.SESSION)
65
66 def get(self, resource_path, *args, **kwargs):
67 r"""
68 Perform a GET request and return response.
69
70 Description of argument(s):
George Keishing6510cfb2019-01-31 12:28:36 -060071 resource_path URI resource absolute path (e.g. "/redfish/v1/Systems/1").
George Keishinge62d8b02018-11-29 12:01:56 -060072 args/kwargs These are passed directly to the corresponding
73 RestClientBase method.
74 """
George Keishing6510cfb2019-01-31 12:28:36 -060075 self._rest_response_ = self._robj_.get(resource_path, *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -060076 return self._rest_response_
77
78 def post(self, resource_path, *args, **kwargs):
79 r"""
80 Perform a POST request.
81
82 Description of argument(s):
83 resource_path URI resource relative path
84 (e.g. "Systems/1/Actions/ComputerSystem.Reset").
85 args/kwargs These are passed directly to the corresponding
86 RestClientBase method.
87 """
88 self._rest_response_ = self._robj_.post('/redfish/v1/' + resource_path,
89 *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -060090 return self._rest_response_
91
92 def patch(self, resource_path, *args, **kwargs):
93 r"""
94 Perform a POST request.
95
96 Description of argument(s):
97 resource_path URI resource relative path
98 args/kwargs These are passed directly to the corresponding
99 RestClientBase method.
100 """
101 self._rest_response_ = self._robj_.patch('/redfish/v1/' + resource_path,
102 *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -0600103 return self._rest_response_
104
105 def put(self, resource_path, actions, attr_data):
106 r"""
107 Perform a PUT request.
108
109 Description of argument(s):
110 resource_path URI resource relative path.
111 args/kwargs These are passed directly to the corresponding
112 RestClientBase method.
113 """
114 self._rest_response_ = self._robj_.put('/redfish/v1/' + resource_path,
115 *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -0600116 return self._rest_response_
117
118 def delete(self, resource_path):
119 r"""
120 Perform a DELETE request.
121
122 Description of argument(s):
123 resource_path URI resource absoulute path
124 (e.g. "/redfish/v1/SessionService/Sessions/8d1a9wiiNL").
125 """
126 self._rest_response_ = self._robj_.delete(resource_path)
George Keishinge62d8b02018-11-29 12:01:56 -0600127 return self._rest_response_
128
129 def logout(self):
130 r"""
131 Logout redfish connection session.
132 """
133 self._robj_.logout()
134
George Keishing83933762019-02-02 04:50:08 -0600135 def get_attribute(self, resource_path, attribute):
136 r"""
137 Perform a GET request and return attribute value.
138
139 Description of argument(s):
140 resource_path URI resource absolute path (e.g. "/redfish/v1/Systems/1").
141 attribute Property name (e.g. "PowerState").
142 """
143
144 resp = self._robj_.get(resource_path)
145
146 if attribute in resp.dict:
147 return resp.dict[attribute]
148
149 return None
150
George Keishinge62d8b02018-11-29 12:01:56 -0600151 def list_request(self, resource_path):
152 r"""
153 Perform a GET list request and return available resource paths.
154
155 Description of argument(s):
156 resource_path URI resource relative path (e.g. "Systems/1").
157 """
158
George Keishinge62d8b02018-11-29 12:01:56 -0600159 global resource_list
160 resource_list = []
George Keishing2296e8c2019-02-01 05:49:58 -0600161
162 self._rest_response_ = self._robj_.get('/redfish/v1/' + resource_path)
163
164 # Return empty list.
165 if self._rest_response_.status != 200:
166 return resource_list
167
George Keishinge62d8b02018-11-29 12:01:56 -0600168 self.walk_nested_dict(self._rest_response_.dict)
169
170 if not resource_list:
171 return uri_path
172
173 for resource in resource_list:
174 self._rest_response_ = self._robj_.get(resource)
175 if self._rest_response_.status != 200:
176 continue
177 self.walk_nested_dict(self._rest_response_.dict)
178
179 resource_list.sort()
George Keishing5a73ee02019-01-28 08:21:47 -0600180 return resource_list
George Keishinge62d8b02018-11-29 12:01:56 -0600181
182 def enumerate_request(self, resource_path):
183 r"""
184 Perform a GET enumerate request and return available resource paths.
185
186 Description of argument(s):
187 resource_path URI resource relative path (e.g. "Systems/1").
188 """
189
George Keishing2296e8c2019-02-01 05:49:58 -0600190 url_list = self.list_request(resource_path)
George Keishinge62d8b02018-11-29 12:01:56 -0600191
192 resource_dict = {}
George Keishing2296e8c2019-02-01 05:49:58 -0600193
194 # Return empty dict.
195 if not url_list:
196 return resource_dict
197
198 for resource in url_list:
George Keishinge62d8b02018-11-29 12:01:56 -0600199 self._rest_response_ = self._robj_.get(resource)
200 if self._rest_response_.status != 200:
201 continue
202 resource_dict[resource] = self._rest_response_.dict
203
204 return json.dumps(resource_dict, sort_keys=True,
205 indent=4, separators=(',', ': '))
206
207 def walk_nested_dict(self, data):
208 r"""
209 Parse through the nested dictionary and get the resource id paths.
210
211 Description of argument(s):
212 data Nested dictionary data from response message.
213 """
214
215 for key, value in data.items():
216 if isinstance(value, dict):
217 self.walk_nested_dict(value)
218 else:
219 if 'Members' == key:
220 if isinstance(value, list):
221 for index in value:
222 if index['@odata.id'] not in resource_list:
223 resource_list.append(index['@odata.id'])
224 if '@odata.id' == key:
225 if value not in resource_list and not value.endswith('/'):
226 resource_list.append(value)