Skip to content

Enhancing storagepool operations and snapshot related fixes in NetApp ONTAP storage plugin - #13897

Open
sandeeplocharla wants to merge 15 commits into
apache:mainfrom
NetApp:netapp-ontap-fixes
Open

Enhancing storagepool operations and snapshot related fixes in NetApp ONTAP storage plugin#13897
sandeeplocharla wants to merge 15 commits into
apache:mainfrom
NetApp:netapp-ontap-fixes

Conversation

@sandeeplocharla

@sandeeplocharla sandeeplocharla commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Description

This PR has contributions from @rajiv-jain-netapp, @suryag1201, @piyush5netapp, @sathvikaragi, and @sandeeplocharla.

Summary

Bug Fixes

  • Fixed NFS storage pool usage after EnterMaintenance and CancelMaintenance operations.
  • Restored the PrimaryDataStoreLifeCycle.updateStoragePool() call required by the Resize StoragePool workflow.
  • Gracefully handled 404 exceptions during deletion of:
    • ExportPolicy
    • ONTAP volumes
    • ONTAP snapshots
  • Added validation to ensure that only Active IP addresses are selected during storage pool creation.
  • Enabled instance and volume snapshots for volumes created with Create on storage.
  • Added support for creating NFS3 and iSCSI primary storage pools with a minimum capacity of 20 MB.
  • Fixed the issue preventing multiple VMs from being created on Oracle Linux hosts.
  • Ensured that iSCSI root disks created using the NetApp ONTAP storage plugin always use the QCOW2 format.

Enhancements

  • Hosts added after storage pool creation can now access the storage pool during instance creation.
  • Instance snapshots can now include volumes from multiple storage pools belonging to the same ONTAP cluster and SVM.
  • Added best-effort data LIF selection during storage pool creation.

Types of Changes

  • Breaking change — Changes existing functionality
  • New feature — Adds non-breaking functionality
  • Bug fix — Fixes an existing issue
  • Enhancement — Improves existing functionality
  • Cleanup — Code refactoring and cleanup
  • Build/CI
  • Test — Unit or integration test code

Feature/Enhancement Scale or Bug Severity

Feature/Enhancement Scale

  • Major
  • Minor

Bug Severity

  • Blocker
  • Critical
  • Major
  • Minor
  • Trivial

Detailed Changes

Bug Fixes

1. NFS Storage Pool Usage After Maintenance Operations

NFS storage pools can now be used after executing the EnterMaintenance and CancelMaintenance calls.

Previously

Although the NFS mount was removed, libvirtd still retained the storage pool details.

NFS storage pool before maintenance fix NFS storage pool before maintenance fix NFS storage pool before maintenance fix NFS storage pool before maintenance fix
Now NFS storage pool after maintenance fix NFS storage pool after maintenance fix NFS storage pool after maintenance fix NFS storage pool after maintenance fix NFS storage pool after maintenance fix NFS storage pool after maintenance fix

2. Restore the updateStoragePool() Lifecycle Call

Restored the PrimaryDataStoreLifeCycle.updateStoragePool() call in StorageManagerImpl.updateStoragePool().

This call is required by the Resize StoragePool workflow.

Background

  • During the updateStoragePool API call, StorageManagerImpl.updateStoragePool() updated the database but did not invoke PrimaryDataStoreLifeCycle.updateStoragePool() on the storage plugin.
  • The call was removed as part of Apache CloudStack PR #7889.
  • This impacted storage vendors that implemented the API.
  • This PR restores the missing lifecycle call.

3. Graceful Handling of 404 Exceptions During Delete Workflows

404 exceptions for ExportPolicy, ONTAP volumes, and ONTAP snapshots are now handled gracefully during their respective delete workflows.

404 exception handling 404 exception handling

4. Validate IP Address Status During Storage Pool Creation

Added validation to ensure that the IP address selected during storage pool creation is in the Active state.

Previously, an IP address that was not in the Active state could be selected.

Refer to the screenshots in Data LIF Selection During Storage Pool Creation.


5. Snapshots for Volumes Created with Create on Storage

Verified that users can take instance and volume snapshots for volumes created with the Create on storage option enabled.

Test Setup

Created a new volume named ADDN-DISK with Create on storage enabled and attached it to the testvm instance.

Created ADDN-DISK volume ADDN-DISK volume details

Additional Disk Created and Attached

Additional disk created Additional disk attached to the instance

Volume Snapshot Created for ADDN-DISK

Volume snapshot for ADDN-DISK

Corresponding ONTAP Snapshot

Corresponding ONTAP snapshot

6. Minimum Primary Storage Pool Capacity

Users can now create NFS3 or iSCSI primary storage pools with a minimum capacity of 20 MB.

Case 1: Capacity Less Than the Minimum

Storage Pool Capacity = 214 B

Storage pool capacity less than 20 MB

Case 2: Capacity Exactly 20 MB

Storage Pool Capacity = 20,971,520 B (20 MB)

Storage pool capacity of 20 MB Storage pool capacity of 20 MB Storage pool capacity of 20 MB

7. Multiple VMs on Oracle Linux Hosts

Users can now create more than one VM on a host running Oracle Linux.

Previously Multiple VMs on Oracle Linux before fix Multiple VMs on Oracle Linux before fix
Now Multiple VMs on Oracle Linux after fix Multiple VMs on Oracle Linux after fix

8. QCOW2 Format for iSCSI Root Disks

The root disk created during instance creation on an iSCSI primary storage pool now always uses the QCOW2 format when the NetApp ONTAP storage plugin is used.

iSCSI root disk format iSCSI root disk format

Enhancements

1. Host Access to Storage Pools Created Before the Host Was Added

A host added after storage pool creation can now access the storage pool and create volumes during instance creation.

Protocol-Specific Behavior

  • NFS3: The host gets access to the storage pool immediately after being added to the cluster.
  • iSCSI: The host gets access to the storage pool during instance creation.

Test Steps

Only One Host Present in the Cluster
One host in the cluster
Created an NFS3 Storage Pool with Cluster Scope
NFS3 storage pool with cluster scope
ONTAP Volume Created for the Storage Pool
ONTAP volume created for storage pool
Export Policy Rule and Client
Export policy rule and client
Added a New Host
New host added
Updated Client in the Export Policy
Updated export policy client
Removed the Host from the Cluster
Host removed from cluster
Client Removed from the Export Policy
Client removed from export policy

2. Instance Snapshots Across Multiple Storage Pools

Users can now take instance snapshots when the instance has volumes from different storage pools belonging to the same ONTAP cluster and SVM.

Test Steps

Created ontapNFS3 and ontapiSCSI Storage Pools

The storage pools use the NFS3 and iSCSI protocols, respectively.

NFS3 and iSCSI storage pools
Created an Instance with Volumes from Both Storage Pools

The root disk was created on ontapiSCSI, and the data disk was created on ontapNFS3.

Instance storage pool assignment Instance with volumes from different storage pools
Created an Instance Snapshot
Instance snapshot
Corresponding ONTAP Snapshot for the Root Disk
ONTAP snapshot for root disk
Corresponding ONTAP Snapshot for the Data Disk
ONTAP snapshot for data disk

