1#!/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 10 11 12class HTTPSBadRequestError(Exception): 13 r""" 14 BMC redfish generic raised method for error(s). 15 """ 16 pass 17 18 19class bmc_redfish(object): 20 21 ROBOT_LIBRARY_SCOPE = "GLOBAL" 22 23 def __init__(self, hostname, username, password, *args, **kwargs): 24 r""" 25 Establish session connection to host. 26 27 Description of argument(s): 28 hostname The host name or IP address of the server. 29 username The username to be used to connect to the server. 30 password The password to be used to connect to the server. 31 args/kwargs Additional parms which are passed directly 32 to the redfish_client function. 33 """ 34 35 self._base_url_ = "https://" + hostname 36 self._username_ = username 37 self._password_ = password 38 self._default_prefix_ = "/redfish/v1" 39 self._robj_ = \ 40 redfish.redfish_client(base_url=self._base_url_, 41 username=self._username_, 42 password=self._password_, 43 default_prefix=self._default_prefix_, 44 *args, **kwargs) 45 self._robj_.login(auth=redfish.AuthMethod.SESSION) 46 self._session_location_ = self._robj_.get_session_location() 47 48 def __enter__(self): 49 return self 50 51 def __exit__(self, exception_type, exception_value, traceback): 52 self._robj_.logout() 53 54 def login(self, *args, **kwargs): 55 r""" 56 Call the corresponding RestClientBase method and return the result. 57 58 Description of argument(s): 59 args/kwargs These are passed directly to the corresponding 60 RestClientBase method. 61 """ 62 self._robj_.__init__(self._base_url_, self._username_, self._password_) 63 self._robj_.login(auth=redfish.AuthMethod.SESSION) 64 65 def get(self, resource_path, *args, **kwargs): 66 r""" 67 Perform a GET request and return response. 68 69 Description of argument(s): 70 resource_path URI resource relative path (e.g. "Systems/1"). 71 args/kwargs These are passed directly to the corresponding 72 RestClientBase method. 73 """ 74 self._rest_response_ = self._robj_.get('/redfish/v1/' + resource_path, 75 *args, **kwargs) 76 if self._rest_response_.status != 200: 77 raise HTTPSBadRequestError("GET Session location: %s, " 78 "return code: %d" 79 % (self._session_location_, 80 self._rest_response_.status)) 81 return self._rest_response_ 82 83 def post(self, resource_path, *args, **kwargs): 84 r""" 85 Perform a POST request. 86 87 Description of argument(s): 88 resource_path URI resource relative path 89 (e.g. "Systems/1/Actions/ComputerSystem.Reset"). 90 args/kwargs These are passed directly to the corresponding 91 RestClientBase method. 92 """ 93 self._rest_response_ = self._robj_.post('/redfish/v1/' + resource_path, 94 *args, **kwargs) 95 if self._rest_response_.status != 200: 96 raise HTTPSBadRequestError("POST Session location: %s, " 97 "return code: %d" 98 % (self._session_location_, 99 self._rest_response_.status)) 100 return self._rest_response_ 101 102 def patch(self, resource_path, *args, **kwargs): 103 r""" 104 Perform a POST request. 105 106 Description of argument(s): 107 resource_path URI resource relative path 108 args/kwargs These are passed directly to the corresponding 109 RestClientBase method. 110 """ 111 self._rest_response_ = self._robj_.patch('/redfish/v1/' + resource_path, 112 *args, **kwargs) 113 if self._rest_response_.status != 200: 114 raise HTTPSBadRequestError("PATCH Session location: %s, " 115 "return code: %d" 116 % (self._session_location_, 117 self._rest_response_.status)) 118 return self._rest_response_ 119 120 def put(self, resource_path, actions, attr_data): 121 r""" 122 Perform a PUT request. 123 124 Description of argument(s): 125 resource_path URI resource relative path. 126 args/kwargs These are passed directly to the corresponding 127 RestClientBase method. 128 """ 129 self._rest_response_ = self._robj_.put('/redfish/v1/' + resource_path, 130 *args, **kwargs) 131 if self._rest_response_.status != 200: 132 raise HTTPSBadRequestError("PUT Session location: %s, " 133 "return code: %d" 134 % (self._session_location_, 135 self._rest_response_.status)) 136 return self._rest_response_ 137 138 def delete(self, resource_path): 139 r""" 140 Perform a DELETE request. 141 142 Description of argument(s): 143 resource_path URI resource absoulute path 144 (e.g. "/redfish/v1/SessionService/Sessions/8d1a9wiiNL"). 145 """ 146 self._rest_response_ = self._robj_.delete(resource_path) 147 if self._rest_response_.status != 200: 148 raise HTTPSBadRequestError("Session location: %s, " 149 "return code: %d" 150 % (self._session_location_, 151 self._rest_response_.status)) 152 return self._rest_response_ 153 154 def logout(self): 155 r""" 156 Logout redfish connection session. 157 """ 158 self._robj_.logout() 159 160 def list_request(self, resource_path): 161 r""" 162 Perform a GET list request and return available resource paths. 163 164 Description of argument(s): 165 resource_path URI resource relative path (e.g. "Systems/1"). 166 """ 167 168 self._rest_response_ = self._robj_.get('/redfish/v1/' + resource_path) 169 170 global resource_list 171 resource_list = [] 172 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() 184 return json.dumps(resource_list, sort_keys=True, 185 indent=4, separators=(',', ': ')) 186 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): 192 resource_path URI resource relative path (e.g. "Systems/1"). 193 """ 194 195 self._rest_response_ = self.list_request(resource_path) 196 197 resource_dict = {} 198 for resource in json.loads(self._rest_response_): 199 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) 227