Create snapshot from VM snapshot without memory for NFS/Local storage (#8117)

This commit is contained in:
slavkap 2023-10-26 09:46:14 +03:00 committed by GitHub
parent ae724b9d4c
commit 6ae3b73ca2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 22 deletions

View File

@ -26,7 +26,7 @@ import java.util.Date;
public interface Snapshot extends ControlledEntity, Identity, InternalIdentity, StateObject<Snapshot.State> { public interface Snapshot extends ControlledEntity, Identity, InternalIdentity, StateObject<Snapshot.State> {
public enum Type { 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; private int max = 8;
public void setMax(int max) { public void setMax(int max) {

View File

@ -66,10 +66,13 @@ import com.cloud.configuration.Config;
import com.cloud.host.Host; import com.cloud.host.Host;
import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.DataStoreRole; 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.StorageManager;
import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.VolumeVO; import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeDao;
import com.cloud.utils.NumbersUtil; import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.DB; import com.cloud.utils.db.DB;
@ -97,6 +100,8 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
@Inject @Inject
StorageManager storageManager; StorageManager storageManager;
@Inject
SnapshotDao snapshotDao;
@Override @Override
public StrategyPriority canHandle(DataObject srcData, DataObject destData) { public StrategyPriority canHandle(DataObject srcData, DataObject destData) {
@ -583,8 +588,8 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
fullSnapshot = snapshotFullBackup; fullSnapshot = snapshotFullBackup;
} }
Map<String, String> options = new HashMap<String, String>(); 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); boolean encryptionRequired = anyVolumeRequiresEncryption(srcData, destData);
Answer answer = null; 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 @Override
public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) { public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
CopyCommandResult result = new CopyCommandResult(null, null); CopyCommandResult result = new CopyCommandResult(null, null);

View File

@ -1014,9 +1014,9 @@ public class KVMStorageProcessor implements StorageProcessor {
command.add("-b", isCreatedFromVmSnapshot ? snapshotDisk.getPath() : snapshot.getPath()); command.add("-b", isCreatedFromVmSnapshot ? snapshotDisk.getPath() : snapshot.getPath());
command.add(NAME_OPTION, snapshotName); command.add(NAME_OPTION, snapshotName);
command.add("-p", snapshotDestPath); command.add("-p", snapshotDestPath);
if (isCreatedFromVmSnapshot) {
descName = UUID.randomUUID().toString(); descName = UUID.randomUUID().toString();
}
command.add("-t", descName); command.add("-t", descName);
final String result = command.execute(); final String result = command.execute();
if (result != null) { if (result != null) {
@ -1041,18 +1041,7 @@ public class KVMStorageProcessor implements StorageProcessor {
if (isCreatedFromVmSnapshot) { if (isCreatedFromVmSnapshot) {
s_logger.debug("Ignoring removal of vm snapshot on primary as this snapshot is created from vm snapshot"); s_logger.debug("Ignoring removal of vm snapshot on primary as this snapshot is created from vm snapshot");
} else if (primaryPool.getType() != StoragePoolType.RBD) { } else if (primaryPool.getType() != StoragePoolType.RBD) {
String snapshotPath = snapshot.getPath(); deleteSnapshotOnPrimary(cmd, snapshot, primaryPool);
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()));
}
} }
try { 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 protected synchronized void attachOrDetachISO(final Connect conn, final String vmName, String isoPath, final boolean isAttach, Map<String, String> params) throws
LibvirtException, InternalErrorException { LibvirtException, InternalErrorException {
DiskDef iso = new DiskDef(); DiskDef iso = new DiskDef();

View File

@ -109,6 +109,7 @@ import com.cloud.storage.SnapshotScheduleVO;
import com.cloud.storage.SnapshotVO; import com.cloud.storage.SnapshotVO;
import com.cloud.storage.Storage; import com.cloud.storage.Storage;
import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageManager; import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateVO;
@ -150,8 +151,10 @@ import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotDetailsVO;
import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao; import com.cloud.vm.snapshot.dao.VMSnapshotDao;
import com.cloud.vm.snapshot.dao.VMSnapshotDetailsDao;
@Component @Component
public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements SnapshotManager, SnapshotApiService, Configurable { public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements SnapshotManager, SnapshotApiService, Configurable {
@ -221,6 +224,10 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
protected SnapshotHelper snapshotHelper; protected SnapshotHelper snapshotHelper;
@Inject @Inject
DataCenterDao dataCenterDao; DataCenterDao dataCenterDao;
@Inject
VMSnapshotDetailsDao vmSnapshotDetailsDao;
@Inject
SnapshotDataFactory snapshotDataFactory;
private int _totalRetries; private int _totalRetries;
private int _pauseInterval; private int _pauseInterval;
@ -497,12 +504,12 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
SnapshotInfo snapshotInfo = this.snapshotFactory.getSnapshot(snapshotId, store); SnapshotInfo snapshotInfo = this.snapshotFactory.getSnapshot(snapshotId, store);
snapshotInfo = (SnapshotInfo)store.create(snapshotInfo); snapshotInfo = (SnapshotInfo)store.create(snapshotInfo);
SnapshotDataStoreVO snapshotOnPrimaryStore = this._snapshotStoreDao.findByStoreSnapshot(store.getRole(), store.getId(), snapshot.getId()); SnapshotDataStoreVO snapshotOnPrimaryStore = this._snapshotStoreDao.findByStoreSnapshot(store.getRole(), store.getId(), snapshot.getId());
snapshotOnPrimaryStore.setState(ObjectInDataStoreStateMachine.State.Ready);
snapshotOnPrimaryStore.setInstallPath(vmSnapshot.getName()); StoragePoolVO storagePool = _storagePoolDao.findById(store.getId());
_snapshotStoreDao.update(snapshotOnPrimaryStore.getId(), snapshotOnPrimaryStore); updateSnapshotInfo(volumeId, vmSnapshotId, vmSnapshot, snapshot, snapshotOnPrimaryStore, storagePool);
snapshot.setState(Snapshot.State.CreatedOnPrimary); snapshot.setState(Snapshot.State.CreatedOnPrimary);
_snapshotDao.update(snapshot.getId(), snapshot); _snapshotDao.update(snapshot.getId(), snapshot);
snapshotInfo = this.snapshotFactory.getSnapshot(snapshotId, store); snapshotInfo = this.snapshotFactory.getSnapshot(snapshotId, store);
Long snapshotOwnerId = vm.getAccountId(); Long snapshotOwnerId = vm.getAccountId();
@ -519,10 +526,35 @@ public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implement
_resourceLimitMgr.decrementResourceCount(snapshotOwnerId, ResourceType.snapshot); _resourceLimitMgr.decrementResourceCount(snapshotOwnerId, ResourceType.snapshot);
_resourceLimitMgr.decrementResourceCount(snapshotOwnerId, ResourceType.secondary_storage, new Long(volume.getSize())); _resourceLimitMgr.decrementResourceCount(snapshotOwnerId, ResourceType.secondary_storage, new Long(volume.getSize()));
throw new CloudRuntimeException("Failed to backup snapshot from vm snapshot", e); throw new CloudRuntimeException("Failed to backup snapshot from vm snapshot", e);
} finally {
if (snapshotOnPrimaryStore != null) {
_snapshotStoreDao.remove(snapshotOnPrimaryStore.getId());
}
} }
return snapshotInfo; 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 @Override
public SnapshotVO getParentSnapshot(VolumeInfo volume) { public SnapshotVO getParentSnapshot(VolumeInfo volume) {
long preId = _snapshotDao.getLastSnapshot(volume.getId(), DataStoreRole.Primary); long preId = _snapshotDao.getLastSnapshot(volume.getId(), DataStoreRole.Primary);