Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@

import feign.QueryMap;
import org.apache.cloudstack.storage.feign.model.ExportPolicy;
import org.apache.cloudstack.storage.feign.model.FileCloneRequest;
import org.apache.cloudstack.storage.feign.model.FileInfo;
import org.apache.cloudstack.storage.feign.model.response.JobResponse;
import org.apache.cloudstack.storage.feign.model.response.OntapResponse;
import feign.Headers;
import feign.Param;
Expand Down Expand Up @@ -58,6 +60,10 @@ void createFile(@Param("authHeader") String authHeader,
@Param("path") String filePath,
FileInfo file);

@RequestLine("POST /api/storage/file/clone")
@Headers({"Authorization: {authHeader}", "Content-Type: application/json"})
JobResponse cloneFile(@Param("authHeader") String authHeader, FileCloneRequest request);

// Export Policy Operations
@RequestLine("POST /api/protocols/nfs/export-policies")
@Headers({"Authorization: {authHeader}"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.apache.cloudstack.storage.feign.model.IscsiService;
import org.apache.cloudstack.storage.feign.model.Lun;
import org.apache.cloudstack.storage.feign.model.LunMap;
import org.apache.cloudstack.storage.feign.model.LunRestoreRequest;
import org.apache.cloudstack.storage.feign.model.response.JobResponse;
import org.apache.cloudstack.storage.feign.model.response.OntapResponse;
import feign.Headers;
Expand All @@ -42,6 +41,10 @@ public interface SANFeignClient {
@Headers({"Authorization: {authHeader}"})
OntapResponse<Lun> createLun(@Param("authHeader") String authHeader, @Param("returnRecords") boolean returnRecords, Lun lun);

@RequestLine("POST /api/storage/luns")
@Headers({"Authorization: {authHeader}", "Content-Type: application/json"})
JobResponse cloneLun(@Param("authHeader") String authHeader, Lun lun);

@RequestLine("GET /api/storage/luns")
@Headers({"Authorization: {authHeader}"})
OntapResponse<Lun> getLunResponse(@Param("authHeader") String authHeader, @QueryMap Map<String, Object> queryMap);
Expand Down Expand Up @@ -90,24 +93,4 @@ public interface SANFeignClient {
void deleteLunMap(@Param("authHeader") String authHeader,
@Param("lunUuid") String lunUUID,
@Param("igroupUuid") String igroupUUID);

// LUN Restore API
/**
* Restores a LUN from a FlexVolume snapshot.
*
* <p>ONTAP REST: {@code POST /api/storage/luns/{lun.uuid}/restore}</p>
*
* <p>This API restores the LUN data from a specified snapshot to a destination path.
* The LUN must exist and the snapshot must contain the LUN data.</p>
*
* @param authHeader Basic auth header
* @param lunUuid UUID of the LUN to restore
* @param request Request body with snapshot name and destination path
* @return JobResponse containing the async job reference
*/
@RequestLine("POST /api/storage/luns/{lunUuid}/restore")
@Headers({"Authorization: {authHeader}", "Content-Type: application/json"})
JobResponse restoreLun(@Param("authHeader") String authHeader,
@Param("lunUuid") String lunUuid,
LunRestoreRequest request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@
import feign.Param;
import feign.QueryMap;
import feign.RequestLine;
import org.apache.cloudstack.storage.feign.model.CliSnapshotRestoreRequest;
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;

Expand Down Expand Up @@ -107,78 +105,4 @@ 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);

/**
* Restores a single file or LUN from a FlexVolume snapshot using the CLI native API.
*
* <p>ONTAP REST (CLI passthrough):
* {@code POST /api/private/cli/volume/snapshot/restore-file}</p>
*
* <p>This CLI-based API is more reliable and works for both NFS files and iSCSI LUNs.
* The request body contains all required parameters: vserver, volume, snapshot, and path.</p>
*
* <p>Example payload:
* <pre>
* {
* "vserver": "vs0",
* "volume": "rajiv_ONTAP_SP1",
* "snapshot": "DATA-3-428726fe-7440-4b41-8d47-3f654e5d9814",
* "path": "/d266bb2c-d479-47ad-81c3-a070e8bb58c0"
* }
* </pre>
* </p>
*
* @param authHeader Basic auth header
* @param request CLI snapshot restore request containing vserver, volume, snapshot, and path
* @return JobResponse containing the async job reference (if applicable)
*/
@RequestLine("POST /api/private/cli/volume/snapshot/restore-file")
@Headers({"Authorization: {authHeader}", "Content-Type: application/json"})
JobResponse restoreFileFromSnapshotCli(@Param("authHeader") String authHeader,
CliSnapshotRestoreRequest request);
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,37 @@
*/
package org.apache.cloudstack.storage.feign.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
* Request body for the ONTAP Snapshot File Restore API.
*
* <p>ONTAP REST endpoint:
* {@code POST /api/storage/volumes/{volume.uuid}/snapshots/{snapshot.uuid}/files/{file.path}/restore}</p>
*
* <p>This API restores a single file or LUN from a FlexVolume snapshot to a
* specified destination path, without reverting the entire FlexVolume.</p>
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SnapshotFileRestoreRequest {
public class FileCloneRequest {
@JsonProperty("volume")
private VolumeRef volume;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

we can use VolumeConcise class instead creating new


@JsonProperty("source_path")
private String sourcePath;

@JsonProperty("destination_path")
private String destinationPath;

public SnapshotFileRestoreRequest() {
@JsonProperty("is_override")
private Boolean isOverride;

public VolumeRef getVolume() {
return volume;
}

public SnapshotFileRestoreRequest(String destinationPath) {
this.destinationPath = destinationPath;
public void setVolume(VolumeRef volume) {
this.volume = volume;
}

public String getSourcePath() {
return sourcePath;
}

public void setSourcePath(String sourcePath) {
this.sourcePath = sourcePath;
}

public String getDestinationPath() {
Expand All @@ -52,4 +58,37 @@ public String getDestinationPath() {
public void setDestinationPath(String destinationPath) {
this.destinationPath = destinationPath;
}

public Boolean getIsOverride() {
return isOverride;
}

public void setIsOverride(Boolean isOverride) {
this.isOverride = isOverride;
}

@JsonInclude(JsonInclude.Include.NON_NULL)
public static class VolumeRef {
@JsonProperty("name")
private String name;

@JsonProperty("uuid")
private String uuid;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getUuid() {
return uuid;
}

public void setUuid(String uuid) {
this.uuid = uuid;
}
}
}
Loading
Loading