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 00000000000..96bd532c0d5 --- /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 fc6e11b3e77..2ee41769329 100644 --- a/plugins/module_utils/redfish_utils.py +++ b/plugins/module_utils/redfish_utils.py @@ -3544,3 +3544,86 @@ def delete_volumes(self, storage_subsystem_id, volume_ids): 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 65d933bdbd2..e3f498952f1 100644 --- a/plugins/modules/redfish_config.py +++ b/plugins/modules/redfish_config.py @@ -152,6 +152,13 @@ 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)" @@ -312,6 +319,20 @@ 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 = ''' @@ -330,7 +351,7 @@ # 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"], } @@ -365,7 +386,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'), @@ -422,6 +444,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, @@ -459,6 +485,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