From 8385d2eb39f748e48ab975bfc3925c8eab8395d6 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 23:24:53 +0200 Subject: [PATCH] [PR #6813/55893f27 backport][stable-7] Adding CreateVolume functionality (#7359) Adding CreateVolume functionality (#6813) * Adding create volume functionality * Adding changelog fragment * Sanity Fix * Sanity fix * Update 6813-redfish-config-add-create-volume.yml * Sanity fix * Sanity fix * Removing capabilities check and correcting controllers terminology to storage subsystem * Updating as per PR suggestions * sanity fix * Update plugins/modules/redfish_config.py Co-authored-by: Felix Fontein * Update plugins/modules/redfish_config.py Agreed Co-authored-by: Felix Fontein * Fixing merge issue * Fixing sanity issues * Adding CapacityBytes as a mandatory parameter and adding failure message when run for server below iLO6 * Sanity fix * Sanity fix * Updating vendor specific failure * Update plugins/modules/redfish_config.py Agreed Co-authored-by: Felix Fontein * Removing vendor specific failure case * removing unused import --------- Co-authored-by: Kushal Co-authored-by: Felix Fontein (cherry picked from commit 55893f27c99282028069728e2b1e2f44478c0455) Co-authored-by: TSKushal <44438079+TSKushal@users.noreply.github.com> --- .../6813-redfish-config-add-create-volume.yml | 2 + plugins/module_utils/redfish_utils.py | 83 +++++++++++++++++++ plugins/modules/redfish_config.py | 32 ++++++- 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/6813-redfish-config-add-create-volume.yml diff --git a/changelogs/fragments/6813-redfish-config-add-create-volume.yml b/changelogs/fragments/6813-redfish-config-add-create-volume.yml new file mode 100644 index 0000000000..96bd532c0d --- /dev/null +++ b/changelogs/fragments/6813-redfish-config-add-create-volume.yml @@ -0,0 +1,2 @@ +minor_changes: + - redfish_config - add ``CreateVolume`` command to allow creation of volumes on servers (https://github.com/ansible-collections/community.general/pull/6813). diff --git a/plugins/module_utils/redfish_utils.py b/plugins/module_utils/redfish_utils.py index 1923d915b6..b14fa1176f 100644 --- a/plugins/module_utils/redfish_utils.py +++ b/plugins/module_utils/redfish_utils.py @@ -3547,3 +3547,86 @@ class RedfishUtils(object): return {'ret': True, 'changed': True, 'msg': "The following volumes were deleted: %s" % str(volume_ids)} + + def create_volume(self, volume_details, storage_subsystem_id): + # Find the Storage resource from the requested ComputerSystem resource + response = self.get_request(self.root_uri + self.systems_uri) + if response['ret'] is False: + return response + data = response['data'] + storage_uri = data.get('Storage', {}).get('@odata.id') + if storage_uri is None: + return {'ret': False, 'msg': 'Storage resource not found'} + + # Get Storage Collection + response = self.get_request(self.root_uri + storage_uri) + if response['ret'] is False: + return response + data = response['data'] + + # Collect Storage Subsystems + self.storage_subsystems_uris = [i['@odata.id'] for i in response['data'].get('Members', [])] + if not self.storage_subsystems_uris: + return { + 'ret': False, + 'msg': "StorageCollection's Members array is either empty or missing"} + + # Matching Storage Subsystem ID with user input + self.storage_subsystem_uri = "" + for storage_subsystem_uri in self.storage_subsystems_uris: + if storage_subsystem_uri.split("/")[-2] == storage_subsystem_id: + self.storage_subsystem_uri = storage_subsystem_uri + + if not self.storage_subsystem_uri: + return { + 'ret': False, + 'msg': "Provided Storage Subsystem ID %s does not exist on the server" % storage_subsystem_id} + + # Validate input parameters + required_parameters = ['RAIDType', 'Drives', 'CapacityBytes'] + allowed_parameters = ['DisplayName', 'InitializeMethod', 'MediaSpanCount', + 'Name', 'ReadCachePolicy', 'StripSizeBytes', 'VolumeUsage', 'WriteCachePolicy'] + + for parameter in required_parameters: + if not volume_details.get(parameter): + return { + 'ret': False, + 'msg': "%s are required parameter to create a volume" % str(required_parameters)} + + # Navigate to the volume uri of the correct storage subsystem + response = self.get_request(self.root_uri + self.storage_subsystem_uri) + if response['ret'] is False: + return response + data = response['data'] + + # Deleting any volumes of RAIDType None present on the Storage Subsystem + response = self.get_request(self.root_uri + data['Volumes']['@odata.id']) + if response['ret'] is False: + return response + volume_data = response['data'] + + if "Members" in volume_data: + for member in volume_data["Members"]: + response = self.get_request(self.root_uri + member['@odata.id']) + if response['ret'] is False: + return response + member_data = response['data'] + + if member_data["RAIDType"] == "None": + response = self.delete_request(self.root_uri + member['@odata.id']) + if response['ret'] is False: + return response + + # Construct payload and issue POST command to create volume + volume_details["Links"] = {} + volume_details["Links"]["Drives"] = [] + for drive in volume_details["Drives"]: + volume_details["Links"]["Drives"].append({"@odata.id": drive}) + del volume_details["Drives"] + payload = volume_details + response = self.post_request(self.root_uri + data['Volumes']['@odata.id'], payload) + if response['ret'] is False: + return response + + return {'ret': True, 'changed': True, + 'msg': "Volume Created"} diff --git a/plugins/modules/redfish_config.py b/plugins/modules/redfish_config.py index 1ccc543bc1..13b495df58 100644 --- a/plugins/modules/redfish_config.py +++ b/plugins/modules/redfish_config.py @@ -153,6 +153,13 @@ options: type: bool default: True version_added: '7.5.0' + volume_details: + required: false + description: + - Setting dict of volume to be created. + type: dict + default: {} + version_added: '7.5.0' author: - "Jose Delarosa (@jose-delarosa)" - "T S Kushal (@TSKushal)" @@ -313,6 +320,20 @@ EXAMPLES = ''' password: "{{ password }}" storage_subsystem_id: "DExxxxxx" volume_ids: ["volume1", "volume2"] + + - name: Create Volume + community.general.redfish_config: + category: Systems + command: CreateVolume + baseuri: "{{ baseuri }}" + username: "{{ username }}" + password: "{{ password }}" + storage_subsystem_id: "DExxxxxx" + volume_details: + Name: "MR Volume" + RAIDType: "RAID0" + Drives: + - "/redfish/v1/Systems/1/Storage/DE00B000/Drives/1" ''' RETURN = ''' @@ -331,7 +352,7 @@ from ansible.module_utils.common.text.converters import to_native # More will be added as module features are expanded CATEGORY_COMMANDS_ALL = { "Systems": ["SetBiosDefaultSettings", "SetBiosAttributes", "SetBootOrder", - "SetDefaultBootOrder", "EnableSecureBoot", "SetSecureBoot", "DeleteVolumes"], + "SetDefaultBootOrder", "EnableSecureBoot", "SetSecureBoot", "DeleteVolumes", "CreateVolume"], "Manager": ["SetNetworkProtocols", "SetManagerNic", "SetHostInterface"], "Sessions": ["SetSessionService"], } @@ -366,7 +387,8 @@ def main(): sessions_config=dict(type='dict', default={}), storage_subsystem_id=dict(type='str', default=''), volume_ids=dict(type='list', default=[], elements='str'), - secure_boot_enable=dict(type='bool', default=True) + secure_boot_enable=dict(type='bool', default=True), + volume_details=dict(type='dict', default={}) ), required_together=[ ('username', 'password'), @@ -433,6 +455,10 @@ def main(): # Set SecureBoot options secure_boot_enable = module.params['secure_boot_enable'] + # Volume creation options + volume_details = module.params['volume_details'] + storage_subsystem_id = module.params['storage_subsystem_id'] + # Build root URI root_uri = "https://" + module.params['baseuri'] rf_utils = RedfishUtils(creds, root_uri, timeout, module, @@ -470,6 +496,8 @@ def main(): result = rf_utils.set_secure_boot(secure_boot_enable) elif command == "DeleteVolumes": result = rf_utils.delete_volumes(storage_subsystem_id, volume_ids) + elif command == "CreateVolume": + result = rf_utils.create_volume(volume_details, storage_subsystem_id) elif category == "Manager": # execute only if we find a Manager service resource