Skip to content

Commit 186e59b

Browse files
CSTACKEX-18_2: using flexvolume snapshot to get snapshot workflows for vm snapshots
1 parent c04e223 commit 186e59b

File tree

8 files changed

+1198
-284
lines changed

8 files changed

+1198
-284
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.cloudstack.storage.feign.client;
20+
21+
import feign.Headers;
22+
import feign.Param;
23+
import feign.QueryMap;
24+
import feign.RequestLine;
25+
import org.apache.cloudstack.storage.feign.model.FlexVolSnapshot;
26+
import org.apache.cloudstack.storage.feign.model.SnapshotFileRestoreRequest;
27+
import org.apache.cloudstack.storage.feign.model.response.JobResponse;
28+
import org.apache.cloudstack.storage.feign.model.response.OntapResponse;
29+
30+
import java.util.Map;
31+
32+
/**
33+
* Feign client for ONTAP FlexVolume snapshot operations.
34+
*
35+
* <p>Maps to the ONTAP REST API endpoint:
36+
* {@code /api/storage/volumes/{volume_uuid}/snapshots}</p>
37+
*
38+
* <p>FlexVolume snapshots are point-in-time, space-efficient copies of an entire
39+
* FlexVolume. Unlike file-level clones, a single FlexVolume snapshot atomically
40+
* captures <b>all</b> files/LUNs within the volume, making it ideal for VM-level
41+
* snapshots when multiple CloudStack disks reside on the same FlexVolume.</p>
42+
*/
43+
public interface SnapshotFeignClient {
44+
45+
/**
46+
* Creates a new snapshot for the specified FlexVolume.
47+
*
48+
* <p>ONTAP REST: {@code POST /api/storage/volumes/{volume_uuid}/snapshots}</p>
49+
*
50+
* @param authHeader Basic auth header
51+
* @param volumeUuid UUID of the ONTAP FlexVolume
52+
* @param snapshot Snapshot request body (at minimum, the {@code name} field)
53+
* @return JobResponse containing the async job reference
54+
*/
55+
@RequestLine("POST /api/storage/volumes/{volumeUuid}/snapshots")
56+
@Headers({"Authorization: {authHeader}", "Content-Type: application/json"})
57+
JobResponse createSnapshot(@Param("authHeader") String authHeader,
58+
@Param("volumeUuid") String volumeUuid,
59+
FlexVolSnapshot snapshot);
60+
61+
/**
62+
* Lists snapshots for the specified FlexVolume.
63+
*
64+
* <p>ONTAP REST: {@code GET /api/storage/volumes/{volume_uuid}/snapshots}</p>
65+
*
66+
* @param authHeader Basic auth header
67+
* @param volumeUuid UUID of the ONTAP FlexVolume
68+
* @param queryParams Optional query parameters (e.g., {@code name}, {@code fields})
69+
* @return Paginated response of FlexVolSnapshot records
70+
*/
71+
@RequestLine("GET /api/storage/volumes/{volumeUuid}/snapshots")
72+
@Headers({"Authorization: {authHeader}"})
73+
OntapResponse<FlexVolSnapshot> getSnapshots(@Param("authHeader") String authHeader,
74+
@Param("volumeUuid") String volumeUuid,
75+
@QueryMap Map<String, Object> queryParams);
76+
77+
/**
78+
* Retrieves a specific snapshot by UUID.
79+
*
80+
* <p>ONTAP REST: {@code GET /api/storage/volumes/{volume_uuid}/snapshots/{uuid}}</p>
81+
*
82+
* @param authHeader Basic auth header
83+
* @param volumeUuid UUID of the ONTAP FlexVolume
84+
* @param snapshotUuid UUID of the snapshot
85+
* @return The FlexVolSnapshot object
86+
*/
87+
@RequestLine("GET /api/storage/volumes/{volumeUuid}/snapshots/{snapshotUuid}")
88+
@Headers({"Authorization: {authHeader}"})
89+
FlexVolSnapshot getSnapshotByUuid(@Param("authHeader") String authHeader,
90+
@Param("volumeUuid") String volumeUuid,
91+
@Param("snapshotUuid") String snapshotUuid);
92+
93+
/**
94+
* Deletes a specific snapshot.
95+
*
96+
* <p>ONTAP REST: {@code DELETE /api/storage/volumes/{volume_uuid}/snapshots/{uuid}}</p>
97+
*
98+
* @param authHeader Basic auth header
99+
* @param volumeUuid UUID of the ONTAP FlexVolume
100+
* @param snapshotUuid UUID of the snapshot to delete
101+
* @return JobResponse containing the async job reference
102+
*/
103+
@RequestLine("DELETE /api/storage/volumes/{volumeUuid}/snapshots/{snapshotUuid}")
104+
@Headers({"Authorization: {authHeader}"})
105+
JobResponse deleteSnapshot(@Param("authHeader") String authHeader,
106+
@Param("volumeUuid") String volumeUuid,
107+
@Param("snapshotUuid") String snapshotUuid);
108+
109+
/**
110+
* Restores a volume to a specific snapshot.
111+
*
112+
* <p>ONTAP REST: {@code PATCH /api/storage/volumes/{volume_uuid}/snapshots/{uuid}}
113+
* with body {@code {"restore": true}} triggers a snapshot restore operation.</p>
114+
*
115+
* <p><b>Note:</b> This is a destructive operation — all data written after the
116+
* snapshot was taken will be lost.</p>
117+
*
118+
* @param authHeader Basic auth header
119+
* @param volumeUuid UUID of the ONTAP FlexVolume
120+
* @param snapshotUuid UUID of the snapshot to restore to
121+
* @param body Request body, typically {@code {"restore": true}}
122+
* @return JobResponse containing the async job reference
123+
*/
124+
@RequestLine("PATCH /api/storage/volumes/{volumeUuid}/snapshots/{snapshotUuid}?restore_to_snapshot=true")
125+
@Headers({"Authorization: {authHeader}", "Content-Type: application/json"})
126+
JobResponse restoreSnapshot(@Param("authHeader") String authHeader,
127+
@Param("volumeUuid") String volumeUuid,
128+
@Param("snapshotUuid") String snapshotUuid);
129+
130+
/**
131+
* Restores a single file or LUN from a FlexVolume snapshot.
132+
*
133+
* <p>ONTAP REST:
134+
* {@code POST /api/storage/volumes/{volume_uuid}/snapshots/{snapshot_uuid}/files/{file_path}/restore}</p>
135+
*
136+
* <p>This restores only the specified file/LUN from the snapshot to the
137+
* given {@code destination_path}, without reverting the entire FlexVolume.
138+
* Ideal when multiple VMs share the same FlexVolume.</p>
139+
*
140+
* @param authHeader Basic auth header
141+
* @param volumeUuid UUID of the ONTAP FlexVolume
142+
* @param snapshotUuid UUID of the snapshot containing the file
143+
* @param filePath path of the file within the snapshot (URL-encoded if needed)
144+
* @param request request body with {@code destination_path}
145+
* @return JobResponse containing the async job reference
146+
*/
147+
@RequestLine("POST /api/storage/volumes/{volumeUuid}/snapshots/{snapshotUuid}/files/{filePath}/restore")
148+
@Headers({"Authorization: {authHeader}", "Content-Type: application/json"})
149+
JobResponse restoreFileFromSnapshot(@Param("authHeader") String authHeader,
150+
@Param("volumeUuid") String volumeUuid,
151+
@Param("snapshotUuid") String snapshotUuid,
152+
@Param("filePath") String filePath,
153+
SnapshotFileRestoreRequest request);
154+
}

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/FileClone.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ public class FileClone {
3232
private String destinationPath;
3333
@JsonProperty("volume")
3434
private VolumeConcise volume;
35+
@JsonProperty("overwrite_destination")
36+
private Boolean overwriteDestination;
37+
3538
public VolumeConcise getVolume() {
3639
return volume;
3740
}
@@ -50,4 +53,10 @@ public String getDestinationPath() {
5053
public void setDestinationPath(String destinationPath) {
5154
this.destinationPath = destinationPath;
5255
}
56+
public Boolean getOverwriteDestination() {
57+
return overwriteDestination;
58+
}
59+
public void setOverwriteDestination(Boolean overwriteDestination) {
60+
this.overwriteDestination = overwriteDestination;
61+
}
5362
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.cloudstack.storage.feign.model;
20+
21+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
22+
import com.fasterxml.jackson.annotation.JsonInclude;
23+
import com.fasterxml.jackson.annotation.JsonProperty;
24+
25+
/**
26+
* Model representing an ONTAP FlexVolume-level snapshot.
27+
*
28+
* <p>Maps to the ONTAP REST API resource at
29+
* {@code /api/storage/volumes/{volume.uuid}/snapshots}.</p>
30+
*
31+
* <p>For creation, only the {@code name} field is required in the POST body.
32+
* ONTAP returns the full representation including {@code uuid}, {@code name},
33+
* and {@code create_time} on GET requests.</p>
34+
*
35+
* @see <a href="https://docs.netapp.com/us-en/ontap-restapi/ontap/storage_volumes_volume.uuid_snapshots_endpoint_overview.html">
36+
* ONTAP REST API - Volume Snapshots</a>
37+
*/
38+
@JsonIgnoreProperties(ignoreUnknown = true)
39+
@JsonInclude(JsonInclude.Include.NON_NULL)
40+
public class FlexVolSnapshot {
41+
42+
@JsonProperty("uuid")
43+
private String uuid;
44+
45+
@JsonProperty("name")
46+
private String name;
47+
48+
@JsonProperty("create_time")
49+
private String createTime;
50+
51+
@JsonProperty("comment")
52+
private String comment;
53+
54+
/** Concise reference to the parent volume (returned in GET responses). */
55+
@JsonProperty("volume")
56+
private VolumeConcise volume;
57+
58+
public FlexVolSnapshot() {
59+
// default constructor for Jackson
60+
}
61+
62+
public FlexVolSnapshot(String name) {
63+
this.name = name;
64+
}
65+
66+
public FlexVolSnapshot(String name, String comment) {
67+
this.name = name;
68+
this.comment = comment;
69+
}
70+
71+
// ── Getters / Setters ────────────────────────────────────────────────────
72+
73+
public String getUuid() {
74+
return uuid;
75+
}
76+
77+
public void setUuid(String uuid) {
78+
this.uuid = uuid;
79+
}
80+
81+
public String getName() {
82+
return name;
83+
}
84+
85+
public void setName(String name) {
86+
this.name = name;
87+
}
88+
89+
public String getCreateTime() {
90+
return createTime;
91+
}
92+
93+
public void setCreateTime(String createTime) {
94+
this.createTime = createTime;
95+
}
96+
97+
public String getComment() {
98+
return comment;
99+
}
100+
101+
public void setComment(String comment) {
102+
this.comment = comment;
103+
}
104+
105+
public VolumeConcise getVolume() {
106+
return volume;
107+
}
108+
109+
public void setVolume(VolumeConcise volume) {
110+
this.volume = volume;
111+
}
112+
113+
@Override
114+
public String toString() {
115+
return "FlexVolSnapshot{" +
116+
"uuid='" + uuid + '\'' +
117+
", name='" + name + '\'' +
118+
", createTime='" + createTime + '\'' +
119+
", comment='" + comment + '\'' +
120+
'}';
121+
}
122+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.cloudstack.storage.feign.model;
20+
21+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
22+
import com.fasterxml.jackson.annotation.JsonInclude;
23+
import com.fasterxml.jackson.annotation.JsonProperty;
24+
25+
/**
26+
* Request body for the ONTAP Snapshot File Restore API.
27+
*
28+
* <p>ONTAP REST endpoint:
29+
* {@code POST /api/storage/volumes/{volume.uuid}/snapshots/{snapshot.uuid}/files/{file.path}/restore}</p>
30+
*
31+
* <p>This API restores a single file or LUN from a FlexVolume snapshot to a
32+
* specified destination path, without reverting the entire FlexVolume.</p>
33+
*/
34+
@JsonIgnoreProperties(ignoreUnknown = true)
35+
@JsonInclude(JsonInclude.Include.NON_NULL)
36+
public class SnapshotFileRestoreRequest {
37+
38+
@JsonProperty("destination_path")
39+
private String destinationPath;
40+
41+
public SnapshotFileRestoreRequest() {
42+
}
43+
44+
public SnapshotFileRestoreRequest(String destinationPath) {
45+
this.destinationPath = destinationPath;
46+
}
47+
48+
public String getDestinationPath() {
49+
return destinationPath;
50+
}
51+
52+
public void setDestinationPath(String destinationPath) {
53+
this.destinationPath = destinationPath;
54+
}
55+
}

0 commit comments

Comments
 (0)