| #!/usr/bin/env python3 |
| |
| r""" |
| This module contains functions having to do with redfish path walking. |
| """ |
| |
| import os |
| import subprocess |
| import json |
| |
| ERROR_RESPONSE = { |
| "404": 'Response Error: status_code: 404 -- Not Found', |
| "500": 'Response Error: status_code: 500 -- Internal Server Error', |
| } |
| |
| # Variable to hold enumerated data. |
| result = {} |
| |
| # Variable to hold the pending list of resources for which enumeration. |
| # is yet to be obtained. |
| pending_enumeration = set() |
| |
| |
| def execute_redfish_cmd(parms, json_type="json"): |
| r""" |
| Run CLI standard redfish tool. |
| |
| Description of variable: |
| parms_string Command to execute from the current SHELL. |
| quiet do not print tool error message if True |
| """ |
| resp = subprocess.run([parms], |
| stdout=subprocess.PIPE, |
| stderr=subprocess.PIPE, |
| shell=True, |
| universal_newlines=True) |
| |
| if resp.stderr: |
| print('\n\t\tERROR with %s ' % parms) |
| print('\t\t' + resp.stderr) |
| return resp.stderr |
| elif json_type == "json": |
| json_data = json.loads(resp.stdout) |
| return json_data |
| else: |
| return resp.stdout |
| |
| |
| def enumerate_request(hostname, username, password, url, return_json="json"): |
| r""" |
| Perform a GET enumerate request and return available resource paths. |
| |
| Description of argument(s): |
| url URI resource absolute path (e.g. |
| "/redfish/v1/SessionService/Sessions"). |
| return_json Indicates whether the result should be |
| returned as a json string or as a |
| dictionary. |
| """ |
| parms = 'redfishtool -u ' + username + ' -p ' + password + ' -r ' + \ |
| hostname + ' -S Always raw GET ' |
| |
| pending_enumeration.add(url) |
| |
| # Variable having resources for which enumeration is completed. |
| enumerated_resources = set() |
| |
| resources_to_be_enumerated = (url,) |
| |
| while resources_to_be_enumerated: |
| for resource in resources_to_be_enumerated: |
| # JsonSchemas, SessionService or URLs containing # are not |
| # required in enumeration. |
| # Example: '/redfish/v1/JsonSchemas/' and sub resources. |
| # '/redfish/v1/SessionService' |
| # '/redfish/v1/Managers/bmc#/Oem' |
| if ('JsonSchemas' in resource) or ('SessionService' in resource)\ |
| or ('PostCodes' in resource) or ('Registries' in resource)\ |
| or ('#' in resource): |
| continue |
| |
| response = execute_redfish_cmd(parms + resource) |
| # Enumeration is done for available resources ignoring the |
| # ones for which response is not obtained. |
| if 'Error getting response' in response: |
| continue |
| |
| walk_nested_dict(response, url=resource) |
| |
| enumerated_resources.update(set(resources_to_be_enumerated)) |
| resources_to_be_enumerated = \ |
| tuple(pending_enumeration - enumerated_resources) |
| |
| if return_json == "json": |
| return json.dumps(result, sort_keys=True, |
| indent=4, separators=(',', ': ')) |
| else: |
| return result |
| |
| |
| def walk_nested_dict(data, url=''): |
| r""" |
| Parse through the nested dictionary and get the resource id paths. |
| |
| Description of argument(s): |
| data Nested dictionary data from response message. |
| url Resource for which the response is obtained in data. |
| """ |
| url = url.rstrip('/') |
| |
| for key, value in data.items(): |
| |
| # Recursion if nested dictionary found. |
| if isinstance(value, dict): |
| walk_nested_dict(value) |
| else: |
| # Value contains a list of dictionaries having member data. |
| if 'Members' == key: |
| if isinstance(value, list): |
| for memberDict in value: |
| if isinstance(memberDict, str): |
| pending_enumeration.add(memberDict) |
| else: |
| pending_enumeration.add(memberDict['@odata.id']) |
| |
| if '@odata.id' == key: |
| value = value.rstrip('/') |
| # Data for the given url. |
| if value == url: |
| result[url] = data |
| # Data still needs to be looked up, |
| else: |
| pending_enumeration.add(value) |
| |
| |
| def get_key_value_nested_dict(data, key): |
| r""" |
| Parse through the nested dictionary and get the searched key value. |
| |
| Description of argument(s): |
| data Nested dictionary data from response message. |
| key Search dictionary key element. |
| """ |
| |
| for k, v in data.items(): |
| if isinstance(v, dict): |
| get_key_value_nested_dict(v, key) |
| |
| if k == key: |
| target_list.append(v) |