From 19afcd16874cfcd342f204d574b786f0453904a2 Mon Sep 17 00:00:00 2001 From: "Srivastava, Piyush" Date: Tue, 10 Feb 2026 10:32:38 +0530 Subject: [PATCH 1/4] CSTACKEX-114: Delete volume or qcow2 file NFS --- .../driver/OntapPrimaryDatastoreDriver.java | 28 +++++++++-- .../storage/service/StorageStrategy.java | 2 +- .../storage/service/UnifiedNASStrategy.java | 48 +++++++++++++++++-- .../storage/service/UnifiedSANStrategy.java | 2 +- .../storage/service/StorageStrategyTest.java | 2 +- 5 files changed, 71 insertions(+), 11 deletions(-) diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java index 5e79aa2298da..1542ca1e7569 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java @@ -158,10 +158,12 @@ public void deleteAsync(DataStore store, DataObject data, AsyncCompletionCallbac throw new CloudRuntimeException("deleteAsync : Storage Pool not found for id: " + store.getId()); } Map details = storagePoolDetailsDao.listDetailsKeyPairs(store.getId()); - if (ProtocolType.NFS3.name().equalsIgnoreCase(details.get(Constants.PROTOCOL))) { - // ManagedNFS qcow2 backing file deletion handled by KVM host/libvirt; nothing to do via ONTAP REST. - s_logger.info("deleteAsync: ManagedNFS volume {} no-op ONTAP deletion", data.getId()); - } + 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()); } } catch (Exception e) { commandResult.setResult(e.getMessage()); @@ -291,6 +293,24 @@ public boolean isStorageSupportHA(Storage.StoragePoolType type) { @Override public void detachVolumeFromAllStorageNodes(Volume volume) { + } + + private CloudStackVolume createDeleteCloudStackVolumeRequest(StoragePool storagePool, Map details, VolumeInfo volumeInfo) { + CloudStackVolume cloudStackVolumeRequest = null; + + String protocol = details.get(Constants.PROTOCOL); + ProtocolType protocolType = ProtocolType.valueOf(protocol); + switch (protocolType) { + case NFS3: + cloudStackVolumeRequest = new CloudStackVolume(); + cloudStackVolumeRequest.setDatastoreId(String.valueOf(storagePool.getId())); + cloudStackVolumeRequest.setVolumeInfo(volumeInfo); + break; + default: + throw new CloudRuntimeException("createDeleteCloudStackVolumeRequest: Unsupported protocol " + protocol); + + } + return cloudStackVolumeRequest; } } diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java index 822e09851f39..e2849053997e 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java @@ -472,7 +472,7 @@ public String getNetworkInterface() { * * @param cloudstackVolume the CloudStack volume to delete */ - abstract void deleteCloudStackVolume(CloudStackVolume cloudstackVolume); + abstract public void deleteCloudStackVolume(CloudStackVolume cloudstackVolume); /** * Method encapsulates the behavior based on the opted protocol in subclasses. diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java index d75f2e695b10..287c7d721d7b 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java @@ -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); } } @@ -110,8 +111,20 @@ CloudStackVolume updateCloudStackVolume(CloudStackVolume cloudstackVolume) { } @Override - void deleteCloudStackVolume(CloudStackVolume cloudstackVolume) { - //TODO + public void deleteCloudStackVolume(CloudStackVolume cloudstackVolume) { + 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 @@ -493,4 +506,31 @@ private Answer createVolumeOnKVMHost(DataObject volumeInfo) { return new Answer(null, false, e.toString()); } } + + private Answer deleteVolumeOnKVMHost(DataObject volumeInfo) { + 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()); + } + } } diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedSANStrategy.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedSANStrategy.java index 7b5372c69bdd..ff9b2248b1b8 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedSANStrategy.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedSANStrategy.java @@ -99,7 +99,7 @@ CloudStackVolume updateCloudStackVolume(CloudStackVolume cloudstackVolume) { } @Override - void deleteCloudStackVolume(CloudStackVolume cloudstackVolume) { + public void deleteCloudStackVolume(CloudStackVolume cloudstackVolume) { //TODO } diff --git a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/StorageStrategyTest.java b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/StorageStrategyTest.java index d298a6afe937..6728c8a85170 100644 --- a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/StorageStrategyTest.java +++ b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/StorageStrategyTest.java @@ -134,7 +134,7 @@ org.apache.cloudstack.storage.service.model.CloudStackVolume updateCloudStackVol } @Override - void deleteCloudStackVolume(org.apache.cloudstack.storage.service.model.CloudStackVolume cloudstackVolume) { + public void deleteCloudStackVolume(org.apache.cloudstack.storage.service.model.CloudStackVolume cloudstackVolume) { } @Override From 87bf0f99432e448b55c36572fffea421c1b39784 Mon Sep 17 00:00:00 2001 From: "Srivastava, Piyush" Date: Wed, 11 Feb 2026 14:16:58 +0530 Subject: [PATCH 2/4] CSTACKEX-114: Updated UT and review comments --- .../driver/OntapPrimaryDatastoreDriver.java | 1 + .../service/UnifiedNASStrategyTest.java | 71 +++++++++++++++++++ 2 files changed, 72 insertions(+) mode change 100644 => 100755 plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java mode change 100644 => 100755 plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java old mode 100644 new mode 100755 index 1542ca1e7569..ee9ae67a0949 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java @@ -162,6 +162,7 @@ public void deleteAsync(DataStore store, DataObject data, AsyncCompletionCallbac 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); + // NFS qcow2 backing file deletion handled by KVM host/libvirt; nothing to do via ONTAP REST. storageStrategy.deleteCloudStackVolume(cloudStackVolumeRequest); s_logger.error("deleteAsync : Volume deleted: " + volumeInfo.getId()); } diff --git a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java old mode 100644 new mode 100755 index 1310ceafab7a..cb0e440f1bc4 --- a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java +++ b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java @@ -27,6 +27,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.feign.client.JobFeignClient; @@ -534,4 +535,74 @@ public void testDeleteAccessGroup_Failed() { strategy.deleteAccessGroup(accessGroup); }); } + + // Test deleteCloudStackVolume - Success + @Test + public void testDeleteCloudStackVolume_Success() throws Exception { + CloudStackVolume cloudStackVolume = mock(CloudStackVolume.class); + VolumeInfo volumeInfo = mock(VolumeInfo.class); + EndPoint endpoint = mock(EndPoint.class); + Answer answer = mock(Answer.class); + + when(cloudStackVolume.getVolumeInfo()).thenReturn(volumeInfo); + when(epSelector.select(volumeInfo)).thenReturn(endpoint); + when(endpoint.sendMessage(any())).thenReturn(answer); + when(answer.getResult()).thenReturn(true); + + // Execute - should not throw exception + strategy.deleteCloudStackVolume(cloudStackVolume); + + // Verify endpoint was selected and message sent + verify(epSelector).select(volumeInfo); + verify(endpoint).sendMessage(any()); + } + + // Test deleteCloudStackVolume - Endpoint Not Found + @Test + public void testDeleteCloudStackVolume_EndpointNotFound() { + CloudStackVolume cloudStackVolume = mock(CloudStackVolume.class); + VolumeInfo volumeInfo = mock(VolumeInfo.class); + + when(cloudStackVolume.getVolumeInfo()).thenReturn(volumeInfo); + when(epSelector.select(volumeInfo)).thenReturn(null); + + assertThrows(CloudRuntimeException.class, () -> { + strategy.deleteCloudStackVolume(cloudStackVolume); + }); + } + + // Test deleteCloudStackVolume - Answer Result False + @Test + public void testDeleteCloudStackVolume_AnswerResultFalse() throws Exception { + CloudStackVolume cloudStackVolume = mock(CloudStackVolume.class); + VolumeInfo volumeInfo = mock(VolumeInfo.class); + EndPoint endpoint = mock(EndPoint.class); + Answer answer = mock(Answer.class); + + when(cloudStackVolume.getVolumeInfo()).thenReturn(volumeInfo); + when(epSelector.select(volumeInfo)).thenReturn(endpoint); + when(endpoint.sendMessage(any())).thenReturn(answer); + when(answer.getResult()).thenReturn(false); + when(answer.getDetails()).thenReturn("Failed to delete volume file"); + + assertThrows(CloudRuntimeException.class, () -> { + strategy.deleteCloudStackVolume(cloudStackVolume); + }); + } + + // Test deleteCloudStackVolume - Answer is Null + @Test + public void testDeleteCloudStackVolume_AnswerNull() throws Exception { + CloudStackVolume cloudStackVolume = mock(CloudStackVolume.class); + VolumeInfo volumeInfo = mock(VolumeInfo.class); + EndPoint endpoint = mock(EndPoint.class); + + when(cloudStackVolume.getVolumeInfo()).thenReturn(volumeInfo); + when(epSelector.select(volumeInfo)).thenReturn(endpoint); + when(endpoint.sendMessage(any())).thenReturn(null); + + assertThrows(CloudRuntimeException.class, () -> { + strategy.deleteCloudStackVolume(cloudStackVolume); + }); + } } From 40e8d87e427278b8c7026421719df3f7d41fbe60 Mon Sep 17 00:00:00 2001 From: "Srivastava, Piyush" Date: Wed, 11 Feb 2026 14:48:32 +0530 Subject: [PATCH 3/4] CSTACKEX-114: resolved UT failure --- .../storage/driver/OntapPrimaryDatastoreDriverTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriverTest.java b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriverTest.java index b9fe71ec199c..d050d379563c 100644 --- a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriverTest.java +++ b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriverTest.java @@ -308,7 +308,6 @@ void testDeleteAsync_NFSVolume_Success() { when(dataStore.getId()).thenReturn(1L); when(volumeInfo.getType()).thenReturn(VOLUME); - when(volumeInfo.getId()).thenReturn(100L); when(storagePoolDao.findById(1L)).thenReturn(storagePool); when(storagePoolDetailsDao.listDetailsKeyPairs(1L)).thenReturn(storagePoolDetails); From a09af0f0a5ec50429f566854e3c891336ddad7d6 Mon Sep 17 00:00:00 2001 From: "Srivastava, Piyush" Date: Mon, 16 Feb 2026 11:15:31 +0530 Subject: [PATCH 4/4] CSTACKEX-114:integration testing changes --- .../storage/driver/OntapPrimaryDatastoreDriver.java | 13 ++++++++----- .../lifecycle/OntapPrimaryDatastoreLifecycle.java | 4 +++- .../storage/listener/OntapHostListener.java | 12 ++++++++++-- .../storage/service/UnifiedNASStrategy.java | 2 +- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java index 27541ed25dd7..9ab57dc60a62 100755 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java @@ -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); @@ -315,9 +314,10 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore Map 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))) { + // 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); @@ -336,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); diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycle.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycle.java index a7df490b9b95..f54217204222 100755 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycle.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycle.java @@ -255,7 +255,9 @@ public DataStore initialize(Map 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"); + 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); diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/listener/OntapHostListener.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/listener/OntapHostListener.java index 30c698995a8f..fd527d285285 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/listener/OntapHostListener.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/listener/OntapHostListener.java @@ -37,9 +37,12 @@ import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; import com.cloud.host.dao.HostDao; +import java.util.Map; + public class OntapHostListener implements HypervisorHostListener { protected Logger logger = LogManager.getLogger(getClass()); @@ -51,7 +54,10 @@ public class OntapHostListener implements HypervisorHostListener { private PrimaryDataStoreDao _storagePoolDao; @Inject private HostDao _hostDao; - @Inject private StoragePoolHostDao storagePoolHostDao; + @Inject + private StoragePoolHostDao storagePoolHostDao; + @Inject + private StoragePoolDetailsDao _storagePoolDetailsDao; @Override @@ -71,10 +77,12 @@ public boolean hostConnect(long hostId, long poolId) { } logger.info("Connecting host {} to ONTAP storage pool {}", host.getName(), pool.getName()); try { + // Load storage pool details from database to pass mount options and other config to agent + Map detailsMap = _storagePoolDetailsDao.listDetailsKeyPairs(poolId); // Create the ModifyStoragePoolCommand to send to the agent // Note: Always send command even if database entry exists, because agent may have restarted // and lost in-memory pool registration. The command handler is idempotent. - ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool); + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool, detailsMap); Answer answer = _agentMgr.easySend(hostId, cmd); diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java index b800d66432fe..26355456b6c9 100644 --- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java +++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java @@ -458,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"));