mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Create snapshot from VM snapshot without memory for NFS/Local storage (#8117)
This commit is contained in:
parent
ae724b9d4c
commit
6ae3b73ca2
@ -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) {
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user