-
Notifications
You must be signed in to change notification settings - Fork 0
CSTACKEX-114: Delete volume or qcow2 file NFS #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
19afcd1
87bf0f9
7a3fdda
40e8d87
a09af0f
0977378
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -168,16 +168,15 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet | |
| volumeVO.set_iScsiName(iscsiPath); | ||
| volumeVO.setPath(iscsiPath); | ||
| s_logger.info("createAsync: Volume [{}] iSCSI path set to {}", volumeVO.getId(), iscsiPath); | ||
| createCmdResult = new CreateCmdResult(null, new Answer(null, true, null)); | ||
|
|
||
| } else if (ProtocolType.NFS3.name().equalsIgnoreCase(details.get(Constants.PROTOCOL))) { | ||
| // For NFS, the hypervisor handles file creation; we only track pool association | ||
| createCmdResult = new CreateCmdResult(volInfo.getUuid(), new Answer(null, true, null)); | ||
| s_logger.info("createAsync: Managed NFS volume [{}] associated with pool {}", | ||
| volumeVO.getId(), storagePool.getId()); | ||
| } | ||
|
|
||
| volumeDao.update(volumeVO.getId(), volumeVO); | ||
| } | ||
| createCmdResult = new CreateCmdResult(null, new Answer(null, true, null)); | ||
| } else { | ||
| errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync"; | ||
| s_logger.error(errMsg); | ||
|
|
@@ -234,39 +233,15 @@ public void deleteAsync(DataStore store, DataObject data, AsyncCompletionCallbac | |
| s_logger.error("deleteAsync: Storage Pool not found for id: " + store.getId()); | ||
| throw new CloudRuntimeException("deleteAsync: Storage Pool not found for id: " + store.getId()); | ||
| } | ||
|
|
||
| Map<String, String> details = storagePoolDetailsDao.listDetailsKeyPairs(store.getId()); | ||
|
|
||
| if (ProtocolType.NFS3.name().equalsIgnoreCase(details.get(Constants.PROTOCOL))) { | ||
| // NFS file deletion is handled by the hypervisor; no ONTAP REST call needed | ||
| s_logger.info("deleteAsync: ManagedNFS volume {} - file deletion handled by hypervisor", data.getId()); | ||
|
|
||
| } else if (ProtocolType.ISCSI.name().equalsIgnoreCase(details.get(Constants.PROTOCOL))) { | ||
| StorageStrategy storageStrategy = Utility.getStrategyByStoragePoolDetails(details); | ||
| VolumeInfo volumeObject = (VolumeInfo) data; | ||
| s_logger.info("deleteAsync: Deleting LUN for volume id [{}]", volumeObject.getId()); | ||
|
|
||
| // Retrieve LUN identifiers stored during volume creation | ||
| String lunName = volumeDetailsDao.findDetail(volumeObject.getId(), Constants.LUN_DOT_NAME).getValue(); | ||
| String lunUUID = volumeDetailsDao.findDetail(volumeObject.getId(), Constants.LUN_DOT_UUID).getValue(); | ||
| if (lunName == null) { | ||
| throw new CloudRuntimeException("deleteAsync: Missing LUN name for volume " + volumeObject.getId()); | ||
| } | ||
|
|
||
| CloudStackVolume delRequest = new CloudStackVolume(); | ||
| Lun lun = new Lun(); | ||
| lun.setName(lunName); | ||
| lun.setUuid(lunUUID); | ||
| delRequest.setLun(lun); | ||
| storageStrategy.deleteCloudStackVolume(delRequest); | ||
|
|
||
| commandResult.setResult(null); | ||
| commandResult.setSuccess(true); | ||
| s_logger.info("deleteAsync: LUN [{}] deleted successfully", lunName); | ||
|
|
||
| } else { | ||
| throw new CloudRuntimeException("deleteAsync: Unsupported protocol: " + details.get(Constants.PROTOCOL)); | ||
| } | ||
| StorageStrategy storageStrategy = Utility.getStrategyByStoragePoolDetails(details); | ||
| s_logger.info("createCloudStackVolumeForTypeVolume: Connection to Ontap SVM [{}] successful, preparing CloudStackVolumeRequest", details.get(Constants.SVM_NAME)); | ||
| VolumeInfo volumeInfo = (VolumeInfo) data; | ||
| CloudStackVolume cloudStackVolumeRequest = createDeleteCloudStackVolumeRequest(storagePool,details,volumeInfo); | ||
| storageStrategy.deleteCloudStackVolume(cloudStackVolumeRequest); | ||
| s_logger.error("deleteAsync : Volume deleted: " + volumeInfo.getId()); | ||
| commandResult.setResult(null); | ||
| commandResult.setSuccess(true); | ||
| } | ||
| } catch (Exception e) { | ||
| s_logger.error("deleteAsync: Failed for data object [{}]: {}", data, e.getMessage()); | ||
|
|
@@ -339,9 +314,10 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore | |
|
|
||
| Map<String, String> details = storagePoolDetailsDao.listDetailsKeyPairs(storagePool.getId()); | ||
| String svmName = details.get(Constants.SVM_NAME); | ||
| String cloudStackVolumeName = volumeDetailsDao.findDetail(volumeVO.getId(), Constants.LUN_DOT_NAME).getValue(); | ||
|
|
||
| if (ProtocolType.ISCSI.name().equalsIgnoreCase(details.get(Constants.PROTOCOL))) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sandeeplocharla @piyush5netapp these have to be handled with strategy implementation we already have instead if-else for protocol. |
||
| // Only retrieve LUN name for iSCSI volumes | ||
| String cloudStackVolumeName = volumeDetailsDao.findDetail(volumeVO.getId(), Constants.LUN_DOT_NAME).getValue(); | ||
| UnifiedSANStrategy sanStrategy = (UnifiedSANStrategy) Utility.getStrategyByStoragePoolDetails(details); | ||
| String accessGroupName = Utility.getIgroupName(svmName, storagePoolUuid); | ||
|
|
||
|
|
@@ -360,8 +336,11 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore | |
| volumeVO.set_iScsiName(iscsiPath); | ||
| volumeVO.setPath(iscsiPath); | ||
| } | ||
| } else if (ProtocolType.NFS3.name().equalsIgnoreCase(details.get(Constants.PROTOCOL))) { | ||
| // For NFS, no access grant needed - file is accessible via mount | ||
| s_logger.debug("grantAccess: NFS volume [{}], no igroup mapping required", volumeVO.getUuid()); | ||
| return true; | ||
| } | ||
|
|
||
| volumeVO.setPoolType(storagePool.getPoolType()); | ||
| volumeVO.setPoolId(storagePool.getId()); | ||
| volumeDao.update(volumeVO.getId(), volumeVO); | ||
|
|
@@ -610,6 +589,37 @@ public boolean isStorageSupportHA(Storage.StoragePoolType type) { | |
|
|
||
| @Override | ||
| public void detachVolumeFromAllStorageNodes(Volume volume) { | ||
| } | ||
|
|
||
| private CloudStackVolume createDeleteCloudStackVolumeRequest(StoragePool storagePool, Map<String, String> details, VolumeInfo volumeInfo) { | ||
| CloudStackVolume cloudStackVolumeDeleteRequest = null; | ||
|
|
||
| String protocol = details.get(Constants.PROTOCOL); | ||
| ProtocolType protocolType = ProtocolType.valueOf(protocol); | ||
| switch (protocolType) { | ||
| case NFS3: | ||
piyush5netapp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| cloudStackVolumeDeleteRequest = new CloudStackVolume(); | ||
| cloudStackVolumeDeleteRequest.setDatastoreId(String.valueOf(storagePool.getId())); | ||
| cloudStackVolumeDeleteRequest.setVolumeInfo(volumeInfo); | ||
| break; | ||
| case ISCSI: | ||
| // Retrieve LUN identifiers stored during volume creation | ||
| String lunName = volumeDetailsDao.findDetail(volumeInfo.getId(), Constants.LUN_DOT_NAME).getValue(); | ||
| String lunUUID = volumeDetailsDao.findDetail(volumeInfo.getId(), Constants.LUN_DOT_UUID).getValue(); | ||
| if (lunName == null) { | ||
| throw new CloudRuntimeException("deleteAsync: Missing LUN name for volume " + volumeInfo.getId()); | ||
| } | ||
| cloudStackVolumeDeleteRequest = new CloudStackVolume(); | ||
| Lun lun = new Lun(); | ||
| lun.setName(lunName); | ||
| lun.setUuid(lunUUID); | ||
| cloudStackVolumeDeleteRequest.setLun(lun); | ||
| break; | ||
| default: | ||
| throw new CloudRuntimeException("createDeleteCloudStackVolumeRequest: Unsupported protocol " + protocol); | ||
|
|
||
| } | ||
| return cloudStackVolumeDeleteRequest; | ||
|
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -230,7 +230,9 @@ public DataStore initialize(Map<String, Object> dsInfos) { | |
| parameters.setType(Storage.StoragePoolType.NetworkFilesystem); | ||
| path = Constants.SLASH + storagePoolName; | ||
| port = Constants.NFS3_PORT; | ||
| s_logger.info("Setting NFS path for storage pool: " + path + ", port: " + port); | ||
| // Force NFSv3 for ONTAP managed storage to avoid NFSv4 ID mapping issues | ||
| details.put("nfsmountopts", "vers=3"); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lets put hardcoding in constants |
||
| s_logger.info("Setting NFS path for storage pool: " + path + ", port: " + port + " with mount option: vers=3"); | ||
| break; | ||
| case ISCSI: | ||
| parameters.setType(Storage.StoragePoolType.Iscsi); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,7 @@ | |
| import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; | ||
| import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; | ||
| import org.apache.cloudstack.storage.command.CreateObjectCommand; | ||
| import org.apache.cloudstack.storage.command.DeleteCommand; | ||
| import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; | ||
| import org.apache.cloudstack.storage.feign.FeignClientFactory; | ||
| import org.apache.cloudstack.storage.feign.client.JobFeignClient; | ||
|
|
@@ -93,12 +94,12 @@ public CloudStackVolume createCloudStackVolume(CloudStackVolume cloudstackVolume | |
| Answer answer = createVolumeOnKVMHost(cloudstackVolume.getVolumeInfo()); | ||
| if (answer == null || !answer.getResult()) { | ||
| String errMsg = answer != null ? answer.getDetails() : "Failed to create qcow2 on KVM host"; | ||
| s_logger.error("createCloudStackVolumeForTypeVolume: " + errMsg); | ||
| s_logger.error("createCloudStackVolume: " + errMsg); | ||
| throw new CloudRuntimeException(errMsg); | ||
| } | ||
| return cloudstackVolume; | ||
| }catch (Exception e) { | ||
| s_logger.error("createCloudStackVolumeForTypeVolume: error occured " + e); | ||
| s_logger.error("createCloudStackVolume: error occured " + e); | ||
| throw new CloudRuntimeException(e); | ||
| } | ||
| } | ||
|
|
@@ -111,7 +112,19 @@ CloudStackVolume updateCloudStackVolume(CloudStackVolume cloudstackVolume) { | |
|
|
||
| @Override | ||
| public void deleteCloudStackVolume(CloudStackVolume cloudstackVolume) { | ||
| //TODO | ||
| s_logger.info("deleteCloudStackVolume: Delete cloudstack volume " + cloudstackVolume); | ||
| try { | ||
| // Step 1: Send command to KVM host to delete qcow2 file using qemu-img | ||
| Answer answer = deleteVolumeOnKVMHost(cloudstackVolume.getVolumeInfo()); | ||
| if (answer == null || !answer.getResult()) { | ||
| String errMsg = answer != null ? answer.getDetails() : "Failed to delete qcow2 on KVM host"; | ||
| s_logger.error("deleteCloudStackVolume: " + errMsg); | ||
| throw new CloudRuntimeException(errMsg); | ||
| } | ||
| }catch (Exception e) { | ||
| s_logger.error("deleteCloudStackVolume: error occured " + e); | ||
| throw new CloudRuntimeException(e); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -445,7 +458,7 @@ private ExportPolicy createExportPolicyRequest(AccessGroup accessGroup,String sv | |
| exportClients.add(exportClient); | ||
| } | ||
| exportRule.setClients(exportClients); | ||
| exportRule.setProtocols(List.of(ExportRule.ProtocolsEnum.any)); | ||
| exportRule.setProtocols(List.of(ExportRule.ProtocolsEnum.nfs3)); | ||
| exportRule.setRoRule(List.of("sys")); | ||
| exportRule.setRwRule(List.of("sys")); | ||
| exportRule.setSuperuser(List.of("sys")); | ||
|
|
@@ -508,4 +521,31 @@ private Answer createVolumeOnKVMHost(DataObject volumeInfo) { | |
| return new Answer(null, false, e.toString()); | ||
| } | ||
| } | ||
|
|
||
| private Answer deleteVolumeOnKVMHost(DataObject volumeInfo) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a way to include this in cloudstack core code, instead of having it here? |
||
| s_logger.info("deleteVolumeOnKVMHost called with volumeInfo: {} ", volumeInfo); | ||
|
|
||
| try { | ||
| s_logger.info("deleteVolumeOnKVMHost: Sending DeleteCommand to KVM agent for volume: {}", volumeInfo.getUuid()); | ||
| DeleteCommand cmd = new DeleteCommand(volumeInfo.getTO()); | ||
| EndPoint ep = epSelector.select(volumeInfo); | ||
| if (ep == null) { | ||
| String errMsg = "No remote endpoint to send DeleteCommand, check if host is up"; | ||
| s_logger.error(errMsg); | ||
| return new Answer(cmd, false, errMsg); | ||
| } | ||
| s_logger.info("deleteVolumeOnKVMHost: Sending command to endpoint: {}", ep.getHostAddr()); | ||
| Answer answer = ep.sendMessage(cmd); | ||
| if (answer != null && answer.getResult()) { | ||
| s_logger.info("deleteVolumeOnKVMHost: Successfully deleted qcow2 file on KVM host"); | ||
| } else { | ||
| s_logger.error("deleteVolumeOnKVMHost: Failed to delete qcow2 file: {}", | ||
| answer != null ? answer.getDetails() : "null answer"); | ||
| } | ||
| return answer; | ||
| } catch (Exception e) { | ||
| s_logger.error("deleteVolumeOnKVMHost: Exception sending DeleteCommand", e); | ||
| return new Answer(null, false, e.toString()); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these has to be refactored using strategy patterns. please create a task in the back log to be picked without fail.