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 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) 90 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) 103 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) 116 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) 127 return self._rest_response_ 128 129 def logout(self): 130 r""" 131 Logout redfish connection session. 132 """ 133 self._robj_.logout() 134 135 def list_request(self, resource_path): 136 r""" 137 Perform a GET list request and return available resource paths. 138 139 Description of argument(s): 140 resource_path URI resource relative path (e.g. "Systems/1"). 141 """ 142 143 self._rest_response_ = self._robj_.get('/redfish/v1/' + resource_path) 144 if self._rest_response_.status != 200: 145 return self._rest_response_ 146 147 global resource_list 148 resource_list = [] 149 self.walk_nested_dict(self._rest_response_.dict) 150 151 if not resource_list: 152 return uri_path 153 154 for resource in resource_list: 155 self._rest_response_ = self._robj_.get(resource) 156 if self._rest_response_.status != 200: 157 continue 158 self.walk_nested_dict(self._rest_response_.dict) 159 160 resource_list.sort() 161 return resource_list 162 163 def enumerate_request(self, resource_path): 164 r""" 165 Perform a GET enumerate request and return available resource paths. 166 167 Description of argument(s): 168 resource_path URI resource relative path (e.g. "Systems/1"). 169 """ 170 171 self._rest_response_ = self.list_request(resource_path) 172 if self._rest_response_.status != 200: 173 return self._rest_response_ 174 175 resource_dict = {} 176 for resource in json.loads(self._rest_response_): 177 self._rest_response_ = self._robj_.get(resource) 178 if self._rest_response_.status != 200: 179 continue 180 resource_dict[resource] = self._rest_response_.dict 181 182 return json.dumps(resource_dict, sort_keys=True, 183 indent=4, separators=(',', ': ')) 184 185 def walk_nested_dict(self, data): 186 r""" 187 Parse through the nested dictionary and get the resource id paths. 188 189 Description of argument(s): 190 data Nested dictionary data from response message. 191 """ 192 193 for key, value in data.items(): 194 if isinstance(value, dict): 195 self.walk_nested_dict(value) 196 else: 197 if 'Members' == key: 198 if isinstance(value, list): 199 for index in value: 200 if index['@odata.id'] not in resource_list: 201 resource_list.append(index['@odata.id']) 202 if '@odata.id' == key: 203 if value not in resource_list and not value.endswith('/'): 204 resource_list.append(value) 205