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..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,9 +347,16 @@ 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 (!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); + 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()); 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..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)) { @@ -802,4 +809,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)); + } + } + }