3. Data LIF Selection During Storage Pool Creation

Added best-effort data LIF selection during storage pool creation.

The selection priority is:

Home-node LIF of the selected aggregate > Active LIF on the home node of the selected aggregate > Active LIF on the selected aggregate

Note: The following screenshots were captured for NFS3. The same behavior applies to iSCSI.

Aggregate selection based on available free space

Based on the available free space, the plugin selects sti246_vsim_ocvs040d_aggr1 by default.

Scenario 1: pool_P1 — No LIFs Were Down

Scenario 1 LIF status Scenario 1 data LIF selection Scenario 1 selected LIF

Result: The first available LIF with matching current and home nodes was selected.

Scenario 2: pool_P2_1 — LIFs on Node 040d Were Down

One LIF had 040d as its current node and 040c as its home node.

Scenario 2 LIF status Scenario 2 data LIF selection Scenario 2 selected LIF Scenario 2 selected LIF details

Scenario 3: pool_P3 — No LIFs on Node 040d Were Up

The first available LIF was selected from node 040c.

Scenario 3 LIF status Scenario 3 data LIF selection Scenario 3 selected LIF Scenario 3 selected LIF details

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the NetApp ONTAP primary storage plugin’s snapshot, VM snapshot, and storage pool operations. It refines how CloudStack interacts with ONTAP for snapshot lifecycle (take/delete/revert), improves data LIF selection behavior, and adds consistency-group orchestration to support VM snapshots spanning multiple FlexVols.

Changes:

  • Adjusts snapshot handling so ONTAP managed-primary volume snapshots remain on primary storage (skipping secondary-archive flows) and delegates ONTAP snapshot deletion to the strategy layer.
  • Implements ONTAP VM snapshots using a temporary consistency group (two-phase start/commit) when VM volumes span multiple FlexVols; uses direct FlexVol snapshots for the single-FlexVol case.
  • Improves operational robustness: idempotent “not found” handling for deletes, ONTAP-safe snapshot naming helpers, and node-affinity-aware data LIF selection with optional alerting.

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java Skips secondary archiving for ONTAP managed-primary snapshots based on payload location.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java Delegates ONTAP snapshot delete/revert orchestration to strategy and normalizes snapshot naming/metadata usage.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/vmsnapshot/OntapVMSnapshotStrategy.java Adds temporary CG two-phase flow for multi-FlexVol VM snapshots; direct snapshot flow for single FlexVol; improves testability.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java Adds connect(ops-only) mode, node-affinity-aware data LIF selection (returns Pair), job polling helpers, and FlexVol snapshot delete helper.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java Makes export-policy delete idempotent on 404 and implements updateAccessGroup for export-policy client maintenance.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/listener/OntapHostListener.java Updates NFS export policy rules on host connect and host removal for NFS pools.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycle.java Persists SVM UUID and processes data-LIF selection warnings (optionally sends alerts).
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/OntapStorageUtils.java Adds ops-only strategy connect, ONTAP-safe snapshot naming helpers, and “object not found” detection.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/OntapStorageConstants.java Adds constants for SVM UUID, LIF/node-affinity fields, CG flows, and job polling.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/model/AccessGroup.java Adds HostRuleAction (ADD/REMOVE) to drive export policy updates.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/SnapshotFeignClient.java Adds ONTAP consistency-group and CG snapshot REST endpoints.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/AggregateFeignClient.java Adds query-map support for requesting specific aggregate fields.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/IpInterface.java Adds state/enabled/location fields for LIF selection and node affinity.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/ExportRule.java Improves enum JSON serialization/deserialization robustness.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/Aggregate.java Adds node/space setters and node model for aggregate node affinity.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/ConsistencyGroup.java Adds model for CG create/list requests.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/ConsistencyGroupSnapshot.java Adds model for CG snapshot start/commit and list responses.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/ConsistencyGroupVolume.java Adds model for CG volume members.
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/ConsistencyGroupVolumeProvisioningOptions.java Adds model for CG volume provisioning options.
plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/vmsnapshot/OntapVMSnapshotStrategyTest.java Expands VM snapshot unit tests to cover single-FlexVol and temporary-CG flows.
plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/utils/OntapStorageUtilsTest.java Adds tests for “object not found” error matching.
plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java Adds coverage for updateAccessGroup behavior and 404 delete behavior.
plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/StorageStrategyTest.java Updates tests for new connect(false), LIF selection Pair, and new job/snapshot helpers.
plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycleTest.java Adds tests for data LIF warnings, failures, and alert integration.
plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriverTest.java Extends capabilities assertions and validates KVM format selection behavior.
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java Adds deleteStoragePool(uuid, details) override delegating to uuid-only delete.
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java Adjusts deleteStoragePool ordering and details-aware delete call.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI review requested due to automatic review settings August 17, 2026 16:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java:1638

  • updateSnapshotPayload is now called with 4 parameters, but the only method in this class still requires (storagePoolId, payload, isKvmAndFileBasedStorage, poolType, clusterId). This is a compile-time error; restore the missing poolType argument (and keep the local variable if needed later).
        boolean isKvmAndFileBasedStorage = isHypervisorKvmAndFileBasedStorage(volume, storagePool);
        boolean backupSnapToSecondary = isBackupSnapshotToSecondaryForZone(volume.getDataCenterId());

        updateSnapshotPayload(volume.getPoolId(), payload, isKvmAndFileBasedStorage, clusterId);

@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.23787% with 523 lines in your changes missing coverage. Please review.
✅ Project coverage is 19.79%. Comparing base (ba67a62) to head (77f078d).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ck/storage/vmsnapshot/OntapVMSnapshotStrategy.java 59.85% 94 Missing and 18 partials ⚠️
...cloudstack/storage/listener/OntapHostListener.java 0.00% 80 Missing ⚠️
...hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java 0.00% 58 Missing ⚠️
...ck/storage/driver/OntapPrimaryDatastoreDriver.java 16.07% 44 Missing and 3 partials ⚠️
.../storage/feign/model/ConsistencyGroupSnapshot.java 24.59% 45 Missing and 1 partial ⚠️
...he/cloudstack/storage/service/StorageStrategy.java 70.54% 25 Missing and 18 partials ⚠️
...he/cloudstack/storage/utils/OntapStorageUtils.java 44.28% 20 Missing and 19 partials ⚠️
...om/cloud/storage/snapshot/SnapshotManagerImpl.java 0.00% 18 Missing ⚠️
...ache/cloudstack/storage/feign/model/Aggregate.java 50.00% 16 Missing ⚠️
...ain/java/com/cloud/storage/StorageManagerImpl.java 0.00% 14 Missing ⚠️
... and 10 more
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #13897      +/-   ##
============================================
+ Coverage     19.72%   19.79%   +0.07%     
- Complexity    19944    20075     +131     
============================================
  Files          6371     6375       +4     
  Lines        575738   576529     +791     
  Branches      70471    70592     +121     
