From 2b8553b242c270fa8207b251b3faf8cf4edbbc85 Mon Sep 17 00:00:00 2001 From: Bill Dodd Date: Tue, 29 Oct 2019 08:10:58 -0500 Subject: [PATCH] Add SetBootOrder and SetDefaultBootOrder commands (#63915) * add SetBootOrder and SetDefaultBootOrder commands * change boot_order version added from 2.9 to 2.10 --- lib/ansible/module_utils/redfish_utils.py | 116 ++++++++++++++---- .../redfish/redfish_config.py | 42 ++++++- 2 files changed, 134 insertions(+), 24 deletions(-) diff --git a/lib/ansible/module_utils/redfish_utils.py b/lib/ansible/module_utils/redfish_utils.py index 35eda9aa2d5..4a5c795dc2e 100644 --- a/lib/ansible/module_utils/redfish_utils.py +++ b/lib/ansible/module_utils/redfish_utils.py @@ -1106,38 +1106,22 @@ class RedfishUtils(object): def get_multi_bios_attributes(self): return self.aggregate(self.get_bios_attributes) - def get_boot_order(self, systems_uri): - result = {} + def _get_boot_options_dict(self, boot): # Get these entries from BootOption, if present properties = ['DisplayName', 'BootOptionReference'] - # Retrieve System resource - response = self.get_request(self.root_uri + systems_uri) - if response['ret'] is False: - return response - result['ret'] = True - data = response['data'] - - # Confirm needed Boot properties are present - if 'Boot' not in data or 'BootOrder' not in data['Boot']: - return {'ret': False, 'msg': "Key BootOrder not found"} - - boot = data['Boot'] - boot_order = boot['BootOrder'] - # Retrieve BootOptions if present if 'BootOptions' in boot and '@odata.id' in boot['BootOptions']: boot_options_uri = boot['BootOptions']["@odata.id"] # Get BootOptions resource response = self.get_request(self.root_uri + boot_options_uri) if response['ret'] is False: - return response + return {} data = response['data'] # Retrieve Members array if 'Members' not in data: - return {'ret': False, - 'msg': "Members not found in BootOptionsCollection"} + return {} members = data['Members'] else: members = [] @@ -1146,14 +1130,14 @@ class RedfishUtils(object): boot_options_dict = {} for member in members: if '@odata.id' not in member: - return {'ret': False, 'msg': "@odata.id not found in BootOptions"} + return {} boot_option_uri = member['@odata.id'] response = self.get_request(self.root_uri + boot_option_uri) if response['ret'] is False: - return response + return {} data = response['data'] if 'BootOptionReference' not in data: - return {'ret': False, 'msg': "BootOptionReference not found in BootOption"} + return {} boot_option_ref = data['BootOptionReference'] # fetch the props to display for this boot device @@ -1164,6 +1148,26 @@ class RedfishUtils(object): boot_options_dict[boot_option_ref] = boot_props + return boot_options_dict + + def get_boot_order(self, systems_uri): + result = {} + + # Retrieve System resource + response = self.get_request(self.root_uri + systems_uri) + if response['ret'] is False: + return response + result['ret'] = True + data = response['data'] + + # Confirm needed Boot properties are present + if 'Boot' not in data or 'BootOrder' not in data['Boot']: + return {'ret': False, 'msg': "Key BootOrder not found"} + + boot = data['Boot'] + boot_order = boot['BootOrder'] + boot_options_dict = self._get_boot_options_dict(boot) + # Build boot device list boot_device_list = [] for ref in boot_order: @@ -1357,6 +1361,74 @@ class RedfishUtils(object): return response return {'ret': True, 'changed': True, 'msg': "Modified BIOS attribute"} + def set_boot_order(self, boot_list): + if not boot_list: + return {'ret': False, + 'msg': "boot_order list required for SetBootOrder command"} + + # TODO(billdodd): change to self.systems_uri after PR 62921 merged + systems_uri = self.systems_uris[0] + response = self.get_request(self.root_uri + systems_uri) + if response['ret'] is False: + return response + data = response['data'] + + # Confirm needed Boot properties are present + if 'Boot' not in data or 'BootOrder' not in data['Boot']: + return {'ret': False, 'msg': "Key BootOrder not found"} + + boot = data['Boot'] + boot_order = boot['BootOrder'] + boot_options_dict = self._get_boot_options_dict(boot) + + # validate boot_list against BootOptionReferences if available + if boot_options_dict: + boot_option_references = boot_options_dict.keys() + for ref in boot_list: + if ref not in boot_option_references: + return {'ret': False, + 'msg': "BootOptionReference %s not found in BootOptions" % ref} + + # If requested BootOrder is already set, nothing to do + if boot_order == boot_list: + return {'ret': True, 'changed': False, + 'msg': "BootOrder already set to %s" % boot_list} + + payload = { + 'Boot': { + 'BootOrder': boot_list + } + } + response = self.patch_request(self.root_uri + systems_uri, payload) + if response['ret'] is False: + return response + return {'ret': True, 'changed': True, 'msg': "BootOrder set"} + + def set_default_boot_order(self): + # TODO(billdodd): change to self.systems_uri after PR 62921 merged + systems_uri = self.systems_uris[0] + response = self.get_request(self.root_uri + systems_uri) + if response['ret'] is False: + return response + data = response['data'] + + # get the #ComputerSystem.SetDefaultBootOrder Action and target URI + action = '#ComputerSystem.SetDefaultBootOrder' + if 'Actions' not in data or action not in data['Actions']: + return {'ret': False, 'msg': 'Action %s not found' % action} + if 'target' not in data['Actions'][action]: + return {'ret': False, + 'msg': 'target URI missing from Action %s' % action} + action_uri = data['Actions'][action]['target'] + + # POST to Action URI + payload = {} + response = self.post_request(self.root_uri + action_uri, payload) + if response['ret'] is False: + return response + return {'ret': True, 'changed': True, + 'msg': "BootOrder set to default"} + def get_chassis_inventory(self): result = {} chassis_results = [] diff --git a/lib/ansible/modules/remote_management/redfish/redfish_config.py b/lib/ansible/modules/remote_management/redfish/redfish_config.py index 44c09ca38fd..69c0febd813 100644 --- a/lib/ansible/modules/remote_management/redfish/redfish_config.py +++ b/lib/ansible/modules/remote_management/redfish/redfish_config.py @@ -68,6 +68,13 @@ options: default: 10 type: int version_added: "2.8" + boot_order: + required: false + description: + - list of BootOptionReference strings specifying the BootOrder + default: [] + type: list + version_added: "2.10" author: "Jose Delarosa (@jose-delarosa)" ''' @@ -111,6 +118,28 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" timeout: 20 + + - name: Set boot order + redfish_config: + category: Systems + command: SetBootOrder + boot_order: + - Boot0002 + - Boot0001 + - Boot0000 + - Boot0003 + - Boot0004 + baseuri: "{{ baseuri }}" + username: "{{ username }}" + password: "{{ password }}" + + - name: Set boot order to the default + redfish_config: + category: Systems + command: SetDefaultBootOrder + baseuri: "{{ baseuri }}" + username: "{{ username }}" + password: "{{ password }}" ''' RETURN = ''' @@ -128,7 +157,8 @@ from ansible.module_utils._text import to_native # More will be added as module features are expanded CATEGORY_COMMANDS_ALL = { - "Systems": ["SetBiosDefaultSettings", "SetBiosAttributes"] + "Systems": ["SetBiosDefaultSettings", "SetBiosAttributes", "SetBootOrder", + "SetDefaultBootOrder"] } @@ -143,7 +173,8 @@ def main(): password=dict(required=True, no_log=True), bios_attribute_name=dict(default='null'), bios_attribute_value=dict(default='null'), - timeout=dict(type='int', default=10) + timeout=dict(type='int', default=10), + boot_order=dict(type='list', elements='str', default=[]) ), supports_check_mode=False ) @@ -162,6 +193,9 @@ def main(): bios_attributes = {'bios_attr_name': module.params['bios_attribute_name'], 'bios_attr_value': module.params['bios_attribute_value']} + # boot order + boot_order = module.params['boot_order'] + # Build root URI root_uri = "https://" + module.params['baseuri'] rf_utils = RedfishUtils(creds, root_uri, timeout, module) @@ -188,6 +222,10 @@ def main(): result = rf_utils.set_bios_default_settings() elif command == "SetBiosAttributes": result = rf_utils.set_bios_attributes(bios_attributes) + elif command == "SetBootOrder": + result = rf_utils.set_boot_order(boot_order) + elif command == "SetDefaultBootOrder": + result = rf_utils.set_default_boot_order() # Return data back or fail with proper message if result['ret'] is True: