CSTACKEX-127: Primary storage-pool is getting created even if desired data LIFs are not reachable#76
CSTACKEX-127: Primary storage-pool is getting created even if desired data LIFs are not reachable#76sandeeplocharla wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the ONTAP primary storage workflow to select a reachable/usable data LIF based on operational status and node affinity (aggregate home node vs. failover vs. cross-node fallback), and surfaces warnings via pool details/alerts when selection is degraded.
Changes:
- Adds node-aware, status-aware LIF selection in
StorageStrategy.getNetworkInterface()and returns both the chosen LIF IP + an optional warning. - Captures the chosen aggregate’s node during volume creation to bias LIF selection toward optimal locality.
- Updates lifecycle + tests to handle the new
(lifIp, warning)result and emits storage alerts when degraded selection occurs.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/StorageStrategyTest.java | Expands unit tests for LIF status and node-affinity tiers; avoids mocking issues on newer JDKs. |
| plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycleTest.java | Updates mocks for new Pair<String,String> LIF return type and scope behavior. |
| plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/OntapStorageUtils.java | Adds helper to send storage alerts for degraded LIF selection. |
| plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/OntapStorageConstants.java | Adds constants for aggregate node/space fields and LIF state/location/warning keys. |
| plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java | Implements tiered LIF selection and tracks chosenAggregateNode from aggregate selection. |
| plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycle.java | Persists selected LIF + warning and emits an alert during pool initialization. |
| plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/IpInterface.java | Extends model with state, enabled, and location to support selection logic. |
| plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/Aggregate.java | Extends model with node and setters needed for reading/constructing detailed aggregate info. |
| plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/AggregateFeignClient.java | Adds @QueryMap to request specific aggregate fields (node/space/state). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
This pull request has merge conflicts. Dear author, please fix the conflicts and sync your branch with the base branch. |
2b19269 to
50d9045
Compare
50d9045 to
52fc886
Compare
| IpInterface currentNodeInterface = null; | ||
| IpInterface fallbackInterface = null; | ||
|
|
||
| for (IpInterface iface : response.getRecords()) { |
| * @return DataStore instance | ||
| */ | ||
| @Override | ||
| public DataStore initialize(Map<String, Object> dsInfos) { |
There was a problem hiding this comment.
this method is becoming very big, can we have some private method instead?
| logger.warn("Aggregate " + aggr.getName() + " is not in online state. Skipping this aggregate."); | ||
| continue; | ||
| } else if (aggrResp.getSpace() == null || aggrResp.getAvailableBlockStorageSpace() == null || | ||
| aggrResp.getAvailableBlockStorageSpace() <= storage.getSize().doubleValue()) { |
There was a problem hiding this comment.
What is this check validating? How does it help determine that there isn't enough free space available in the aggregate?
There was a problem hiding this comment.
Its skipping aggregates with available space less than the requested capacity for storage pool.
| } | ||
|
|
||
| private void validateAndSelectAggregatesForVolumeCreation(String authHeader, String svmName, List<Aggregate> aggrs) { | ||
| if (aggrs == null || aggrs.isEmpty()) { |
There was a problem hiding this comment.
I have a question on the flow here. This method is invoked during the connect workflow, where we apply a set of filters/validations on the aggregates. As soon as the workflow finds the first aggregate that satisfies the criteria, it breaks out of the loop and stores that aggregate in a class-level variable.
Later, during volume creation, we appear to be using this class-level variable with the assumption that it contains all eligible aggregates. However, based on the current flow, it seems to contain only the single aggregate that was selected before the loop exited. The code path in the createVolume() method (and the related changes in this PR) seems to rely on that variable.
Is this the intended behaviour?
My understanding was that we would retain all aggregates that pass the filtering criteria and, during volume creation, iterate through the eligible aggregates to select the most appropriate one. That would also allow us to place volumes on aggregates with more available capacity and achieve better load balancing of storage consumption instead of always using the first matching aggregate.
There was a problem hiding this comment.
The break should not be there. So, its been corrected and tested. Was waiting for more comments to raise a diff. 'break' would be removed in the next commit.
Choosing IpInterface based on its status and affinity to the chosen aggregate
Description
This PR...
Types of changes
Feature/Enhancement Scale or Bug Severity
Feature/Enhancement Scale
Bug Severity
Screenshots (if appropriate):
How Has This Been Tested?
Note: The following images have been captured for NFS3, the same would be the case for iSCSI.
Clearly, by the virtue of free space available, the plugin would choose
sti246_vsim_ocvs040d_aggr1by default.Scenario-1 [pool_P1]: Happy path; No LIFs were down.



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




040dnode were down; with one LIF whose current node:040d, while its home node:040cScenario-3 [pool_P3]: None of the




040dnode LIFs are UP. First best available LIF is picked from040c.