From 9a185900070b95e068792bd914266b8874103a77 Mon Sep 17 00:00:00 2001
From: sp16743
Date: Tue, 20 Oct 2026 14:50:58 +0530
Subject: [PATCH] CSTACKEX-348 Fix NFS volume from snapshot source path
---
.../storage/driver/OntapPrimaryDatastoreDriver.java | 4 +++-
.../cloudstack/storage/service/UnifiedNASStrategy.java | 5 ++---
.../storage/driver/OntapPrimaryDatastoreDriverTest.java | 5 +++--
.../storage/service/UnifiedNASStrategyTest.java | 9 ++++-----
4 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java
index 8a5cbb6a753c..6f7dc7a201bf 100644
--- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java
+++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java
@@ -2293,7 +2293,9 @@ private CloudStackVolume createCloneFileFromSnapshotRequest(StoragePoolVO storag
String flexVolName = details.get(OntapStorageConstants.VOLUME_NAME);
FileInfo file = new FileInfo();
- file.setPath(OntapStorageUtils.toFlexVolRelativePath(sourceVolumePath, flexVolName));
+ String relativeSourcePath = OntapStorageUtils.toFlexVolRelativePath(sourceVolumePath, flexVolName);
+ file.setPath(OntapStorageConstants.DOT + OntapStorageConstants.SNAPSHOT_PATH_SEGMENT + snapshotName
+ + OntapStorageConstants.SLASH + relativeSourcePath);
CloudStackVolume request = new CloudStackVolume();
request.setDatastoreId(String.valueOf(storagePool.getId()));
diff --git a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java
index 1c8fae171b67..510fea5c6c75 100644
--- a/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java
+++ b/plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java
@@ -176,8 +176,7 @@ public void deleteCloudStackVolume(CloudStackVolume cloudstackVolume) {
* Clones a file inside the FlexVolume using ONTAP's file clone API.
*
* The source is taken from {@code file.path} and the destination from
- * {@code destinationPath}, both relative to the root of the FlexVolume backing the pool.
- * When {@code snapshotName} is set, the source is read from that FlexVolume snapshot.
+ * {@code destinationPath}, both relative to the root of the FlexVolume backing the pool.
*/
@Override
public CloudStackVolume cloneCloudStackVolume(CloudStackVolume cloudstackVolume) {
@@ -203,7 +202,7 @@ public CloudStackVolume cloneCloudStackVolume(CloudStackVolume cloudstackVolume)
logger.info("cloneCloudStackVolume: Cloning file [{}] to [{}] in FlexVol [{}] from snapshot [{}]",
sourcePath, destinationPath, flexVolName, snapshotName);
try {
- FileCloneRequest request = new FileCloneRequest(flexVolUuid, flexVolName, sourcePath, destinationPath, snapshotName);
+ FileCloneRequest request = new FileCloneRequest(flexVolUuid, flexVolName, sourcePath, destinationPath);
JobResponse jobResponse = nasFeignClient.cloneFile(getAuthHeader(), request);
pollJobIfPresent(jobResponse, "clone file [" + sourcePath + "] to [" + destinationPath + "]");
diff --git a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriverTest.java b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriverTest.java
index 12e5ff3faced..97642c5997e8 100644
--- a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriverTest.java
+++ b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriverTest.java
@@ -1108,7 +1108,7 @@ void testCreateAsync_VolumeClonedFromSnapshot_NfsSuccess() {
ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(CloudStackVolume.class);
verify(nasStrategy).cloneCloudStackVolume(requestCaptor.capture());
CloudStackVolume request = requestCaptor.getValue();
- assertEquals("source-file-uuid", request.getFile().getPath());
+ assertEquals("./.snapshot/snap_cs200/source-file-uuid", request.getFile().getPath());
assertEquals("new-volume-uuid", request.getDestinationPath());
assertEquals("snap_cs200", request.getSnapshotName());
assertEquals("1", request.getDatastoreId());
@@ -3177,7 +3177,8 @@ void testCopyAsync_NfsTemporarySnapshotCopy_SetsFilePath() {
ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(CloudStackVolume.class);
verify(nasStrategy).cloneCloudStackVolume(requestCaptor.capture());
- assertEquals("source-file-uuid", requestCaptor.getValue().getFile().getPath());
+ assertEquals("./.snapshot/snap_cs200/source-file-uuid",
+ requestCaptor.getValue().getFile().getPath());
assertEquals("tmp-volume-uuid", requestCaptor.getValue().getDestinationPath());
assertEquals("snap_cs200", requestCaptor.getValue().getSnapshotName());
diff --git a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java
index 199a847e2136..bab14d4bf8dc 100755
--- a/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java
+++ b/plugins/storage/volume/ontap/src/test/java/org/apache/cloudstack/storage/service/UnifiedNASStrategyTest.java
@@ -1127,7 +1127,7 @@ public void testCloneCloudStackVolume_Success() {
}
@Test
- public void testCloneCloudStackVolume_SnapshotSource_SendsSnapshotName() {
+ public void testCloneCloudStackVolume_SnapshotSource_UsesSnapshotSourcePath() {
VolumeObject volumeObject = mock(VolumeObject.class);
VolumeVO volumeVO = mock(VolumeVO.class);
when(volumeObject.getId()).thenReturn(100L);
@@ -1140,7 +1140,7 @@ public void testCloneCloudStackVolume_SnapshotSource_SendsSnapshotName() {
when(storagePoolDetailsDao.listDetailsKeyPairs(1L)).thenReturn(details);
FileInfo source = new FileInfo();
- source.setPath("source-file-uuid");
+ source.setPath("./.snapshot/snap_cs200/source-file-uuid");
CloudStackVolume request = new CloudStackVolume();
request.setDatastoreId("1");
request.setVolumeInfo(volumeObject);
@@ -1156,10 +1156,9 @@ public void testCloneCloudStackVolume_SnapshotSource_SendsSnapshotName() {
assertEquals("snap_cs200", result.getSnapshotName());
ArgumentCaptor captor = ArgumentCaptor.forClass(FileCloneRequest.class);
verify(nasFeignClient).cloneFile(anyString(), captor.capture());
- assertEquals("source-file-uuid", captor.getValue().getSourcePath());
+ assertEquals("./.snapshot/snap_cs200/source-file-uuid", captor.getValue().getSourcePath());
assertEquals("new-volume-uuid", captor.getValue().getDestinationPath());
- assertNotNull(captor.getValue().getSnapshot());
- assertEquals("snap_cs200", captor.getValue().getSnapshot().getName());
+ assertNull(captor.getValue().getSnapshot());
}
@Test