From d623db04028fff6f86b9eded0625a56505decf9c Mon Sep 17 00:00:00 2001 From: "Srivastava, Piyush" Date: Mon, 29 Jun 2026 10:39:12 +0530 Subject: [PATCH 1/4] bugfix/CSTACKEX-188: fixed hypervisor for zone scope --- .../storage/lifecycle/OntapPrimaryDatastoreLifecycle.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 d7b89de25461..e6463728eff4 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 @@ -347,9 +347,14 @@ public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.Hyper logger.error("attachZone : Storage Pool not found for id: " + dataStore.getId()); throw new CloudRuntimeException("Storage Pool not found for id: " + dataStore.getId()); } + if(hypervisorType != null && hypervisorType == Hypervisor.HypervisorType.None && storagePool.getHypervisor() == null){ + storagePool.setHypervisor(hypervisorType); + storagePoolDao.update(storagePool.getId(),storagePool); + logger.debug("attachZone : Set Hypervisor type for storage pool {} to {}", storagePool.getName(), hypervisorType); + } PrimaryDataStoreInfo primaryStore = (PrimaryDataStoreInfo)dataStore; - List hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), Hypervisor.HypervisorType.KVM); + List hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), hypervisorType); logger.debug(String.format("In createPool. Attaching the pool to each of the hosts in %s.", hostsToConnect)); Map details = storagePoolDetailsDao.listDetailsKeyPairs(primaryStore.getId()); From 193f72cc83df2874fd1af9f966f106c1df3f5d45 Mon Sep 17 00:00:00 2001 From: "Srivastava, Piyush" Date: Mon, 29 Jun 2026 10:45:07 +0530 Subject: [PATCH 2/4] bugfix/CSTACKEX-188: fixed hypervisor validation check --- .../lifecycle/OntapPrimaryDatastoreLifecycle.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) 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 e6463728eff4..434283a2dbf2 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 @@ -347,11 +347,12 @@ public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.Hyper logger.error("attachZone : Storage Pool not found for id: " + dataStore.getId()); throw new CloudRuntimeException("Storage Pool not found for id: " + dataStore.getId()); } - if(hypervisorType != null && hypervisorType == Hypervisor.HypervisorType.None && storagePool.getHypervisor() == null){ - storagePool.setHypervisor(hypervisorType); - storagePoolDao.update(storagePool.getId(),storagePool); - logger.debug("attachZone : Set Hypervisor type for storage pool {} to {}", storagePool.getName(), hypervisorType); + if (hypervisorType != null && hypervisorType != Hypervisor.HypervisorType.KVM) { + throw new CloudRuntimeException("ONTAP primary storage is supported only for KVM hypervisor"); } + storagePool.setHypervisor(hypervisorType); + storagePoolDao.update(storagePool.getId(),storagePool); + logger.debug("attachZone : Set Hypervisor type for storage pool {} to {}", storagePool.getName(), hypervisorType); PrimaryDataStoreInfo primaryStore = (PrimaryDataStoreInfo)dataStore; List hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), hypervisorType); From 697833cd109c9f3347ca4494d78f4a380774af53 Mon Sep 17 00:00:00 2001 From: "Srivastava, Piyush" Date: Tue, 30 Jun 2026 21:49:18 +0530 Subject: [PATCH 3/4] bugfix/CSTACKEX-188: junit and hypervisor check --- .../OntapPrimaryDatastoreLifecycle.java | 3 +- .../OntapPrimaryDatastoreLifecycleTest.java | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) 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 434283a2dbf2..0d27d115783b 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 @@ -347,7 +347,8 @@ public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.Hyper logger.error("attachZone : Storage Pool not found for id: " + dataStore.getId()); throw new CloudRuntimeException("Storage Pool not found for id: " + dataStore.getId()); } - if (hypervisorType != null && hypervisorType != Hypervisor.HypervisorType.KVM) { + if (!Hypervisor.HypervisorType.KVM.equals(hypervisorType)){ + logger.error("attachZone : ONTAP primary storage is supported only for KVM hypervisor"); throw new CloudRuntimeException("ONTAP primary storage is supported only for KVM hypervisor"); } storagePool.setHypervisor(hypervisorType); diff --git a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycleTest.java b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycleTest.java index 604ab400474c..de2efa8cd331 100644 --- a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycleTest.java +++ b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycleTest.java @@ -802,4 +802,49 @@ public void testAttachZone_createAccessGroupCalled() throws Exception { } } + @Test + public void testAttachZone_nonKvmHypervisorThrowsException() { + // Non-KVM hypervisor type must be rejected before any further processing + Exception ex = assertThrows(CloudRuntimeException.class, () -> + ontapPrimaryDatastoreLifecycle.attachZone( + dataStore, zoneScope, Hypervisor.HypervisorType.VMware)); + + assertTrue(ex.getMessage().contains("ONTAP primary storage is supported only for KVM hypervisor")); + // update should never be reached + verify(storagePoolDao, times(0)).update(anyLong(), any(StoragePoolVO.class)); + } + + @Test + public void testAttachZone_nullHypervisorThrowsException() { + // null hypervisorType is not a valid case — only KVM is accepted + Exception ex = assertThrows(CloudRuntimeException.class, () -> + ontapPrimaryDatastoreLifecycle.attachZone(dataStore, zoneScope, null)); + + assertTrue(ex.getMessage().contains("ONTAP primary storage is supported only for KVM hypervisor")); + verify(storagePoolDao, times(0)).update(anyLong(), any(StoragePoolVO.class)); + } + + @Test + public void testAttachZone_kvmHypervisorSetsAndUpdatesPool() throws Exception { + // KVM hypervisorType should be set on the pool and persisted via storagePoolDao.update + when(zoneScope.getScopeId()).thenReturn(1L); + when(_resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(any(), eq(1L), eq(Hypervisor.HypervisorType.KVM))) + .thenReturn(mockHosts); + when(storagePoolDetailsDao.listDetailsKeyPairs(1L)).thenReturn(poolDetails); + when(_dataStoreHelper.attachZone(any(DataStore.class))).thenReturn(dataStore); + + try (MockedStatic utilityMock = Mockito.mockStatic(OntapStorageUtils.class)) { + utilityMock.when(() -> OntapStorageUtils.getStrategyByStoragePoolDetails(any())) + .thenReturn(storageStrategy); + when(storageStrategy.createAccessGroup(any(AccessGroup.class))).thenReturn(null); + when(_storageMgr.connectHostToSharedPool(any(HostVO.class), anyLong())).thenReturn(true); + + boolean result = ontapPrimaryDatastoreLifecycle.attachZone( + dataStore, zoneScope, Hypervisor.HypervisorType.KVM); + + assertTrue(result, "attachZone should succeed for KVM hypervisor"); + verify(storagePoolDao, times(1)).update(eq(1L), any(StoragePoolVO.class)); + } + } + } From 60d365a8d5ef3dc94bdedf246984d0062446fabd Mon Sep 17 00:00:00 2001 From: "Srivastava, Piyush" Date: Wed, 1 Jul 2026 12:44:43 +0530 Subject: [PATCH 4/4] bugfix/CSTACKEX-188: junit addition --- .../OntapPrimaryDatastoreLifecycleTest.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycleTest.java b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycleTest.java index de2efa8cd331..3b576df97e37 100644 --- a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycleTest.java +++ b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycleTest.java @@ -344,17 +344,24 @@ public void testInitialize_clusterNotKVM() { clusterVO.setHypervisorType("XenServer"); when(_clusterDao.findById(2L)).thenReturn(clusterVO); + HashMap detailsMap = new HashMap<>(); + detailsMap.put(OntapStorageConstants.USERNAME, "testUser"); + detailsMap.put(OntapStorageConstants.PASSWORD, "testPassword"); + detailsMap.put(OntapStorageConstants.STORAGE_IP, "10.10.10.10"); + detailsMap.put(OntapStorageConstants.SVM_NAME, "vs0"); + detailsMap.put(OntapStorageConstants.PROTOCOL, "NFS3"); + Map dsInfos = new HashMap<>(); - dsInfos.put("zoneId",1L); - dsInfos.put("podId",1L); + dsInfos.put("zoneId", 1L); + dsInfos.put("podId", 1L); dsInfos.put("clusterId", 2L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes",200000L); - dsInfos.put("managed",true); + dsInfos.put("capacityBytes", 200000L); + dsInfos.put("managed", true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); - dsInfos.put("details", new HashMap()); + dsInfos.put("details", detailsMap); Exception ex = assertThrows(CloudRuntimeException.class, () -> { try (MockedStatic storageProviderFactory = Mockito.mockStatic(StorageProviderFactory.class)) {