diff --git a/lib/ansible/module_utils/redfish_utils.py b/lib/ansible/module_utils/redfish_utils.py index 2ea036050b..219cf9783f 100644 --- a/lib/ansible/module_utils/redfish_utils.py +++ b/lib/ansible/module_utils/redfish_utils.py @@ -815,9 +815,13 @@ class RedfishUtils(object): return response return {'ret': True, 'changed': True, 'msg': "Set BIOS to default settings"} - def set_one_time_boot_device(self, bootdevice): + def set_one_time_boot_device(self, bootdevice, uefi_target, boot_next): result = {} - key = "Bios" + key = "Boot" + + if not bootdevice: + return {'ret': False, + 'msg': "bootdevice option required for SetOneTimeBoot"} # Search for 'key' entry and extract URI from it response = self.get_request(self.root_uri + self.systems_uris[0]) @@ -829,23 +833,65 @@ class RedfishUtils(object): if key not in data: return {'ret': False, 'msg': "Key %s not found" % key} - bios_uri = data[key]["@odata.id"] + boot = data[key] - response = self.get_request(self.root_uri + bios_uri) - if response['ret'] is False: - return response - data = response['data'] + annotation = 'BootSourceOverrideTarget@Redfish.AllowableValues' + if annotation in boot: + allowable_values = boot[annotation] + if isinstance(allowable_values, list) and bootdevice not in allowable_values: + return {'ret': False, + 'msg': "Boot device %s not in list of allowable values (%s)" % + (bootdevice, allowable_values)} - boot_mode = data[u'Attributes']["BootMode"] - if boot_mode == "Uefi": - payload = {"Boot": {"BootSourceOverrideTarget": "UefiTarget", "UefiTargetBootSourceOverride": bootdevice}} + # read existing values + enabled = boot.get('BootSourceOverrideEnabled') + target = boot.get('BootSourceOverrideTarget') + cur_uefi_target = boot.get('UefiTargetBootSourceOverride') + cur_boot_next = boot.get('BootNext') + + if bootdevice == 'UefiTarget': + if not uefi_target: + return {'ret': False, + 'msg': "uefi_target option required to SetOneTimeBoot for UefiTarget"} + if enabled == 'Once' and target == bootdevice and uefi_target == cur_uefi_target: + # If properties are already set, no changes needed + return {'ret': True, 'changed': False} + payload = { + 'Boot': { + 'BootSourceOverrideEnabled': 'Once', + 'BootSourceOverrideTarget': bootdevice, + 'UefiTargetBootSourceOverride': uefi_target + } + } + elif bootdevice == 'UefiBootNext': + if not boot_next: + return {'ret': False, + 'msg': "boot_next option required to SetOneTimeBoot for UefiBootNext"} + if enabled == 'Once' and target == bootdevice and boot_next == cur_boot_next: + # If properties are already set, no changes needed + return {'ret': True, 'changed': False} + payload = { + 'Boot': { + 'BootSourceOverrideEnabled': 'Once', + 'BootSourceOverrideTarget': bootdevice, + 'BootNext': boot_next + } + } else: - payload = {"Boot": {"BootSourceOverrideTarget": bootdevice}} + if enabled == 'Once' and target == bootdevice: + # If properties are already set, no changes needed + return {'ret': True, 'changed': False} + payload = { + 'Boot': { + 'BootSourceOverrideEnabled': 'Once', + 'BootSourceOverrideTarget': bootdevice + } + } response = self.patch_request(self.root_uri + self.systems_uris[0], payload) if response['ret'] is False: return response - return {'ret': True} + return {'ret': True, 'changed': True} def set_bios_attributes(self, attr): result = {} diff --git a/lib/ansible/modules/remote_management/redfish/redfish_command.py b/lib/ansible/modules/remote_management/redfish/redfish_command.py index 498a0e5978..9b9d8d027f 100644 --- a/lib/ansible/modules/remote_management/redfish/redfish_command.py +++ b/lib/ansible/modules/remote_management/redfish/redfish_command.py @@ -74,6 +74,16 @@ options: default: 10 type: int version_added: '2.8' + uefi_target: + required: false + description: + - UEFI target when bootdevice is "UefiTarget" + version_added: "2.9" + boot_next: + required: false + description: + - BootNext target when bootdevice is "UefiBootNext" + version_added: "2.9" author: "Jose Delarosa (@jose-delarosa)" ''' @@ -96,6 +106,26 @@ EXAMPLES = ''' username: "{{ username }}" password: "{{ password }}" + - name: Set one-time boot device to UefiTarget of "/0x31/0x33/0x01/0x01" + redfish_command: + category: Systems + command: SetOneTimeBoot + bootdevice: "UefiTarget" + uefi_target: "/0x31/0x33/0x01/0x01" + baseuri: "{{ baseuri }}" + username: "{{ username }}" + password: "{{ password }}" + + - name: Set one-time boot device to BootNext target of "Boot0001" + redfish_command: + category: Systems + command: SetOneTimeBoot + bootdevice: "UefiBootNext" + boot_next: "Boot0001" + baseuri: "{{ baseuri }}" + username: "{{ username }}" + password: "{{ password }}" + - name: Set chassis indicator LED to blink redfish_command: category: Chassis @@ -183,7 +213,9 @@ def main(): new_password=dict(no_log=True), roleid=dict(), bootdevice=dict(), - timeout=dict(type='int', default=10) + timeout=dict(type='int', default=10), + uefi_target=dict(), + boot_next=dict() ), supports_check_mode=False ) @@ -248,7 +280,10 @@ def main(): if "Power" in command: result = rf_utils.manage_system_power(command) elif command == "SetOneTimeBoot": - result = rf_utils.set_one_time_boot_device(module.params['bootdevice']) + result = rf_utils.set_one_time_boot_device( + module.params['bootdevice'], + module.params['uefi_target'], + module.params['boot_next']) elif category == "Chassis": result = rf_utils._find_chassis_resource(rf_uri) @@ -283,7 +318,8 @@ def main(): # Return data back or fail with proper message if result['ret'] is True: del result['ret'] - module.exit_json(changed=True, msg='Action was successful') + changed = result.get('changed', True) + module.exit_json(changed=changed, msg='Action was successful') else: module.fail_json(msg=to_native(result['msg']))