From 8b7775603084c673955a841ec0ef6741c19f5df2 Mon Sep 17 00:00:00 2001 From: sandeeplocharla Date: Wed, 19 Aug 2026 21:39:16 +0530 Subject: [PATCH] Change the minimum storagepool size to 20MB and throw an exception in case of invalid capacity bytes instead of adjusting to minimum requirement --- plugins/storage/volume/ontap/README.md | 4 +- .../OntapPrimaryDatastoreLifecycle.java | 20 +++--- .../OntapPrimaryDatastoreLifecycleTest.java | 63 ++++++++++++++----- 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/plugins/storage/volume/ontap/README.md b/plugins/storage/volume/ontap/README.md index e7e066aafb55..4bccc7fe2bbc 100644 --- a/plugins/storage/volume/ontap/README.md +++ b/plugins/storage/volume/ontap/README.md @@ -65,7 +65,7 @@ The NetApp ONTAP Storage Plugin provides integration between Apache CloudStack a ### Minimum Volume Size -ONTAP requires a minimum volume size of **1.56 GB** (1,677,721,600 bytes). The plugin will automatically adjust requested sizes below this threshold. +ONTAP requires a minimum volume size of **20 MB** (20,971,520 bytes). Requests below this threshold are rejected. ## Configuration @@ -116,7 +116,7 @@ username=admin;password=secretpass;svmName=svm1;protocol=ISCSI;managementLIF=192 3. **Capacity Errors** - Check aggregate space availability - - Ensure requested volume size meets minimum requirements (1.56 GB) + - Ensure requested volume size meets minimum requirements (20 MB) 4. **Host Connection Issues** - For iSCSI: Verify host IQN is properly configured in host's storage URL 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 c002db728dd1..8e8150e24e2c 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 @@ -83,7 +83,7 @@ public class OntapPrimaryDatastoreLifecycle extends BasePrimaryDataStoreLifeCycl @Inject private AlertManager _alertMgr; private static final Logger logger = LogManager.getLogger(OntapPrimaryDatastoreLifecycle.class); - private static final long ONTAP_MIN_VOLUME_SIZE_IN_BYTES = 1677721600L; + private static final long ONTAP_MIN_VOLUME_SIZE_IN_BYTES = 20971520L; /** * Creates primary storage on NetApp storage @@ -113,7 +113,7 @@ public DataStore initialize(Map dsInfos) { @SuppressWarnings("unchecked") Map details = (Map) dsInfos.get("details"); - capacityBytes = validateInitializeInputs(capacityBytes, podId, clusterId, zoneId, storagePoolName, providerName, managed, details); + validateInitializeInputs(capacityBytes, podId, clusterId, zoneId, storagePoolName, providerName, managed, details); PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters(); if (clusterId != null) { @@ -212,16 +212,16 @@ public DataStore initialize(Map dsInfos) { return _dataStoreHelper.createPrimaryDataStore(parameters); } - private long validateInitializeInputs(Long capacityBytes, Long podId, Long clusterId, Long zoneId, + private void validateInitializeInputs(Long capacityBytes, Long podId, Long clusterId, Long zoneId, String storagePoolName, String providerName, boolean managed, Map details) { - // Validate and set capacity if (capacityBytes == null || capacityBytes <= 0) { - logger.warn("capacityBytes not provided or invalid (" + capacityBytes + "), using ONTAP minimum size: " + ONTAP_MIN_VOLUME_SIZE_IN_BYTES); - capacityBytes = ONTAP_MIN_VOLUME_SIZE_IN_BYTES; - } else if (capacityBytes < ONTAP_MIN_VOLUME_SIZE_IN_BYTES) { - logger.warn("capacityBytes (" + capacityBytes + ") is below ONTAP minimum (" + ONTAP_MIN_VOLUME_SIZE_IN_BYTES + "), adjusting to minimum"); - capacityBytes = ONTAP_MIN_VOLUME_SIZE_IN_BYTES; + throw new InvalidParameterValueException("Storage pool capacity is required for ONTAP primary storage and must be at least " + + ONTAP_MIN_VOLUME_SIZE_IN_BYTES + " bytes (20 MB)"); + } + if (capacityBytes < ONTAP_MIN_VOLUME_SIZE_IN_BYTES) { + throw new InvalidParameterValueException("Storage pool capacity " + capacityBytes + " bytes is below the ONTAP minimum volume size of " + + ONTAP_MIN_VOLUME_SIZE_IN_BYTES + " bytes (20 MB)"); } // Validate scope @@ -278,8 +278,6 @@ private long validateInitializeInputs(Long capacityBytes, Long podId, Long clust missing.removeAll(providedKeys); throw new CloudRuntimeException("ONTAP primary storage creation failed, missing detail(s): " + missing); } - - return capacityBytes; } private void processDataLifSelection(Pair lifResult, Map details, 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 ed538de4a49c..0a82cee17e6c 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 @@ -32,6 +32,7 @@ import org.mockito.quality.Strictness; import org.apache.cloudstack.storage.feign.model.Volume; import com.cloud.dc.dao.ClusterDao; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.dc.ClusterVO; import com.cloud.host.HostVO; @@ -178,7 +179,7 @@ public void testInitialize_positive() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes",200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed",true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -212,7 +213,7 @@ public void testInitialize_missingRequiredDetailKey() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes",200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed",true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -249,7 +250,37 @@ public void testInitialize_invalidCapacityBytes() { try (MockedStatic storageProviderFactory = Mockito.mockStatic(StorageProviderFactory.class)) { storageProviderFactory.when(() -> StorageProviderFactory.getStrategy(any())).thenReturn(storageStrategy); - ontapPrimaryDatastoreLifecycle.initialize(dsInfos); + Exception ex = assertThrows(InvalidParameterValueException.class, () -> ontapPrimaryDatastoreLifecycle.initialize(dsInfos)); + assertTrue(ex.getMessage().contains("must be at least")); + } + } + + @Test + public void testInitialize_capacityBelowOntapMinimum() { + + 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("clusterId", 1L); + dsInfos.put("name", "testStoragePool"); + dsInfos.put("providerName", "testProvider"); + dsInfos.put("capacityBytes", 20971519L); + dsInfos.put("managed",true); + dsInfos.put("tags", "testTag"); + dsInfos.put("isTagARule", false); + dsInfos.put("details", detailsMap); + + try (MockedStatic storageProviderFactory = Mockito.mockStatic(StorageProviderFactory.class)) { + storageProviderFactory.when(() -> StorageProviderFactory.getStrategy(any())).thenReturn(storageStrategy); + Exception ex = assertThrows(InvalidParameterValueException.class, () -> ontapPrimaryDatastoreLifecycle.initialize(dsInfos)); + assertTrue(ex.getMessage().contains("below the ONTAP minimum volume size")); } } @@ -261,7 +292,7 @@ public void testInitialize_unmanagedStorage() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes",200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed",false); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -284,7 +315,7 @@ public void testInitialize_nullStoragePoolName() { dsInfos.put("clusterId", 1L); dsInfos.put("name", null); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes",200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed",true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -307,7 +338,7 @@ public void testInitialize_nullProviderName() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", null); - dsInfos.put("capacityBytes",200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed",true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -330,7 +361,7 @@ public void testInitialize_nullPodAndClusterAndZone() { dsInfos.put("clusterId", null); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes",200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed",true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -364,7 +395,7 @@ public void testInitialize_clusterNotKVM() { dsInfos.put("clusterId", 2L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes", 200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed", true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -396,7 +427,7 @@ public void testInitialize_unexpectedDetailKey() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes",200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed",true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -428,7 +459,7 @@ public void testInitialize_dataLifWithWarning() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes", 200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed", true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -464,7 +495,7 @@ public void testInitialize_nullDataLif() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes", 200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed", true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -495,7 +526,7 @@ public void testInitialize_emptyDataLif() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes", 200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed", true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -526,7 +557,7 @@ public void testInitialize_getNetworkInterfaceException() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes", 200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed", true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -558,7 +589,7 @@ public void testInitialize_volumeCreationFailure_nullVolume() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes", 200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed", true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -589,7 +620,7 @@ public void testInitialize_volumeCreationException() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes", 200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed", true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false); @@ -621,7 +652,7 @@ public void testInitialize_positiveWithDetailAssertions() { dsInfos.put("clusterId", 1L); dsInfos.put("name", "testStoragePool"); dsInfos.put("providerName", "testProvider"); - dsInfos.put("capacityBytes", 200000L); + dsInfos.put("capacityBytes", 1073741824L); dsInfos.put("managed", true); dsInfos.put("tags", "testTag"); dsInfos.put("isTagARule", false);