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);

Reply via email to