1#!/usr/bin/env python 2 3r""" 4BMC redfish utility functions. 5""" 6 7import json 8from robot.libraries.BuiltIn import BuiltIn 9import gen_print as gp 10 11 12class bmc_redfish_utils(object): 13 14 def __init__(self): 15 r""" 16 Initialize the bmc_redfish_utils object. 17 """ 18 # Obtain a reference to the global redfish object. 19 self._redfish_ = BuiltIn().get_library_instance('redfish') 20 21 def get_redfish_session_info(self): 22 r""" 23 Returns redfish sessions info dictionary. 24 25 { 26 'key': 'yLXotJnrh5nDhXj5lLiH' , 27 'location': '/redfish/v1/SessionService/Sessions/nblYY4wlz0' 28 } 29 """ 30 session_dict = { 31 "key": self._redfish_.get_session_key(), 32 "location": self._redfish_.get_session_location() 33 } 34 return session_dict 35 36 def get_attribute(self, resource_path, attribute): 37 r""" 38 Get resource attribute. 39 40 Description of argument(s): 41 resource_path URI resource absolute path (e.g. 42 "/redfish/v1/Systems/1"). 43 attribute Name of the attribute (e.g. 'PowerState'). 44 """ 45 46 resp = self._redfish_.get(resource_path) 47 if attribute in resp.dict: 48 return resp.dict[attribute] 49 50 return None 51 52 def get_properties(self, resource_path): 53 r""" 54 Returns dictionary of attributes for the resource. 55 56 Description of argument(s): 57 resource_path URI resource absolute path (e.g. 58 "/redfish/v1/Systems/1"). 59 """ 60 61 resp = self._redfish_.get(resource_path) 62 return resp.dict 63 64 def get_target_actions(self, resource_path, target_attribute): 65 r""" 66 Returns resource target entry of the searched target attribute. 67 68 Description of argument(s): 69 resource_path URI resource absolute path 70 (e.g. "/redfish/v1/Systems/system"). 71 target_attribute Name of the attribute (e.g. 'ComputerSystem.Reset'). 72 73 Example: 74 "Actions": { 75 "#ComputerSystem.Reset": { 76 "ResetType@Redfish.AllowableValues": [ 77 "On", 78 "ForceOff", 79 "GracefulRestart", 80 "GracefulShutdown" 81 ], 82 "target": "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset" 83 } 84 } 85 """ 86 87 global target_list 88 target_list = [] 89 90 resp_dict = self.get_attribute(resource_path, "Actions") 91 if resp_dict is None: 92 return None 93 94 # Recursively search the "target" key in the nested dictionary. 95 # Populate the target_list of target entries. 96 self.get_key_value_nested_dict(resp_dict, "target") 97 98 # Return the matching target URL entry. 99 for target in target_list: 100 # target "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset" 101 if target_attribute in target: 102 return target 103 104 return None 105 106 def get_member_list(self, resource_path): 107 r""" 108 Perform a GET list request and return available members entries. 109 110 Description of argument(s): 111 resource_path URI resource absolute path 112 (e.g. "/redfish/v1/SessionService/Sessions"). 113 114 "Members": [ 115 { 116 "@odata.id": "/redfish/v1/SessionService/Sessions/Z5HummWPZ7" 117 } 118 { 119 "@odata.id": "/redfish/v1/SessionService/Sessions/46CmQmEL7H" 120 } 121 ], 122 """ 123 124 member_list = [] 125 resp_list_dict = self.get_attribute(resource_path, "Members") 126 if resp_list_dict is None: 127 return member_list 128 129 for member_id in range(0, len(resp_list_dict)): 130 member_list.append(resp_list_dict[member_id]["@odata.id"]) 131 132 return member_list 133 134 def list_request(self, resource_path): 135 r""" 136 Perform a GET list request and return available resource paths. 137 138 Description of argument(s): 139 resource_path URI resource absolute path 140 (e.g. "/redfish/v1/SessionService/Sessions"). 141 """ 142 143 gp.qprint_executing(style=gp.func_line_style_short) 144 145 # Set quiet variable to keep subordinate get() calls quiet. 146 quiet = 1 147 148 global resource_list 149 resource_list = [] 150 self._rest_response_ = \ 151 self._redfish_.get(resource_path, 152 valid_status_codes=[200, 404, 500]) 153 154 # Return empty list. 155 if self._rest_response_.status != 200: 156 return resource_list 157 158 self.walk_nested_dict(self._rest_response_.dict) 159 160 if not resource_list: 161 return uri_path 162 163 for resource in resource_list: 164 self._rest_response_ = \ 165 self._redfish_.get(resource, 166 valid_status_codes=[200, 404, 500]) 167 if self._rest_response_.status != 200: 168 continue 169 self.walk_nested_dict(self._rest_response_.dict) 170 171 resource_list.sort() 172 return resource_list 173 174 def enumerate_request(self, resource_path): 175 r""" 176 Perform a GET enumerate request and return available resource paths. 177 178 Description of argument(s): 179 resource_path URI resource absolute path 180 (e.g. "/redfish/v1/SessionService/Sessions"). 181 """ 182 183 gp.qprint_executing(style=gp.func_line_style_short) 184 185 # Set quiet variable to keep subordinate get() calls quiet. 186 quiet = 1 187 188 url_list = self.list_request(resource_path) 189 190 resource_dict = {} 191 192 # Return empty dict. 193 if not url_list: 194 return resource_dict 195 196 for resource in url_list: 197 # JsonSchemas data are not required in enumeration. 198 # Example: '/redfish/v1/JsonSchemas/' and sub resources. 199 if 'JsonSchemas' in resource: 200 continue 201 self._rest_response_ = \ 202 self._redfish_.get(resource, 203 valid_status_codes=[200, 404, 500]) 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) 231 232 def get_key_value_nested_dict(self, data, key): 233 r""" 234 Parse through the nested dictionary and get the searched key value. 235 236 Description of argument(s): 237 data Nested dictionary data from response message. 238 key Search dictionary key element. 239 """ 240 241 for k, v in data.items(): 242 if isinstance(v, dict): 243 self.get_key_value_nested_dict(v, key) 244 245 if k == key: 246 target_list.append(v) 247