This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch 4.18
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.18 by this push:
new 6ae3b73ca2d Create snapshot from VM snapshot without memory for
NFS/Local storage (#8117)
6ae3b73ca2d is described below
commit 6ae3b73ca2d7bf12acdd03333749b7a0a8cc94ee
Author: slavkap <[email protected]>
AuthorDate: Thu Oct 26 09:46:14 2023 +0300
Create snapshot from VM snapshot without memory for NFS/Local storage
(#8117)
---
api/src/main/java/com/cloud/storage/Snapshot.java | 2 +-
.../storage/motion/AncientDataMotionStrategy.java | 18 ++++++++--
.../kvm/storage/KVMStorageProcessor.java | 40 ++++++++++++++--------
.../storage/snapshot/SnapshotManagerImpl.java | 40 +++++++++++++++++++---
4 files changed, 78 insertions(+), 22 deletions(-)
diff --git a/api/src/main/java/com/cloud/storage/Snapshot.java
b/api/src/main/java/com/cloud/storage/Snapshot.java
index 5b25843f48b..fc919e442b2 100644
--- a/api/src/main/java/com/cloud/storage/Snapshot.java
+++ b/api/src/main/java/com/cloud/storage/Snapshot.java
@@ -26,7 +26,7 @@ import java.util.Date;
public interface Snapshot extends ControlledEntity, Identity,
InternalIdentity, StateObject<Snapshot.State> {
public enum Type {
- MANUAL, RECURRING, TEMPLATE, HOURLY, DAILY, WEEKLY, MONTHLY, GROUP;
+ MANUAL, RECURRING, TEMPLATE, HOURLY, DAILY, WEEKLY, MONTHLY, GROUP,
FROM_GROUP;
private int max = 8;
public void setMax(int max) {
diff --git
a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index 1d463cad7ea..e450addb261 100644
---
a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++
b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -66,10 +66,13 @@ import com.cloud.configuration.Config;
import com.cloud.host.Host;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.Snapshot.Type;
+import com.cloud.storage.SnapshotVO;
import com.cloud.storage.StorageManager;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.DB;
@@ -97,6 +100,8 @@ public class AncientDataMotionStrategy implements
DataMotionStrategy {
@Inject
StorageManager storageManager;
+ @Inject
+ SnapshotDao snapshotDao;
@Override
public StrategyPriority canHandle(DataObject srcData, DataObject destData)
{
@@ -583,8 +588,8 @@ public class AncientDataMotionStrategy implements
DataMotionStrategy {
fullSnapshot = snapshotFullBackup;
}
Map<String, String> options = new HashMap<String, String>();
- options.put("fullSnapshot", fullSnapshot.toString());
- options.put(SnapshotInfo.BackupSnapshotAfterTakingSnapshot.key(),
String.valueOf(SnapshotInfo.BackupSnapshotAfterTakingSnapshot.value()));
+
+ addCommandOptions(snapshotInfo, fullSnapshot, options);
boolean encryptionRequired = anyVolumeRequiresEncryption(srcData,
destData);
Answer answer = null;
@@ -631,6 +636,15 @@ public class AncientDataMotionStrategy implements
DataMotionStrategy {
}
+ private void addCommandOptions(SnapshotInfo snapshotInfo, Boolean
fullSnapshot, Map<String, String> options) {
+ SnapshotVO snap = snapshotDao.findById(snapshotInfo.getSnapshotId());
+ if (snap != null &&
Type.FROM_GROUP.name().equals(snap.getTypeDescription())) {
+ options.put("typeDescription", snap.getTypeDescription());
+ }
+ options.put("fullSnapshot", fullSnapshot.toString());
+ options.put(SnapshotInfo.BackupSnapshotAfterTakingSnapshot.key(),
String.valueOf(SnapshotInfo.BackupSnapshotAfterTakingSnapshot.value()));
+ }
+
@Override
public void copyAsync(Map<VolumeInfo, DataStore> volumeMap,
VirtualMachineTO vmTo, Host srcHost, Host destHost,
AsyncCompletionCallback<CopyCommandResult> callback) {
CopyCommandResult result = new CopyCommandResult(null, null);
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
index ae0fa637bf0..f7ec09ca50f 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
@@ -1014,9 +1014,9 @@ public class KVMStorageProcessor implements
StorageProcessor {
command.add("-b", isCreatedFromVmSnapshot ?
snapshotDisk.getPath() : snapshot.getPath());
command.add(NAME_OPTION, snapshotName);
command.add("-p", snapshotDestPath);
- if (isCreatedFromVmSnapshot) {
- descName = UUID.randomUUID().toString();
- }
+
+ descName = UUID.randomUUID().toString();
+
command.add("-t", descName);
final String result = command.execute();
if (result != null) {
@@ -1041,18 +1041,7 @@ public class KVMStorageProcessor implements
StorageProcessor {
if (isCreatedFromVmSnapshot) {
s_logger.debug("Ignoring removal of vm snapshot on primary as
this snapshot is created from vm snapshot");
} else if (primaryPool.getType() != StoragePoolType.RBD) {
- String snapshotPath = snapshot.getPath();
- String backupSnapshotAfterTakingSnapshot = cmd.getOptions() ==
null ? null :
cmd.getOptions().get(SnapshotInfo.BackupSnapshotAfterTakingSnapshot.key());
-
- if (backupSnapshotAfterTakingSnapshot == null ||
BooleanUtils.toBoolean(backupSnapshotAfterTakingSnapshot)) {
- try {
- Files.deleteIfExists(Paths.get(snapshotPath));
- } catch (IOException ex) {
- s_logger.error(String.format("Failed to delete
snapshot [%s] on primary storage [%s].", snapshotPath, primaryPool.getUuid()),
ex);
- }
- } else {
- s_logger.debug(String.format("This backup is temporary,
not deleting snapshot [%s] on primary storage [%s]", snapshotPath,
primaryPool.getUuid()));
- }
+ deleteSnapshotOnPrimary(cmd, snapshot, primaryPool);
}
try {
@@ -1064,6 +1053,27 @@ public class KVMStorageProcessor implements
StorageProcessor {
}
}
}
+
+ private void deleteSnapshotOnPrimary(final CopyCommand cmd, final
SnapshotObjectTO snapshot,
+ KVMStoragePool primaryPool) {
+ String snapshotPath = snapshot.getPath();
+ String backupSnapshotAfterTakingSnapshot = null;
+ boolean deleteSnapshotOnPrimary = true;
+ if (cmd.getOptions() != null) {
+ backupSnapshotAfterTakingSnapshot =
cmd.getOptions().get(SnapshotInfo.BackupSnapshotAfterTakingSnapshot.key());
+ deleteSnapshotOnPrimary = cmd.getOptions().get("typeDescription")
== null;
+ }
+
+ if ((backupSnapshotAfterTakingSnapshot == null ||
BooleanUtils.toBoolean(backupSnapshotAfterTakingSnapshot)) &&
deleteSnapshotOnPrimary) {
+ try {
+ Files.deleteIfExists(Paths.get(snapshotPath));
+ } catch (IOException ex) {
+ s_logger.error(String.format("Failed to delete snapshot [%s]
on primary storage [%s].", snapshotPath, primaryPool.getUuid()), ex);
+ }
+ } else {
+ s_logger.debug(String.format("This backup is temporary, not
deleting snapshot [%s] on primary storage [%s]", snapshotPath,
primaryPool.getUuid()));
+ }
+ }
protected synchronized void attachOrDetachISO(final Connect conn, final
String vmName, String isoPath, final boolean isAttach, Map<String, String>
params) throws
LibvirtException, InternalErrorException {
DiskDef iso = new DiskDef();
diff --git
a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java
b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java
index bd8811b2a15..aeb095b6ecf 100755
--- a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -109,6 +109,7 @@ import com.cloud.storage.SnapshotScheduleVO;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateVO;
@@ -150,8 +151,10 @@ import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.snapshot.VMSnapshot;
+import com.cloud.vm.snapshot.VMSnapshotDetailsVO;
import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+import com.cloud.vm.snapshot.dao.VMSnapshotDetailsDao;
@Component
public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase
implements SnapshotManager, SnapshotApiService, Configurable {
@@ -221,6 +224,10 @@ public class SnapshotManagerImpl extends
MutualExclusiveIdsManagerBase implement
protected SnapshotHelper snapshotHelper;
@Inject
DataCenterDao dataCenterDao;
+ @Inject
+ VMSnapshotDetailsDao vmSnapshotDetailsDao;
+ @Inject
+ SnapshotDataFactory snapshotDataFactory;
private int _totalRetries;
private int _pauseInterval;
@@ -497,12 +504,12 @@ public class SnapshotManagerImpl extends
MutualExclusiveIdsManagerBase implement
SnapshotInfo snapshotInfo =
this.snapshotFactory.getSnapshot(snapshotId, store);
snapshotInfo = (SnapshotInfo)store.create(snapshotInfo);
SnapshotDataStoreVO snapshotOnPrimaryStore =
this._snapshotStoreDao.findByStoreSnapshot(store.getRole(), store.getId(),
snapshot.getId());
-
snapshotOnPrimaryStore.setState(ObjectInDataStoreStateMachine.State.Ready);
- snapshotOnPrimaryStore.setInstallPath(vmSnapshot.getName());
- _snapshotStoreDao.update(snapshotOnPrimaryStore.getId(),
snapshotOnPrimaryStore);
+
+ StoragePoolVO storagePool = _storagePoolDao.findById(store.getId());
+ updateSnapshotInfo(volumeId, vmSnapshotId, vmSnapshot, snapshot,
snapshotOnPrimaryStore, storagePool);
+
snapshot.setState(Snapshot.State.CreatedOnPrimary);
_snapshotDao.update(snapshot.getId(), snapshot);
-
snapshotInfo = this.snapshotFactory.getSnapshot(snapshotId, store);
Long snapshotOwnerId = vm.getAccountId();
@@ -519,10 +526,35 @@ public class SnapshotManagerImpl extends
MutualExclusiveIdsManagerBase implement
_resourceLimitMgr.decrementResourceCount(snapshotOwnerId,
ResourceType.snapshot);
_resourceLimitMgr.decrementResourceCount(snapshotOwnerId,
ResourceType.secondary_storage, new Long(volume.getSize()));
throw new CloudRuntimeException("Failed to backup snapshot from vm
snapshot", e);
+ } finally {
+ if (snapshotOnPrimaryStore != null) {
+ _snapshotStoreDao.remove(snapshotOnPrimaryStore.getId());
+ }
}
return snapshotInfo;
}
+ private void updateSnapshotInfo(Long volumeId, Long vmSnapshotId,
VMSnapshotVO vmSnapshot, SnapshotVO snapshot,
+ SnapshotDataStoreVO snapshotOnPrimaryStore, StoragePoolVO
storagePool) {
+ if ((storagePool.getPoolType() == StoragePoolType.NetworkFilesystem ||
storagePool.getPoolType() == StoragePoolType.Filesystem) &&
vmSnapshot.getType() == VMSnapshot.Type.Disk) {
+ List<VMSnapshotDetailsVO> vmSnapshotDetails =
vmSnapshotDetailsDao.findDetails(vmSnapshotId, "kvmStorageSnapshot");
+ for (VMSnapshotDetailsVO vmSnapshotDetailsVO : vmSnapshotDetails) {
+ SnapshotInfo sInfo =
snapshotDataFactory.getSnapshot(Long.parseLong(vmSnapshotDetailsVO.getValue()),
DataStoreRole.Primary);
+ if (sInfo.getVolumeId() == volumeId) {
+
snapshotOnPrimaryStore.setState(ObjectInDataStoreStateMachine.State.Ready);
+ snapshotOnPrimaryStore.setInstallPath(sInfo.getPath());
+ _snapshotStoreDao.update(snapshotOnPrimaryStore.getId(),
snapshotOnPrimaryStore);
+ snapshot.setTypeDescription(Type.FROM_GROUP.name());
+ snapshot.setSnapshotType((short)Type.FROM_GROUP.ordinal());
+ }
+ }
+ } else {
+
snapshotOnPrimaryStore.setState(ObjectInDataStoreStateMachine.State.Ready);
+ snapshotOnPrimaryStore.setInstallPath(vmSnapshot.getName());
+ _snapshotStoreDao.update(snapshotOnPrimaryStore.getId(),
snapshotOnPrimaryStore);
+ }
+ }
+
@Override
public SnapshotVO getParentSnapshot(VolumeInfo volume) {
long preId = _snapshotDao.getLastSnapshot(volume.getId(),
DataStoreRole.Primary);