blob: ae31d4044da0273c4a72139a5b94fcc0c7099eb7 [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):
71 resource_path URI resource relative path (e.g. "Systems/1").
72 args/kwargs These are passed directly to the corresponding
73 RestClientBase method.
74 """
75 self._rest_response_ = self._robj_.get('/redfish/v1/' + resource_path,
76 *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -060077 return self._rest_response_
78
79 def post(self, resource_path, *args, **kwargs):
80 r"""
81 Perform a POST request.
82
83 Description of argument(s):
84 resource_path URI resource relative path
85 (e.g. "Systems/1/Actions/ComputerSystem.Reset").
86 args/kwargs These are passed directly to the corresponding
87 RestClientBase method.
88 """
89 self._rest_response_ = self._robj_.post('/redfish/v1/' + resource_path,
90 *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -060091 return self._rest_response_
92
93 def patch(self, resource_path, *args, **kwargs):
94 r"""
95 Perform a POST request.
96
97 Description of argument(s):
98 resource_path URI resource relative path
99 args/kwargs These are passed directly to the corresponding
100 RestClientBase method.
101 """
102 self._rest_response_ = self._robj_.patch('/redfish/v1/' + resource_path,
103 *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -0600104 return self._rest_response_
105
106 def put(self, resource_path, actions, attr_data):
107 r"""
108 Perform a PUT request.
109
110 Description of argument(s):
111 resource_path URI resource relative path.
112 args/kwargs These are passed directly to the corresponding
113 RestClientBase method.
114 """
115 self._rest_response_ = self._robj_.put('/redfish/v1/' + resource_path,
116 *args, **kwargs)
George Keishinge62d8b02018-11-29 12:01:56 -0600117 return self._rest_response_
118
119 def delete(self, resource_path):
120 r"""
121 Perform a DELETE request.
122
123 Description of argument(s):
124 resource_path URI resource absoulute path
125 (e.g. "/redfish/v1/SessionService/Sessions/8d1a9wiiNL").
126 """
127 self._rest_response_ = self._robj_.delete(resource_path)
George Keishinge62d8b02018-11-29 12:01:56 -0600128 return self._rest_response_
129
130 def logout(self):
131 r"""
132 Logout redfish connection session.
133 """
134 self._robj_.logout()
135
136 def list_request(self, resource_path):
137 r"""
138 Perform a GET list request and return available resource paths.
139
140 Description of argument(s):
141 resource_path URI resource relative path (e.g. "Systems/1").
142 """
143
George Keishinge62d8b02018-11-29 12:01:56 -0600144 global resource_list
145 resource_list = []
George Keishing2296e8c2019-02-01 05:49:58 -0600146
147 self._rest_response_ = self._robj_.get('/redfish/v1/' + resource_path)
148
149 # Return empty list.
150 if self._rest_response_.status != 200:
151 return resource_list
152
George Keishinge62d8b02018-11-29 12:01:56 -0600153 self.walk_nested_dict(self._rest_response_.dict)
154
155 if not resource_list:
156 return uri_path
157
158 for resource in resource_list:
159 self._rest_response_ = self._robj_.get(resource)
160 if self._rest_response_.status != 200:
161 continue
162 self.walk_nested_dict(self._rest_response_.dict)
163
164 resource_list.sort()
George Keishing5a73ee02019-01-28 08:21:47 -0600165 return resource_list
George Keishinge62d8b02018-11-29 12:01:56 -0600166
167 def enumerate_request(self, resource_path):
168 r"""
169 Perform a GET enumerate request and return available resource paths.
170
171 Description of argument(s):
172 resource_path URI resource relative path (e.g. "Systems/1").
173 """
174
George Keishing2296e8c2019-02-01 05:49:58 -0600175 url_list = self.list_request(resource_path)
George Keishinge62d8b02018-11-29 12:01:56 -0600176
177 resource_dict = {}
George Keishing2296e8c2019-02-01 05:49:58 -0600178
179 # Return empty dict.
180 if not url_list:
181 return resource_dict
182
183 for resource in url_list:
George Keishinge62d8b02018-11-29 12:01:56 -0600184 self._rest_response_ = self._robj_.get(resource)
185 if self._rest_response_.status != 200:
186 continue
187 resource_dict[resource] = self._rest_response_.dict
188
189 return json.dumps(resource_dict, sort_keys=True,
190 indent=4, separators=(',', ': '))
191
192 def walk_nested_dict(self, data):
193 r"""
194 Parse through the nested dictionary and get the resource id paths.
195
196 Description of argument(s):
197 data Nested dictionary data from response message.
198 """
199
200 for key, value in data.items():
201 if isinstance(value, dict):
202 self.walk_nested_dict(value)
203 else:
204 if 'Members' == key:
205 if isinstance(value, list):
206 for index in value:
207 if index['@odata.id'] not in resource_list:
208 resource_list.append(index['@odata.id'])
209 if '@odata.id' == key:
210 if value not in resource_list and not value.endswith('/'):
211 resource_list.append(value)