CSTACKEX-158: if ontap snapshot are already delete from ontap side, d…#82
CSTACKEX-158: if ontap snapshot are already delete from ontap side, d…#82rajiv-jain-netapp wants to merge 2 commits into
Conversation
…eletion of CS side of snapshot should not fail on not finding ontap snapshot.
There was a problem hiding this comment.
Pull request overview
This PR makes ONTAP snapshot deletion idempotent from CloudStack’s perspective: if the backend ONTAP snapshot is already gone, CloudStack-side deletion should not fail.
Changes:
- Add a shared helper (
OntapStorageUtils.isOntapSnapshotNotFoundError) to recognize “snapshot already missing” errors. - Update ONTAP snapshot delete workflows to treat those errors as success (both in
StorageStrategyandOntapPrimaryDatastoreDriver). - Add/extend unit tests to cover the new behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/OntapStorageUtils.java | Introduces shared “snapshot not found” detection helper used by delete paths. |
| plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java | Wraps FlexVol snapshot deletion with “already absent” handling. |
| plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java | Replaces local matcher with shared helper for delete idempotency. |
| plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/utils/OntapStorageUtilsTest.java | Adds tests for the new helper (with recommended regression coverage). |
| plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/StorageStrategyTest.java | Adds a test ensuring delete succeeds when ONTAP reports the snapshot is missing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * Returns true when the exception indicates the ONTAP snapshot was already removed. | ||
| * Delete workflows treat a missing backend snapshot as idempotent success. | ||
| */ | ||
| public static boolean isOntapSnapshotNotFoundError(Throwable error) { |
There was a problem hiding this comment.
If the idea is to throw a polished message back to the user, wouldn't it be better to have a generic ONTAP Exception wrapper class and have similar implementations for all possible ONTAP error codes?
There was a problem hiding this comment.
This was added purely to improve readability. You can treat it as a helper method rather than an exception class specific to ONTAP.
There was a problem hiding this comment.
This could be a generic method not specific to snapshot, like instead of isOntapSnapshotNotFoundError(Throwable error) could be isNotFoundError(Throwable error). And, maybe this could be in a separate class and similar methods could be written for 401/403/500...?
| } | ||
| String message = error.getMessage(); | ||
| if (message != null) { | ||
| String lower = message.toLowerCase(); |
There was a problem hiding this comment.
it is better to check the status code as 404
There was a problem hiding this comment.
To keep the implementation generic, I chose to rely on the exception message rather than a specific error code. We could certainly check for error codes as well, but that would make the logic more implementation-specific and reduce its reusability across different scenarios.
There was a problem hiding this comment.
but for any entity which is not found, we will receive 404 error code,
There was a problem hiding this comment.
All these checks are placed at exception handling level. Error code related checks can be handled at feign response level.
There was a problem hiding this comment.
The snapshot delete operation is asynchronous and initially returns a job response. As a result, any "snapshot not found" condition would typically be surfaced during job polling rather than as an immediate response to the DELETE request. Therefore, we should not expect a direct 404 from the initial delete call. ONTAP uses its own error codes for these scenarios, which are reported through the asynchronous job status and results.
| return false; | ||
| } | ||
| String message = error.getMessage(); | ||
| if (message != null) { |
There was a problem hiding this comment.
if message is null somehow, I think func run infinitely ?
There was a problem hiding this comment.
It shouldn't recurse indefinitely, as we already have a null check at the beginning of the method. My intent here is to ensure that a 404 (Not Found) condition is not missed simply because the exception is wrapped or thrown through multiple nested layers.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/utils/OntapStorageUtils.java:258
isOntapObjectNotFoundErrorlowercases with the default locale and also treats any message containing generic "not found" as an ONTAP-missing-object signal. This can mask non-ONTAP failures (e.g., CloudRuntimeException("Snapshot not found …") thrown in this plugin) as idempotent success when used by delete flows. Consider scoping the match to ONTAP delete/job-failure messages (and still allowing HTTP 404), and use a locale-stable lowercasing.
String message = error.getMessage();
if (message != null) {
String lower = message.toLowerCase();
if (lower.contains("404") || lower.contains("not found") || lower.contains("does not exist")
|| lower.contains("entry doesn't exist")) {
return true;
}
}
return isOntapObjectNotFoundError(error.getCause());
| @Test | ||
| public void isOntapSnapshotNotFoundError_matchesEntryDoesNotExist() { | ||
| CloudRuntimeException ex = new CloudRuntimeException("Job failed with error: entry doesn't exist"); | ||
| assertTrue(OntapStorageUtils.isOntapObjectNotFoundError(ex)); | ||
| } | ||
|
|
||
| @Test | ||
| public void isOntapSnapshotNotFoundError_rejectsUnrelatedErrors() { | ||
| assertFalse(OntapStorageUtils.isOntapObjectNotFoundError( |
…Deletion of CS side of snapshot should not fail on not finding ontap snapshot.
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?
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.
How did you try to break this feature and the system with this change?