============================================
+ Hits         113587   114150     +563     
- Misses       449805   449974     +169     
- Partials      12346    12405      +59     
Flag Coverage Δ
uitests 3.41% <ø> (ø)
unittests 21.08% <50.23%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI review requested due to automatic review settings August 17, 2026 17:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/StorageStrategyTest.java:1259

  • The final @Test method block is indented as if it were nested, which is inconsistent with the rest of the class and can trigger Checkstyle indentation rules.
        @Test
        void testDeleteFlexVolSnapshotForCloudStackVolume_Feign404_TreatedAsSuccess() {
                FeignException notFoundException = mock(FeignException.class);
                when(notFoundException.status()).thenReturn(404);
                when(snapshotFeignClient.deleteSnapshot(anyString(), eq("fv-uuid-1"), eq("snap-uuid-1")))

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/OntapStorageUtils.java:215

  • buildOntapSnapshotName(): when the uniqueness suffix is very long (suffix length >= MAX_SNAPSHOT_NAME_LENGTH), maxBaseLength becomes <= 0 and the code calls normalizedBase.substring(0, maxLength). If normalizedBase is shorter than maxLength (e.g., "snapshot"), this throws StringIndexOutOfBoundsException. This can surface unexpectedly if a caller passes a long suffix (UUIDs, paths, etc.).
        int maxLength = OntapStorageConstants.MAX_SNAPSHOT_NAME_LENGTH;
        int maxBaseLength = maxLength - suffix.length();
        if (maxBaseLength <= 0) {
            return normalizedBase.substring(0, maxLength);
        }

Copilot AI review requested due to automatic review settings August 20, 2026 04:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated no new comments.

Suppressed comments (4)

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java:536

  • getNetworkInterface() dereferences iface.getIp().getAddress() without guarding against iface, iface.getIp(), or the address being null. A partial/unexpected ONTAP response would cause a NullPointerException and prevent pool creation.
            for (IpInterface iface : response.getRecords()) {
                if (!Boolean.TRUE.equals(iface.getEnabled()) || !OntapStorageConstants.LIF_STATE_UP.equals(iface.getState())) {
                    continue;
                }
                if (!isIPv4Address(iface.getIp().getAddress())) {
                    continue;
                }

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java:449

  • createExportPolicyRequest() can build an export client match of "null/32" when a Host has neither storageIpAddress nor privateIpAddress (because ip + "/32" string-concats null). That would push an invalid client entry to ONTAP.
            String hostStorageIp = host.getStorageIpAddress() != null ? host.getStorageIpAddress().trim() : null;
            String ip = (hostStorageIp != null && !hostStorageIp.isEmpty())
                    ? hostStorageIp
                    : (host.getPrivateIpAddress() != null ? host.getPrivateIpAddress().trim() : null);
            String ipToUse = ip + "/32";

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/listener/OntapHostListener.java:213

  • hostDisconnected() is invoked by StorageManagerImpl.disconnectHostFromSharedPool (server/src/main/java/com/cloud/storage/StorageManagerImpl.java:1935), but this implementation currently does nothing and always returns false. This prevents proper detach/unmount cleanup on host disconnect (e.g., maintenance flows) and the in-code note claiming it isn't called is incorrect.
    public boolean hostDisconnected(long hostId, long poolId) {
        logger.info("hostDisconnected: Disconnecting host {} from pool {}", hostId, poolId);
        // Note: This is not currently being called for NetApp ONTAP storage plugin.
        return false;
    }

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java:213

  • validateAndSelectAggregatesForVolumeCreation overwrites this.aggregates on every eligible aggregate and ends up keeping only the last eligible entry. This prevents createStorageVolume() from selecting the best aggregate across all eligible candidates and can lead to an unintended aggregate being used for pool provisioning.
            logger.debug("Found aggregate: " + aggr.getName() + " with UUID: " + aggr.getUuid());
            Aggregate aggrResp = aggregateFeignClient.getAggregateByUUID(authHeader, aggr.getUuid(),
                        Map.of(OntapStorageConstants.FIELDS, OntapStorageConstants.AGGREGATE_NODE
                                + OntapStorageConstants.COMMA + OntapStorageConstants.AGGREGATE_SPACE
                                + OntapStorageConstants.COMMA + OntapStorageConstants.STATE));

sandeeplocharla and others added 12 commits August 22, 2026 12:07
This PR provides support to addition and removal of multiple hosts to NFS3 and iSCSI type storage pools

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [X] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

- [X] Major
- [ ] Minor

- [ ] BLOCKER
- [ ] Critical
- [ ] Major
- [ ] Minor
- [ ] Trivial

**Only 1 Host present in the Cluster**
<img width="1049" height="340" alt="Screenshot 2026-07-14 at 9 19 49 AM"
src="https://github.com/user-attachments/assets/8d639c94-6686-40de-a362-341d41ff48fe"
/>

**Created an NFS3 StoragePool with Cluster scope**
<img width="1049" height="340" alt="Screenshot 2026-07-14 at 9 20 58 AM"
src="https://github.com/user-attachments/assets/f14cc903-bd60-47d4-8a7c-5a2ec4d2e0d0"
/>

**ONTAP volume created for the SP**
<img width="1101" height="305" alt="Screenshot 2026-07-14 at 9 21 30 AM"
src="https://github.com/user-attachments/assets/7823e398-782d-472d-948d-25153d5c372a"
/>

**Export Policy rule and client**
<img width="1077" height="407" alt="Screenshot 2026-07-14 at 9 34 00 AM"
src="https://github.com/user-attachments/assets/5426f9d4-cc96-45dc-9857-0312227867c8"
/>

**Added a new host**
<img width="1048" height="314" alt="Screenshot 2026-07-14 at 9 24 42 AM"
src="https://github.com/user-attachments/assets/5acd2a38-6b54-4393-a4f9-86790f1c81de"
/>

**Updated client in the Export Policy**
<img width="1077" height="407" alt="Screenshot 2026-07-14 at 9 35 24 AM"
src="https://github.com/user-attachments/assets/7d0e8470-3391-4909-9de9-a3f22fead439"
/>

**Removed the host from the cluster**
<img width="1042" height="342" alt="Screenshot 2026-07-14 at 9 32 16 AM"
src="https://github.com/user-attachments/assets/24fea619-4c8b-4805-ad53-49fc2fb6aa13"
/>

**The respective client has been removed from the Export Policy**
<img width="1077" height="423" alt="Screenshot 2026-07-14 at 9 36 07 AM"
src="https://github.com/user-attachments/assets/76e62a97-a034-4c75-8642-41bd116938e1"
/>

Test Done | Result | Comments
-- | -- | --
Create an instance by specifying the host and disk offering pointed to
NFS3 Primary Storage Pool (Cluster scoped with min of 2 hosts) | PASS |
 
Create an instance specifying host and disk offering pointed to iSCSI
Primary Storage Pool (Cluster scoped with min of 2 hosts) | PASS |  
Create an instance in a cluster with atleast 2 hosts in the cluster by
not specifying the host and disk offering pointed to NFS3 Primary
Storage Pool (Cluster scoped with min of 2 hosts) | PASS |  
Create an instance in a cluster with atleast 2 hosts in the cluster by
not specifying the host and disk offering pointed to iSCSI Primary
Storage Pool (Cluster scoped with min of 2 hosts) | PASS |  
Create an instance by specifying the host and disk offering pointed to 2
NFS3 Primary Storage Pools (Cluster scoped + Zone scoped) | FAIL |
StoragePoolAllocator is coming as empty and the random strategy to
allocate was failing.
Create an instance by specifying the host and disk offering pointed to 2
iSCSI Primary Storage Pools (Cluster scoped + Zone scoped) | FAIL |
StoragePoolAllocator is coming as empty and the random strategy to
allocate was failing.
Create an instance by specifying the host and disk offering pointed to
NFS3 Primary Storage Pool (Zone scoped with min of 2 hosts) | FAIL |
Zone scoped instance creation failing (CSTACKEX-188)
Create an instance specifying host and disk offering pointed to iSCSI
Primary Storage Pool (Zone scoped with min of 2 hosts) | FAIL | Zone
scoped instance creation failing (CSTACKEX-188)
Create an instance in a cluster with atleast 2 hosts in the cluster by
not specifying the host and disk offering pointed to NFS3 Primary
Storage Pool (Zone scoped with min of 2 hosts) | FAIL | Zone scoped
instance creation failing (CSTACKEX-188)
Create an instance in a cluster with atleast 2 hosts in the cluster by
not specifying the host and disk offering pointed to iSCSI Primary
Storage Pool (Zone scoped with min of 2 hosts) | FAIL | Zone scoped
instance creation failing (CSTACKEX-188)
Power off VM on Host-1 and start it on Host-2 (same cluster) with disk
offering pointed to NFS3 primary storage pool (cluster scoped) | PASS |
 
Power off and on a VM with 'last known host' selected. Create the
instance in a cluster, without specifying a host. | PASS | Last known
host was selected
Power off and on a VM with 'last known host' NOT selected. Create the
instance in a cluster, without specifying a host. | PASS | VM got hosted
on the chosen host.
Power off and on a VM with 'last known host' selected but choose a
different host. Create the instance in a cluster, without specifying a
host. | PASS | VM got hosted on the chosen host.
Insufficient resources in the storage pool. Instance creation should
fail. | PASS | Generic error is being displayed instead of proper error
regarding Insufficient resources.
One host in the cluster (min. 2 hosts) loaded, resulting in insufficient
CPU. Disk Offering pointed to Cluster scoped primary storage pool. |
PASS |  
Both host in the cluster (min. 2 hosts) loaded, resulting in
insufficient CPU. Disk Offering pointed to Cluster scoped primary
storage pool. Instance creation should fail but disks should first get
created and then destroyed.
#71)

Fix for NFS3 primary storage pool is failing to come out of maintenance
mode

### Description

This PR has the following:

1. For NetworkFileSystem type, libvirtd handles mounting and unmounting
of nfs mount [Ref: https://libvirt.org/storage.html]
2. KVM adaptor hasn't overridden `deleteStoragePool` method leading to
only just the change in the DB. This was leading to error in case of
`Cancel Maintenance` as the pool already exists with the host.
3. Also, when `Enable Maintenance` call comes, it was first removing the
nfs mount, which was causing the libvirtd to error out during `Destroy
Pool` call as the mount wasn't available.

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

### Types of changes

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [X] Bug fix (non-breaking change which fixes an issue)
- [ ] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

### Feature/Enhancement Scale or Bug Severity

#### Feature/Enhancement Scale

- [] Major
- [ ] Minor

#### Bug Severity

- [ ] BLOCKER
- [ ] Critical
- [X] Major
- [ ] Minor
- [ ] Trivial

### Screenshots (if appropriate):

### How Has This Been Tested?

`Previously:`

<img width="1035" height="362" alt="Screenshot 2026-07-08 at 8 00 05 AM"
src="https://github.com/user-attachments/assets/91a3bcd7-cb6f-4b53-81f5-0851abd337ee"
/>
<img width="1301" height="365" alt="Screenshot 2026-07-08 at 7 58 31 AM"
src="https://github.com/user-attachments/assets/5444b1ae-5cfa-4709-a48f-107b8a257e29"
/>
<img width="1035" height="362" alt="Screenshot 2026-07-08 at 8 00 29 AM"
src="https://github.com/user-attachments/assets/bbeaece1-8795-46ef-b1c7-9a9b24910b21"
/>
<img width="1301" height="327" alt="Screenshot 2026-07-08 at 8 01 37 AM"
src="https://github.com/user-attachments/assets/c9086ef2-066c-4661-a684-c4788e471fdc"
/>

So, clearly though the nfs mount was removed, the libvirtd still has the
pool details with it.

`Now:`

<img width="1042" height="351" alt="Screenshot 2026-07-08 at 8 30 46 AM"
src="https://github.com/user-attachments/assets/59d2c629-41bd-4991-9988-3989dd3497aa"
/>
<img width="1300" height="382" alt="Screenshot 2026-07-08 at 8 31 18 AM"
src="https://github.com/user-attachments/assets/9b774243-8329-4fb8-babb-a0891d20fc6a"
/>
<img width="1043" height="355" alt="Screenshot 2026-07-08 at 8 32 41 AM"
src="https://github.com/user-attachments/assets/5207517a-c2d0-4935-adf0-db70877b79fa"
/>
<img width="1299" height="312" alt="Screenshot 2026-07-08 at 8 33 02 AM"
src="https://github.com/user-attachments/assets/fd5014bb-8d46-423b-8039-b2caa391b885"
/>
<img width="1049" height="340" alt="Screenshot 2026-07-08 at 8 34 32 AM"
src="https://github.com/user-attachments/assets/ec951783-a90e-4118-89d2-8d62b28f138e"
/>
<img width="1299" height="365" alt="Screenshot 2026-07-08 at 8 33 46 AM"
src="https://github.com/user-attachments/assets/a64a2c86-9089-4f67-a345-90a0dbfa88fc"
/>
#73)

Fixes to handle 404 exceptions when export policy and ontap volume are
missing during storagepool delete workflow

This PR...
Has fixes to handle 404 Not found exceptions in case of 'ExportPolicy'
and 'Volume' deletion.

**latest**
<img width="1301" height="503" alt="Screenshot 2026-08-02 at 2 13 22 PM"
src="https://github.com/user-attachments/assets/53e48052-c833-4758-acff-b6ee753113cf"
/>

<img width="1293" height="674" alt="Screenshot 2026-07-01 at 3 13 00 PM"
src="https://github.com/user-attachments/assets/46190b26-500c-448b-b65e-4b989e8dca28"
/>

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [X] Bug fix (non-breaking change which fixes an issue)
- [ ] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

- [ ] Major
- [] Minor

- [ ] BLOCKER
- [ ] Critical
- [ ] Major
- [X] Minor
- [ ] Trivial

<!-- Please describe in detail how you tested your changes. -->
<!-- Include details of your testing environment, and the tests you ran
to -->

change?

<!-- see how your change affects other areas of the code, etc. -->

<!-- Please read the
[CONTRIBUTING](https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md)
document -->
…ross multiple flexvolumes (#74)

This PR...
<!--- Describe your changes in DETAIL - And how has behaviour
functionally changed. -->

<!-- For new features, provide link to FS, dev ML discussion etc. -->
<!-- In case of bug fix, the expected and actual behaviours, steps to
reproduce. -->

<!-- When "Fixes: #<id>" is specified, the issue/PR will automatically
be closed when this PR gets merged -->
<!-- For addressing multiple issues/PRs, use multiple "Fixes: #<id>" -->
<!-- Fixes: # -->

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

- [x] Major
- [ ] Minor

- [ ] BLOCKER
- [ ] Critical
- [x] Major
- [ ] Minor
- [ ] Trivial

<!-- Please describe in detail how you tested your changes. -->
<!-- Include details of your testing environment, and the tests you ran
to -->

change?

<!-- see how your change affects other areas of the code, etc. -->

<!-- Please read the
[CONTRIBUTING](https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md)
document -->
… data LIFs are not reachable (#76)

Choosing IpInterface based on its status and affinity to the chosen
aggregate

This PR...
1. Fixed an issue in picking an unavailable IP while creating the
storage pool.
2. When CloudStack creates an ONTAP primary storage pool, it now picks
the best available network interface (LIF) using a priority-based
selection:
- Best case: Uses a LIF homed on the same node as the storage aggregate
— optimal I/O, no warning
- Degraded case: All home-node LIFs are down but a failover LIF is
running on that node — pool is created, admin is warned
- Fallback case: No LIF at all on the aggregate's node, pool is created
using a LIF from a different node, admin is warned with a latency note
- Failure case: No usable LIF anywhere, pool creation fails with a clear
error

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [X] Bug fix (non-breaking change which fixes an issue)
- [ ] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

- [X] Major
- [ ] Minor

- [ ] BLOCKER
- [ ] Critical
- [X] Major
- [ ] Minor
- [ ] Trivial

Note: The following images have been captured for NFS3, the same would
be the case for iSCSI.

<img width="487" height="661" alt="Screenshot 2026-07-08 at 6 55 32 AM"
src="https://github.com/user-attachments/assets/e48a42c7-9914-4563-bc27-f1ad6501629c"
/>

Clearly, by the virtue of free space available, the plugin would choose
`sti246_vsim_ocvs040d_aggr1` by default.

**Scenario-1 [pool_P1]: Happy path; No LIFs were down.**
<img width="1122" height="742" alt="Screenshot 2026-07-07 at 10 26
34 PM"
src="https://github.com/user-attachments/assets/8b748425-c548-4d03-8265-2b86a568f45b"
/>
<img width="1122" height="419" alt="Screenshot 2026-07-07 at 10 26
49 PM"
src="https://github.com/user-attachments/assets/45177fc2-4e87-4ead-928e-659e50504d9d"
/>
<img width="1032" height="432" alt="Screenshot 2026-07-07 at 10 27
48 PM"
src="https://github.com/user-attachments/assets/6bbe3533-2081-429d-ba1f-fa1a8731dd3f"
/>
The first best available LIF with current node and home node matching
with the chosen node has been picked.

**Scenario-2 [pool_P2_1]: LIFs on `040d` node were down; with one LIF
whose current node: `040d`, while its home node: `040c`**
<img width="1032" height="765" alt="Screenshot 2026-07-07 at 10 28
38 PM"
src="https://github.com/user-attachments/assets/adb8e4ff-670b-49d2-b8ca-1d7558f34643"
/>
<img width="1032" height="415" alt="Screenshot 2026-07-07 at 10 28
50 PM"
src="https://github.com/user-attachments/assets/6d982076-adba-4458-960b-dc0066d1c5a6"
/>
<img width="1032" height="380" alt="Screenshot 2026-07-07 at 11 05
22 PM"
src="https://github.com/user-attachments/assets/c73957ec-a82b-4093-bf88-43da515d8663"
/>
<img width="1032" height="220" alt="Screenshot 2026-07-07 at 11 05
43 PM"
src="https://github.com/user-attachments/assets/f179e0b7-808f-4643-9d89-7ebb52fa1d33"
/>

**Scenario-3 [pool_P3]: None of the `040d` node LIFs are UP. First best
available LIF is picked from `040c`.**
<img width="867" height="764" alt="Screenshot 2026-07-07 at 11 07 00 PM"
src="https://github.com/user-attachments/assets/59a05c54-e4f7-468a-9682-9fc392ba45c9"
/>
<img width="867" height="420" alt="Screenshot 2026-07-07 at 11 07 22 PM"
src="https://github.com/user-attachments/assets/87c4a008-17d8-4bff-9335-14e0707f9ddd"
/>
<img width="1029" height="425" alt="Screenshot 2026-07-07 at 11 08
30 PM"
src="https://github.com/user-attachments/assets/2f2888d0-0a7a-4e29-91d4-d03f1bf4440e"
/>
<img width="1029" height="228" alt="Screenshot 2026-07-07 at 11 08
54 PM"
src="https://github.com/user-attachments/assets/5cf00e5f-0a46-4010-899d-14c605b676d2"
/>
#77)

### Description
Fix snapshot failure for CloudStack volumes attached to running VMs on
ONTAP primary storage (both NFS3 and iSCSI protocols).

This PR...
<!--- Describe your changes in DETAIL - And how has behaviour
functionally changed. -->
When a volume was created and attached to a running VM in a single
step,by enabling create on storage and choose the storage pool tag the
volume format was not being set correctly. The format is now determined
by the hypervisor type (KVM → QCOW2) in ontapdriver via
[getImageFormatByHypervisor(HypervisorType] mirroring the
[getSupportedImageFormatForCluster] in VolumeOrchestrator file.


<!-- For new features, provide link to FS, dev ML discussion etc. -->
<!-- In case of bug fix, the expected and actual behaviours, steps to
reproduce. -->

<!-- When "Fixes: #<id>" is specified, the issue/PR will automatically
be closed when this PR gets merged -->
<!-- For addressing multiple issues/PRs, use multiple "Fixes: #<id>" -->
<!-- Fixes: # -->

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

### Types of changes

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [X] Bug fix (non-breaking change which fixes an issue)
- [ ] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

### Feature/Enhancement Scale or Bug Severity

#### Feature/Enhancement Scale

- [ ] Major
- [ ] Minor

#### Bug Severity

- [ ] BLOCKER
- [ ] Critical
- [X] Major
- [ ] Minor
- [ ] Trivial

### How Has This Been Tested?

Tested on a dev setup  against these scenarios:

Scenario A — Attach data disk to running VM, then snapshot

- Create ONTAP primary storage pool (NFS3 or iSCSI)
- Deploy VM with data disk using pool-tagged disk offering → VM reaches
Running state
- Create volume attached to the running VM by enabling create on storage
and choose the storage pool tag
- Take snapshot of attached volume — ✅ succeeds (was failing before fix)

Scenario B — Attach volume to root-disk-only VM, then snapshot

- Create ONTAP primary storage pool (NFS3 or iSCSI)
- Deploy VM without data disk → VM reaches Running state
- Create and attach volume to the running VM by enabling create on
storage and choose the storage pool tag
- Take snapshot of attached volume — ✅ succeeds (was failing before fix)

scenarios-C-create a volume on storage pool but not attach to any vm

- Create ONTAP primary storage pool (NFS3 or iSCSI)
- Create volume by enabling create on storage and choose the storage
pool tag
- Take snapshot- — ✅ succeeds (was failing before fix)

### Screenshots (if appropriate):
snapshots for when cs volume is attached to NFS and ISCSI instance that
has both root and data disk and create on storage enabled:
<img width="1464" height="436" alt="Screenshot 2026-07-15 at 12 28
32 AM"
src="https://github.com/user-attachments/assets/69827e56-ac5d-4746-a2e9-f32ac8e95433"
/>
<img width="1472" height="414" alt="Screenshot 2026-07-15 at 12 28
38 AM"
src="https://github.com/user-attachments/assets/799c8485-7023-4b1f-9eeb-3d0c4a745a57"
/>

verifying on ontap and db:
<img width="1549" height="343" alt="Screenshot 2026-07-15 at 12 28
58 AM"
src="https://github.com/user-attachments/assets/ee62e8b1-81a9-41b9-b5fb-639133a1cfff"
/>
<img width="1548" height="397" alt="Screenshot 2026-07-15 at 12 29
10 AM"
src="https://github.com/user-attachments/assets/8f74ae08-437e-4ac6-aa24-49ef4675cd30"
/>
<img width="1720" height="175" alt="Screenshot 2026-07-15 at 12 30
43 AM"
src="https://github.com/user-attachments/assets/088fbc14-581e-4ac9-85df-77bced054e3f"
/>

snapshots for when cs volume is attached to NFS and ISCSI instance that
has only root and also case when they are not attached to any instance
and create on storage enabled:
<img width="1458" height="320" alt="Screenshot 2026-07-15 at 12 52
30 AM"
src="https://github.com/user-attachments/assets/8150b81c-bc07-48e7-91ca-c93ef53b6e8a"
/>
<img width="1454" height="256" alt="Screenshot 2026-07-15 at 12 52
39 AM"
src="https://github.com/user-attachments/assets/0408156a-6374-4026-b5aa-b51b070fd44f"
/>


<!-- Please describe in detail how you tested your changes. -->
<!-- Include details of your testing environment, and the tests you ran
to -->

#### How did you try to break this feature and the system with this
change?

<!-- see how your change affects other areas of the code, etc. -->

<!-- Please read the
[CONTRIBUTING](https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md)
document -->
#82)

…Deletion of CS side of snapshot should not fail on not finding ontap
snapshot.

This PR...
<!--- Describe your changes in DETAIL - And how has behaviour
functionally changed. -->

<!-- For new features, provide link to FS, dev ML discussion etc. -->
<!-- In case of bug fix, the expected and actual behaviours, steps to
reproduce. -->

<!-- When "Fixes: #<id>" is specified, the issue/PR will automatically
be closed when this PR gets merged -->
<!-- For addressing multiple issues/PRs, use multiple "Fixes: #<id>" -->
<!-- Fixes: # -->

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

- [ ] Major
- [x] Minor

- [ ] BLOCKER
- [ ] Critical
- [ ] Major
- [x] Minor
- [ ] Trivial

Test -1: Ran VM snapshot delete operation when the respective snapshot
is not available at ONTAP, it passed.
Test -2: Ran VM snapshot delete operation when the respective snapshot
is available at ONTAP; it passed
Test -3: Ran cloudstack volume snapshot delete workflow when the
respective snapshot is not available at ONTAP, it passed.
Test -4: Ran cloudstack volume snapshot delete workflow when the
respective snapshot is available at ONTAP, it passed.

<!-- Please describe in detail how you tested your changes. -->
<!-- Include details of your testing environment, and the tests you ran
to -->

change?

<!-- see how your change affects other areas of the code, etc. -->

<!-- Please read the
[CONTRIBUTING](https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md)
document -->
…nux (#88)

### Description

Subsequent VM Creation is failing for ISCSI Storage Pool on Oracle Linux
<!--- Describe your changes in DETAIL - And how has behaviour
functionally changed. -->

<!-- For new features, provide link to FS, dev ML discussion etc. -->
<!-- In case of bug fix, the expected and actual behaviours, steps to
reproduce. -->

<!-- When "Fixes: #<id>" is specified, the issue/PR will automatically
be closed when this PR gets merged -->
<!-- For addressing multiple issues/PRs, use multiple "Fixes: #<id>" -->
<!-- Fixes: # -->

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

### Types of changes

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

### Feature/Enhancement Scale or Bug Severity

#### Feature/Enhancement Scale

- [ ] Major
- [ ] Minor

#### Bug Severity

- [ ] BLOCKER
- [ ] Critical
- [x] Major
- [ ] Minor
- [ ] Trivial

### Screenshots (if appropriate):

### How Has This Been Tested?

Tested on both Oracle and Unbuntu and tried creating multiple VMs

#### How did you try to break this feature and the system with this
change?

<!-- see how your change affects other areas of the code, etc. -->

<!-- Please read the
[CONTRIBUTING](https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md)
document -->

---------

Co-authored-by: Gupta, Surya <Surya.Gupta@netapp.com>
…throw an exception in case of invalid capacity bytes instead of adjusting to minimum requirement (#94)

This PR corrects the minimum allowed storage pool size from 1.56GB to
20MB as per ONTAP guidelines for FlexVol. Also, this removes the
behaviour to silently correct the invalid capacity bytes to min.
requirement, instead it'll throw an exception to let the user decide on
the corrective action.

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [X] Bug fix (non-breaking change which fixes an issue)
- [ ] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

- [ ] Major
- [ ] Minor

- [ ] BLOCKER
- [ ] Critical
- [X] Major
- [ ] Minor
- [ ] Trivial

`Case-1: Storage Pool Capacity Bytes = 214B, less than the min. req of
20MB`
<img width="1047" height="735" alt="Screenshot 2026-08-20 at 7 08 03 AM"
src="https://github.com/user-attachments/assets/f09d23d8-4c74-4222-8b2e-e4b37b3de1b3"
/>

`Case-2: Storage Pool Capacity Bytes = 20971520B or 20MB`
<img width="1047" height="735" alt="Screenshot 2026-08-20 at 7 15 58 AM"
src="https://github.com/user-attachments/assets/8b4a47af-0d90-4636-bb48-5d41260a0fad"
/>
<img width="1047" height="735" alt="Screenshot 2026-08-20 at 7 16 27 AM"
src="https://github.com/user-attachments/assets/f0033b69-0390-4fc6-8394-0e67247274be"
/>
<img width="1103" height="437" alt="Screenshot 2026-08-20 at 7 17 16 AM"
src="https://github.com/user-attachments/assets/1bf51bd5-d746-43b6-b99e-fd87515db411"
/>
…cycle (#90)

### Description
While implementing storage pool resize via the updateStoragePool API, 
StorageManagerImpl.updateStoragePool()updates the database but never
calls PrimaryDataStoreLifeCycle.updateStoragePool() on the storage
plugin.
adding that call in here.
This PR...
<!--- Describe your changes in DETAIL - And how has behaviour
functionally changed. -->

<!-- For new features, provide link to FS, dev ML discussion etc. -->
<!-- In case of bug fix, the expected and actual behaviours, steps to
reproduce. -->

<!-- When "Fixes: #<id>" is specified, the issue/PR will automatically
be closed when this PR gets merged -->
<!-- For addressing multiple issues/PRs, use multiple "Fixes: #<id>" -->
<!-- Fixes: # -->

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

### Types of changes

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

### Feature/Enhancement Scale or Bug Severity

#### Feature/Enhancement Scale

- [ ] Major
- [ ] Minor

#### Bug Severity

- [ ] BLOCKER
- [x] Critical
- [ ] Major
- [ ] Minor
- [ ] Trivial

### Screenshots (if appropriate):

### How Has This Been Tested?

<!-- Please describe in detail how you tested your changes. -->
<!-- Include details of your testing environment, and the tests you ran
to -->

#### How did you try to break this feature and the system with this
change?

<!-- see how your change affects other areas of the code, etc. -->

<!-- Please read the
[CONTRIBUTING](https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md)
document -->
### Description

This PR...
<!--- Describe your changes in DETAIL - And how has behaviour
functionally changed. -->

<!-- For new features, provide link to FS, dev ML discussion etc. -->
<!-- In case of bug fix, the expected and actual behaviours, steps to
reproduce. -->

<!-- When "Fixes: #<id>" is specified, the issue/PR will automatically
be closed when this PR gets merged -->
<!-- For addressing multiple issues/PRs, use multiple "Fixes: #<id>" -->
<!-- Fixes: # -->

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

### Types of changes

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

### Feature/Enhancement Scale or Bug Severity

#### Feature/Enhancement Scale

- [ ] Major
- [ ] Minor

#### Bug Severity

- [ ] BLOCKER
- [ ] Critical
- [ ] Major
- [ ] Minor
- [ ] Trivial

### Screenshots (if appropriate):

### How Has This Been Tested?

<!-- Please describe in detail how you tested your changes. -->
<!-- Include details of your testing environment, and the tests you ran
to -->

#### How did you try to break this feature and the system with this
change?

<!-- see how your change affects other areas of the code, etc. -->

<!-- Please read the
[CONTRIBUTING](https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md)
document -->

---------

Co-authored-by: Srivastava, Piyush <Piyush.Srivastava@netapp.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated 4 comments.

Suppressed comments (1)

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java:535

  • getNetworkInterface assumes iface.getIp() and iface.getIp().getAddress() are non-null. If ONTAP returns an interface record without an IP payload (or a null address), this will throw a NullPointerException before filtering.
                if (!Boolean.TRUE.equals(iface.getEnabled()) || !OntapStorageConstants.LIF_STATE_UP.equals(iface.getState())) {
                    continue;
                }
                if (!isIPv4Address(iface.getIp().getAddress())) {
                    continue;

Copilot AI review requested due to automatic review settings August 22, 2026 08:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated 2 comments.

Suppressed comments (3)

Previously missed (1) — in code that hasn't changed since the last review.

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycle.java:290

  • processDataLifSelection assumes lifResult is non-null; if getNetworkInterface() ever returns null (or a future refactor changes behavior), this will throw a NullPointerException before producing the intended CloudRuntimeException. Guard against a null Pair explicitly.
    private void processDataLifSelection(Pair<String, String> lifResult, Map<String, String> details,
                                         String storagePoolName, Long zoneId, Long podId) {
        String dataLIF = lifResult.first();
        if (dataLIF == null || dataLIF.isEmpty()) {
            throw new CloudRuntimeException("Failed to retrieve Data LIF from ONTAP, cannot create primary storage");

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java:277

  • When catching InterruptedException, the thread's interrupted status should be restored (Thread.currentThread().interrupt()), otherwise higher-level code may not observe the interrupt and shutdown/cancellation can be delayed.
            } catch (InterruptedException ex) {
                logger.warn("Interrupted while waiting for iSCSI device {} to become available", volumeUuid, ex);
                return false;

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java:213

  • Inside validateAndSelectAggregatesForVolumeCreation, once an eligible aggregate is found, the loop continues and this.aggregates keeps getting overwritten; the final selection therefore depends on the iteration order of svm.getAggregates(). Also, the method currently stores the unvalidated aggr object rather than the fully populated/validated aggrResp returned by ONTAP.
            logger.info("Selected aggregate: " + aggr.getName() + " for volume operations.");
            this.aggregates = List.of(aggr);
        }

Comment thread server/src/main/java/com/cloud/storage/StorageManagerImpl.java
### Description
OntapPrimaryDatastoreDriver now returns RAW format for KVM+iSCSI (was
always QCOW2), and VolumeServiceImpl.managedCopyBaseImageCallback adds a
volume.getFormat() != null guard to prevent the template's format from
overwriting it.
<img width="836" height="1614" alt="image"
src="https://github.com/user-attachments/assets/f74184e8-82d8-4382-894f-e7fa7ad6ea57"
/>

This PR...
<!--- Describe your changes in DETAIL - And how has behaviour
functionally changed. -->

<!-- For new features, provide link to FS, dev ML discussion etc. -->
<!-- In case of bug fix, the expected and actual behaviours, steps to
reproduce. -->

<!-- When "Fixes: #<id>" is specified, the issue/PR will automatically
be closed when this PR gets merged -->
<!-- For addressing multiple issues/PRs, use multiple "Fixes: #<id>" -->
<!-- Fixes: # -->

<!---
*******************************************************************************
-->
<!--- NOTE: AUTOMATION USES THE DESCRIPTIONS TO SET LABELS AND PRODUCE
DOCUMENTATION. -->
<!--- PLEASE PUT AN 'X' in only **ONE** box -->
<!---
*******************************************************************************
-->

### Types of changes

- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] Enhancement (improves an existing feature and functionality)
- [ ] Cleanup (Code refactoring and cleanup, that may add test cases)
- [ ] Build/CI
- [ ] Test (unit or integration test code)

### Feature/Enhancement Scale or Bug Severity

#### Feature/Enhancement Scale

- [ ] Major
- [ ] Minor

#### Bug Severity

- [ ] BLOCKER
- [ ] Critical
- [x] Major
- [ ] Minor
- [ ] Trivial

### Screenshots (if appropriate):
<img width="1704" height="200" alt="Screenshot 2026-08-13 at 11 48
46 AM"
src="https://github.com/user-attachments/assets/21de01f3-8ed4-4485-9b23-65d310e69440"
/>

### How Has This Been Tested?

Ran Iscsi automation suite: Everything is green 
<img width="2100" height="1520" alt="image"
src="https://github.com/user-attachments/assets/bcb44bad-ce86-480c-9274-4f128817affa"
/>

<!-- Please describe in detail how you tested your changes. -->
<!-- Include details of your testing environment, and the tests you ran
to -->

#### How did you try to break this feature and the system with this
change?

<!-- see how your change affects other areas of the code, etc. -->

<!-- Please read the
[CONTRIBUTING](https://github.com/apache/cloudstack/blob/main/CONTRIBUTING.md)
document -->
Copilot AI review requested due to automatic review settings August 23, 2026 04:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated no new comments.

Suppressed comments (5)

Previously missed (3) — in code that hasn't changed since the last review.

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/OntapStorageUtils.java:215

  • buildOntapSnapshotName(): when suffix length is >= MAX_SNAPSHOT_NAME_LENGTH, maxBaseLength <= 0 and normalizedBase.substring(0, maxLength) can throw if normalizedBase is shorter than maxLength. Guard the substring to avoid StringIndexOutOfBoundsException.
        int maxLength = OntapStorageConstants.MAX_SNAPSHOT_NAME_LENGTH;
        int maxBaseLength = maxLength - suffix.length();
        if (maxBaseLength <= 0) {
            return normalizedBase.substring(0, maxLength);
        }

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycle.java:128

  • initialize(): validateInitializeInputs(...) is called twice with the same arguments (once before building parameters, and again immediately after). This is redundant and makes future changes riskier if the method gains side effects.
        validateInitializeInputs(capacityBytes, podId, clusterId, zoneId, storagePoolName, providerName, managed, details);

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java:801

  • jobPollUntilSuccess(): the loop sleeps after every poll, even when the current poll already returned JOB_SUCCESS. This adds an unnecessary delay (one extra poll interval) to otherwise-fast operations. Return immediately when state becomes SUCCESS before sleeping.
                jobRetryCount++;
                Thread.sleep(sleepTimeInMilliSecs);
            }

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/IscsiAdmStorageAdaptor.java:278

  • waitForDiskToBecomeAvailable(): InterruptedException is caught and the method returns false, but the thread interrupt flag is not restored. This can break higher-level shutdown/cancellation logic.
            try {
                Thread.sleep(timeBetweenTries);
            } catch (InterruptedException ex) {
                logger.warn("Interrupted while waiting for iSCSI device {} to become available", volumeUuid, ex);
                return false;
            }

plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java:957

  • File ends with an extra closing brace (}}), which will not compile.
    }}

Copilot AI review requested due to automatic review settings August 23, 2026 04:35
@sandeeplocharla
sandeeplocharla marked this pull request as ready for review August 23, 2026 04:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

server/src/main/java/com/cloud/storage/StorageManagerImpl.java:1277

  • capacityBytes is a Long, but the update check uses reference comparison (!=) against pool.getCapacityBytes(). This can incorrectly treat equal values as different (or vice-versa) depending on boxing/caching, causing unintended updates and plugin lifecycle calls.
            if (capacityBytes != pool.getCapacityBytes()) {

List<ExportRule.ExportClient> clients = existingPolicy.getRules().get(0).getClients();
assertEquals(1, clients.size());
assertEquals("192.168.1.10/32", clients.get(0).getMatch());
}}
@sandeeplocharla

Copy link
Copy Markdown
Contributor Author

@blueorangutan package

@blueorangutan

Copy link
Copy Markdown

@sandeeplocharla a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan

Copy link
Copy Markdown

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 18957

@sandeeplocharla

Copy link
Copy Markdown
Contributor Author

@blueorangutan test

@sandeeplocharla

Copy link
Copy Markdown
Contributor Author

Hi @DaanHoogland
Can you please help me trigger the tests for this PR?

@DaanHoogland

Copy link
Copy Markdown
Contributor

@blueorangutan test

@blueorangutan

Copy link
Copy Markdown

@DaanHoogland a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests

@blueorangutan

Copy link
Copy Markdown

[SF] Trillian test result (tid-16809)
Environment: kvm-ol8 (x2), zone: Advanced Networking with Mgmt server ol8
Total time taken: 60368 seconds
Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr13897-t16809-kvm-ol8.zip
Smoke tests completed. 152 look OK, 4 have errors, 0 did not run
Only failed and skipped tests results shown below:

Test Result Time (s) Test File
ContextSuite context=TestClusterDRS>:setup Error 0.00 test_cluster_drs.py
test_list_system_vms_metrics_history Failure 0.87 test_metrics_api.py
test_01_ssl_offloading_isolated_network Failure 729.45 test_ssl_offloading.py
test_02_ssl_offloading_project_vpc Failure 728.57 test_ssl_offloading.py
test_1_userdata_on_ssvm Failure 127.75 test_systemvm_userdata.py

@sandeeplocharla

Copy link
Copy Markdown
Contributor Author

Hi @DaanHoogland @winterhazel @nvazquez @weizhouapache
Could you folks please review this PR and let me know your thoughts?

Also, I'm not able see the option to request review from people and blueorangutan test command doesn't work when I comment. Just curious on how they work here?

@weizhouapache weizhouapache added this to the 24.0.0 milestone Aug 24, 2026
@weizhouapache

Copy link
Copy Markdown
Member

thanks @sandeeplocharla @rajiv-jain-netapp and all NetApp contributors
I added this to 24.0.0 milestone as we will create 4.23.0 RC3 soon.

@sandeeplocharla @blueorangutan test can be only kicked by few authorized users.

@blueorangutan

Copy link
Copy Markdown

@weizhouapache [SL] unsupported parameters provided. Supported mgmt server os are: suse15, alma10, ol10, rocky10, alma9, centos7, centos6, rocky9, alma8, ubuntu18, ol9, ol8, ubuntu22, debian12, ubuntu20, ubuntu26, rocky8, ubuntu24. Supported hypervisors are: kvm-centos6, kvm-centos7, kvm-rocky8, kvm-rocky9, kvm-rocky10, kvm-ol8, kvm-ol9, kvm-ol10, kvm-alma8, kvm-alma9, kvm-alma10, kvm-ubuntu18, kvm-ubuntu20, kvm-ubuntu22, kvm-ubuntu24, kvm-ubuntu26, kvm-debian12, kvm-suse15, vmware-55u3, vmware-60u2, vmware-65u2, vmware-67u3, vmware-70u1, vmware-70u2, vmware-70u3, vmware-80, vmware-80u1, vmware-80u2, vmware-80u3, vmware-80u3e, xenserver-65sp1, xenserver-71, xenserver-74, xenserver-84, xcpng74, xcpng76, xcpng80, xcpng81, xcpng82, xcpng83

@rajiv-jain-netapp

Copy link
Copy Markdown
Contributor

thanks @sandeeplocharla @rajiv-jain-netapp and all NetApp contributors I added this to 24.0.0 milestone as we will create 4.23.0 RC3 soon.

@sandeeplocharla @blueorangutan test can be only kicked by few authorized users.

Appreciate @weizhouapache

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants