Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f42552b
CSTACKEX-18_2: NFS3 snapshot changes
rajiv-jain-netapp Feb 19, 2026
8894248
CSTACK-18_2: fixing junit dependent changes
rajiv-jain-netapp Feb 19, 2026
3f0019a
STACK-18_2: fixes
rajiv-jain-netapp Feb 20, 2026
9b79f46
CSTACKEX-18_2: adding VM snapshot logic
rajiv-jain-netapp Feb 20, 2026
7a0d61e
CSTACKEX-18_2: fix junit issues
rajiv-jain-netapp Feb 20, 2026
7c3419e
CSTACKEX-18_2: fixes for vm snapshot workflow
rajiv-jain-netapp Feb 21, 2026
d2b6a27
CSTACKEX-18_2: fixing the behaviour for the VM level snapshot when qu…
rajiv-jain-netapp Feb 21, 2026
c5d5428
CSTACKEX-18_2: incorporating the review comments.
rajiv-jain-netapp Feb 24, 2026
3f18c11
CSTACKEX-18_2: transient fixes post incorporating the comments
rajiv-jain-netapp Feb 24, 2026
723561b
CSTACKEX-18_2: Incorporate review comments
rajiv-jain-netapp Feb 24, 2026
09968db
CSTACKEX-18_2: quiecing VM would be done based on user input for VM l…
rajiv-jain-netapp Feb 25, 2026
0a1a9c4
CSTACKEX-18_2: ONTAP plugin can not handle memory snapshot with stora…
rajiv-jain-netapp Feb 26, 2026
49df4c3
CSTACKEX-18_2: junit fix
rajiv-jain-netapp Feb 26, 2026
776b9a2
CSTACKEX-18_2: junit fix2
rajiv-jain-netapp Feb 26, 2026
c04e223
CSTACKEX-18_2: ensure that ONTAP volume related calls are served by c…
rajiv-jain-netapp Feb 26, 2026
186e59b
CSTACKEX-18_2: using flexvolume snapshot to get snapshot workflows fo…
rajiv-jain-netapp Feb 26, 2026
1020a2c
CSTACKEX-18_2: using flexvolume snapshot even for CS volume snapshot …
rajiv-jain-netapp Feb 27, 2026
672d7a4
CSTACKEX-18_2: we are taking snapshot for volume with flexvolume snap…
rajiv-jain-netapp Feb 28, 2026
9c63c61
CSTACKEX-18_2: junit fixes with recent refactor
rajiv-jain-netapp Feb 28, 2026
79730ed
CSTACKEX-18_2: fixing snapshot delete condition fix
rajiv-jain-netapp Mar 2, 2026
ae96e9b
CSTACKEX-18_2: delete snapshot should be done over plugin path not on…
rajiv-jain-netapp Mar 2, 2026
1b0bba9
CSTACKEX-18_2: plugin has to consider VM for snapshot in running and …
rajiv-jain-netapp Mar 2, 2026
7780a93
CSTACKEX-18_2: revert snapshot fixes for API not found
rajiv-jain-netapp Mar 2, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
protected SearchBuilder<SnapshotDataStoreVO> searchFilteringStoreIdEqStateEqStoreRoleEqIdEqUpdateCountEqSnapshotIdEqVolumeIdEq;
private SearchBuilder<SnapshotDataStoreVO> stateSearch;
private SearchBuilder<SnapshotDataStoreVO> idStateNeqSearch;
private SearchBuilder<SnapshotDataStoreVO> idStateNinSearch;
protected SearchBuilder<SnapshotVO> snapshotVOSearch;
private SearchBuilder<SnapshotDataStoreVO> snapshotCreatedSearch;
private SearchBuilder<SnapshotDataStoreVO> dataStoreAndInstallPathSearch;
Expand Down Expand Up @@ -151,6 +152,11 @@ public boolean configure(String name, Map<String, Object> params) throws Configu
idStateNeqSearch.and(STATE, idStateNeqSearch.entity().getState(), SearchCriteria.Op.NEQ);
idStateNeqSearch.done();

idStateNinSearch = createSearchBuilder();
idStateNinSearch.and(SNAPSHOT_ID, idStateNinSearch.entity().getSnapshotId(), SearchCriteria.Op.EQ);
idStateNinSearch.and(STATE, idStateNinSearch.entity().getState(), SearchCriteria.Op.NIN);
idStateNinSearch.done();

snapshotVOSearch = snapshotDao.createSearchBuilder();
snapshotVOSearch.and(VOLUME_ID, snapshotVOSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
snapshotVOSearch.done();
Expand Down Expand Up @@ -488,7 +494,7 @@ public List<SnapshotDataStoreVO> findBySnapshotIdWithNonDestroyedState(long snap

@Override
public List<SnapshotDataStoreVO> findBySnapshotIdAndNotInDestroyedHiddenState(long snapshotId) {
SearchCriteria<SnapshotDataStoreVO> sc = idStateNeqSearch.create();
SearchCriteria<SnapshotDataStoreVO> sc = idStateNinSearch.create();
sc.setParameters(SNAPSHOT_ID, snapshotId);
sc.setParameters(STATE, State.Destroyed.name(), State.Hidden.name());
return listBy(sc);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ public class KvmFileBasedStorageVmSnapshotStrategy extends StorageVMSnapshotStra

private static final List<Storage.StoragePoolType> supportedStoragePoolTypes = List.of(Storage.StoragePoolType.Filesystem, Storage.StoragePoolType.NetworkFilesystem, Storage.StoragePoolType.SharedMountPoint);

private static final String ONTAP_PROVIDER_NAME = "NetApp ONTAP";

@Inject
protected SnapshotDataStoreDao snapshotDataStoreDao;

Expand Down Expand Up @@ -325,6 +327,11 @@ public StrategyPriority canHandle(Long vmId, Long rootPoolId, boolean snapshotMe
List<VolumeVO> volumes = volumeDao.findByInstance(vmId);
for (VolumeVO volume : volumes) {
StoragePoolVO storagePoolVO = storagePool.findById(volume.getPoolId());
if (storagePoolVO.isManaged() && ONTAP_PROVIDER_NAME.equals(storagePoolVO.getStorageProviderName())) {
logger.debug(String.format("%s as the VM has a volume on ONTAP managed storage pool [%s]. " +
"ONTAP managed storage has its own dedicated VM snapshot strategy.", cantHandleLog, storagePoolVO.getName()));
return StrategyPriority.CANT_HANDLE;
}
if (!supportedStoragePoolTypes.contains(storagePoolVO.getPoolType())) {
logger.debug(String.format("%s as the VM has a volume that is in a storage with unsupported type [%s].", cantHandleLog, storagePoolVO.getPoolType()));
return StrategyPriority.CANT_HANDLE;
Expand Down Expand Up @@ -503,8 +510,9 @@ protected VMSnapshot takeVmSnapshotInternal(VMSnapshot vmSnapshot, Map<VolumeInf
return processCreateVmSnapshotAnswer(vmSnapshot, volumeInfoToSnapshotObjectMap, createDiskOnlyVMSnapshotAnswer, userVm, vmSnapshotVO, virtualSize, parentSnapshotVo);
}

logger.error("Disk-only VM snapshot for VM [{}] failed{}.", userVm.getUuid(), answer != null ? " due to" + answer.getDetails() : "");
throw new CloudRuntimeException(String.format("Disk-only VM snapshot for VM [%s] failed.", userVm.getUuid()));
String details = answer != null ? answer.getDetails() : String.format("No answer received from host [%s]. The host may be unreachable.", hostId);

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?

Copy link
Author

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.

logger.error("Disk-only VM snapshot for VM [{}] failed due to: {}.", userVm.getUuid(), details);
throw new CloudRuntimeException(String.format("Disk-only VM snapshot for VM [%s] failed due to: %s.", userVm.getUuid(), details));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The 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();
}
Expand Down
10 changes: 10 additions & 0 deletions plugins/storage/volume/ontap/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@
<artifactId>cloud-engine-storage-volume</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-storage-snapshot</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
Expand Down
Loading
Loading