forked from apache/cloudstack
-
Notifications
You must be signed in to change notification settings - Fork 0
NFS3 protocol specific snapshot workflows #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rajiv-jain-netapp
wants to merge
17
commits into
main
Choose a base branch
from
feature/CSTACKEX-18_2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
f42552b
CSTACKEX-18_2: NFS3 snapshot changes
rajiv-jain-netapp 8894248
CSTACK-18_2: fixing junit dependent changes
rajiv-jain-netapp 3f0019a
STACK-18_2: fixes
rajiv-jain-netapp 9b79f46
CSTACKEX-18_2: adding VM snapshot logic
rajiv-jain-netapp 7a0d61e
CSTACKEX-18_2: fix junit issues
rajiv-jain-netapp 7c3419e
CSTACKEX-18_2: fixes for vm snapshot workflow
rajiv-jain-netapp d2b6a27
CSTACKEX-18_2: fixing the behaviour for the VM level snapshot when qu…
rajiv-jain-netapp c5d5428
CSTACKEX-18_2: incorporating the review comments.
rajiv-jain-netapp 3f18c11
CSTACKEX-18_2: transient fixes post incorporating the comments
rajiv-jain-netapp 723561b
CSTACKEX-18_2: Incorporate review comments
rajiv-jain-netapp 09968db
CSTACKEX-18_2: quiecing VM would be done based on user input for VM l…
rajiv-jain-netapp 0a1a9c4
CSTACKEX-18_2: ONTAP plugin can not handle memory snapshot with stora…
rajiv-jain-netapp 49df4c3
CSTACKEX-18_2: junit fix
rajiv-jain-netapp 776b9a2
CSTACKEX-18_2: junit fix2
rajiv-jain-netapp c04e223
CSTACKEX-18_2: ensure that ONTAP volume related calls are served by c…
rajiv-jain-netapp 186e59b
CSTACKEX-18_2: using flexvolume snapshot to get snapshot workflows fo…
rajiv-jain-netapp 1020a2c
CSTACKEX-18_2: using flexvolume snapshot even for CS volume snapshot …
rajiv-jain-netapp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -106,6 +106,10 @@ protected Answer takeDiskOnlyVmSnapshotOfRunningVm(CreateDiskOnlyVmSnapshotComma | |
| return new CreateDiskOnlyVmSnapshotAnswer(cmd, false, errorMsg, null); | ||
| } | ||
| return new CreateDiskOnlyVmSnapshotAnswer(cmd, false, e.getMessage(), null); | ||
| } catch (Exception e) { | ||
| String errorMsg = String.format("Creation of disk-only VM snapshot for VM [%s] failed due to %s.", vmName, e.getMessage()); | ||
| logger.error(errorMsg, e); | ||
| return new CreateDiskOnlyVmSnapshotAnswer(cmd, false, errorMsg, null); | ||
| } finally { | ||
| if (dm != null) { | ||
| try { | ||
|
|
@@ -146,21 +150,13 @@ protected Answer takeDiskOnlyVmSnapshotOfStoppedVm(CreateDiskOnlyVmSnapshotComma | |
| } | ||
| } catch (LibvirtException | QemuImgException e) { | ||
| logger.error("Exception while creating disk-only VM snapshot for VM [{}]. Deleting leftover deltas.", vmName, e); | ||
| for (VolumeObjectTO volumeObjectTO : volumeObjectTos) { | ||
| Pair<Long, String> volSizeAndNewPath = mapVolumeToSnapshotSizeAndNewVolumePath.get(volumeObjectTO.getUuid()); | ||
| PrimaryDataStoreTO primaryDataStoreTO = (PrimaryDataStoreTO) volumeObjectTO.getDataStore(); | ||
| KVMStoragePool kvmStoragePool = storagePoolMgr.getStoragePool(primaryDataStoreTO.getPoolType(), primaryDataStoreTO.getUuid()); | ||
|
|
||
| if (volSizeAndNewPath == null) { | ||
| continue; | ||
| } | ||
| try { | ||
| Files.deleteIfExists(Path.of(kvmStoragePool.getLocalPathFor(volSizeAndNewPath.second()))); | ||
| } catch (IOException ex) { | ||
| logger.warn("Tried to delete leftover snapshot at [{}] failed.", volSizeAndNewPath.second(), ex); | ||
| } | ||
| } | ||
| cleanupLeftoverDeltas(volumeObjectTos, mapVolumeToSnapshotSizeAndNewVolumePath, storagePoolMgr); | ||
| return new Answer(cmd, e); | ||
| } catch (Exception e) { | ||
| logger.error("Unexpected exception while creating disk-only VM snapshot for VM [{}]. Deleting leftover deltas.", vmName, e); | ||
| cleanupLeftoverDeltas(volumeObjectTos, mapVolumeToSnapshotSizeAndNewVolumePath, storagePoolMgr); | ||
| return new CreateDiskOnlyVmSnapshotAnswer(cmd, false, | ||
| String.format("Creation of disk-only VM snapshot for VM [%s] failed due to %s.", vmName, e.getMessage()), null); | ||
| } | ||
|
|
||
| return new CreateDiskOnlyVmSnapshotAnswer(cmd, true, null, mapVolumeToSnapshotSizeAndNewVolumePath); | ||
|
|
@@ -192,6 +188,23 @@ protected Pair<String, Map<String, Pair<Long, String>>> createSnapshotXmlAndNewV | |
| return new Pair<>(snapshotXml, volumeObjectToNewPathMap); | ||
| } | ||
|
|
||
| protected void cleanupLeftoverDeltas(List<VolumeObjectTO> volumeObjectTos, Map<String, Pair<Long, String>> mapVolumeToSnapshotSizeAndNewVolumePath, KVMStoragePoolManager storagePoolMgr) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this refactoring somehow help our plugin functionality? |
||
| for (VolumeObjectTO volumeObjectTO : volumeObjectTos) { | ||
| Pair<Long, String> volSizeAndNewPath = mapVolumeToSnapshotSizeAndNewVolumePath.get(volumeObjectTO.getUuid()); | ||
| PrimaryDataStoreTO primaryDataStoreTO = (PrimaryDataStoreTO) volumeObjectTO.getDataStore(); | ||
| KVMStoragePool kvmStoragePool = storagePoolMgr.getStoragePool(primaryDataStoreTO.getPoolType(), primaryDataStoreTO.getUuid()); | ||
|
|
||
| if (volSizeAndNewPath == null) { | ||
| continue; | ||
| } | ||
| try { | ||
| Files.deleteIfExists(Path.of(kvmStoragePool.getLocalPathFor(volSizeAndNewPath.second()))); | ||
| } catch (IOException ex) { | ||
| logger.warn("Tried to delete leftover snapshot at [{}] failed.", volSizeAndNewPath.second(), ex); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| protected long getFileSize(String path) { | ||
| return new File(path).length(); | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
154 changes: 154 additions & 0 deletions
154
...e/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/SnapshotFeignClient.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
| package org.apache.cloudstack.storage.feign.client; | ||
|
|
||
| import feign.Headers; | ||
| import feign.Param; | ||
| import feign.QueryMap; | ||
| import feign.RequestLine; | ||
| import org.apache.cloudstack.storage.feign.model.FlexVolSnapshot; | ||
| import org.apache.cloudstack.storage.feign.model.SnapshotFileRestoreRequest; | ||
| import org.apache.cloudstack.storage.feign.model.response.JobResponse; | ||
| import org.apache.cloudstack.storage.feign.model.response.OntapResponse; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * Feign client for ONTAP FlexVolume snapshot operations. | ||
| * | ||
| * <p>Maps to the ONTAP REST API endpoint: | ||
| * {@code /api/storage/volumes/{volume_uuid}/snapshots}</p> | ||
| * | ||
| * <p>FlexVolume snapshots are point-in-time, space-efficient copies of an entire | ||
| * FlexVolume. Unlike file-level clones, a single FlexVolume snapshot atomically | ||
| * captures <b>all</b> files/LUNs within the volume, making it ideal for VM-level | ||
| * snapshots when multiple CloudStack disks reside on the same FlexVolume.</p> | ||
| */ | ||
| public interface SnapshotFeignClient { | ||
|
|
||
| /** | ||
| * Creates a new snapshot for the specified FlexVolume. | ||
| * | ||
| * <p>ONTAP REST: {@code POST /api/storage/volumes/{volume_uuid}/snapshots}</p> | ||
| * | ||
| * @param authHeader Basic auth header | ||
| * @param volumeUuid UUID of the ONTAP FlexVolume | ||
| * @param snapshot Snapshot request body (at minimum, the {@code name} field) | ||
| * @return JobResponse containing the async job reference | ||
| */ | ||
| @RequestLine("POST /api/storage/volumes/{volumeUuid}/snapshots") | ||
| @Headers({"Authorization: {authHeader}", "Content-Type: application/json"}) | ||
| JobResponse createSnapshot(@Param("authHeader") String authHeader, | ||
| @Param("volumeUuid") String volumeUuid, | ||
| FlexVolSnapshot snapshot); | ||
|
|
||
| /** | ||
| * Lists snapshots for the specified FlexVolume. | ||
| * | ||
| * <p>ONTAP REST: {@code GET /api/storage/volumes/{volume_uuid}/snapshots}</p> | ||
| * | ||
| * @param authHeader Basic auth header | ||
| * @param volumeUuid UUID of the ONTAP FlexVolume | ||
| * @param queryParams Optional query parameters (e.g., {@code name}, {@code fields}) | ||
| * @return Paginated response of FlexVolSnapshot records | ||
| */ | ||
| @RequestLine("GET /api/storage/volumes/{volumeUuid}/snapshots") | ||
| @Headers({"Authorization: {authHeader}"}) | ||
| OntapResponse<FlexVolSnapshot> getSnapshots(@Param("authHeader") String authHeader, | ||
| @Param("volumeUuid") String volumeUuid, | ||
| @QueryMap Map<String, Object> queryParams); | ||
|
|
||
| /** | ||
| * Retrieves a specific snapshot by UUID. | ||
| * | ||
| * <p>ONTAP REST: {@code GET /api/storage/volumes/{volume_uuid}/snapshots/{uuid}}</p> | ||
| * | ||
| * @param authHeader Basic auth header | ||
| * @param volumeUuid UUID of the ONTAP FlexVolume | ||
| * @param snapshotUuid UUID of the snapshot | ||
| * @return The FlexVolSnapshot object | ||
| */ | ||
| @RequestLine("GET /api/storage/volumes/{volumeUuid}/snapshots/{snapshotUuid}") | ||
| @Headers({"Authorization: {authHeader}"}) | ||
| FlexVolSnapshot getSnapshotByUuid(@Param("authHeader") String authHeader, | ||
| @Param("volumeUuid") String volumeUuid, | ||
| @Param("snapshotUuid") String snapshotUuid); | ||
|
|
||
| /** | ||
| * Deletes a specific snapshot. | ||
| * | ||
| * <p>ONTAP REST: {@code DELETE /api/storage/volumes/{volume_uuid}/snapshots/{uuid}}</p> | ||
| * | ||
| * @param authHeader Basic auth header | ||
| * @param volumeUuid UUID of the ONTAP FlexVolume | ||
| * @param snapshotUuid UUID of the snapshot to delete | ||
| * @return JobResponse containing the async job reference | ||
| */ | ||
| @RequestLine("DELETE /api/storage/volumes/{volumeUuid}/snapshots/{snapshotUuid}") | ||
| @Headers({"Authorization: {authHeader}"}) | ||
| JobResponse deleteSnapshot(@Param("authHeader") String authHeader, | ||
| @Param("volumeUuid") String volumeUuid, | ||
| @Param("snapshotUuid") String snapshotUuid); | ||
|
|
||
| /** | ||
| * Restores a volume to a specific snapshot. | ||
| * | ||
| * <p>ONTAP REST: {@code PATCH /api/storage/volumes/{volume_uuid}/snapshots/{uuid}} | ||
| * with body {@code {"restore": true}} triggers a snapshot restore operation.</p> | ||
| * | ||
| * <p><b>Note:</b> This is a destructive operation — all data written after the | ||
| * snapshot was taken will be lost.</p> | ||
| * | ||
| * @param authHeader Basic auth header | ||
| * @param volumeUuid UUID of the ONTAP FlexVolume | ||
| * @param snapshotUuid UUID of the snapshot to restore to | ||
| * @param body Request body, typically {@code {"restore": true}} | ||
| * @return JobResponse containing the async job reference | ||
| */ | ||
| @RequestLine("PATCH /api/storage/volumes/{volumeUuid}/snapshots/{snapshotUuid}?restore_to_snapshot=true") | ||
| @Headers({"Authorization: {authHeader}", "Content-Type: application/json"}) | ||
| JobResponse restoreSnapshot(@Param("authHeader") String authHeader, | ||
| @Param("volumeUuid") String volumeUuid, | ||
| @Param("snapshotUuid") String snapshotUuid); | ||
|
|
||
| /** | ||
| * Restores a single file or LUN from a FlexVolume snapshot. | ||
| * | ||
| * <p>ONTAP REST: | ||
| * {@code POST /api/storage/volumes/{volume_uuid}/snapshots/{snapshot_uuid}/files/{file_path}/restore}</p> | ||
| * | ||
| * <p>This restores only the specified file/LUN from the snapshot to the | ||
| * given {@code destination_path}, without reverting the entire FlexVolume. | ||
| * Ideal when multiple VMs share the same FlexVolume.</p> | ||
| * | ||
| * @param authHeader Basic auth header | ||
| * @param volumeUuid UUID of the ONTAP FlexVolume | ||
| * @param snapshotUuid UUID of the snapshot containing the file | ||
| * @param filePath path of the file within the snapshot (URL-encoded if needed) | ||
| * @param request request body with {@code destination_path} | ||
| * @return JobResponse containing the async job reference | ||
| */ | ||
| @RequestLine("POST /api/storage/volumes/{volumeUuid}/snapshots/{snapshotUuid}/files/{filePath}/restore") | ||
| @Headers({"Authorization: {authHeader}", "Content-Type: application/json"}) | ||
| JobResponse restoreFileFromSnapshot(@Param("authHeader") String authHeader, | ||
| @Param("volumeUuid") String volumeUuid, | ||
| @Param("snapshotUuid") String snapshotUuid, | ||
| @Param("filePath") String filePath, | ||
| SnapshotFileRestoreRequest request); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this change is required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am returning the failure reasons through the exception.