package org.ovirt.engine.core.bll.snapshots;
import java.util.ArrayList;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.InternalCommandAttribute;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.storage.disk.image.BaseImagesCommand;
import org.ovirt.engine.core.bll.storage.domain.PostDeleteActionHandler;
import org.ovirt.engine.core.bll.storage.utils.BlockStorageDiscardFunctionalityHelper;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.RestoreFromSnapshotParameters;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.asynctasks.AsyncTaskType;
import org.ovirt.engine.core.common.businessentities.Snapshot.SnapshotType;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.errors.EngineException;
import org.ovirt.engine.core.common.errors.EngineFault;
import org.ovirt.engine.core.common.vdscommands.DestroyImageVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.DiskImageDao;
import org.ovirt.engine.core.dao.ImageDao;
import org.ovirt.engine.core.dao.StorageDomainDao;
/**
* This command responsible to make snapshot of some Vm mapped to some drive be
* active snapshot. All children snapshots and other snapshot mapped to same
* drive will be removed.
*/
@InternalCommandAttribute
public class RestoreFromSnapshotCommand<T extends RestoreFromSnapshotParameters> extends BaseImagesCommand<T> {
@Inject
private BlockStorageDiscardFunctionalityHelper discardHelper;
@Inject
private PostDeleteActionHandler postDeleteActionHandler;
@Inject
private ImageDao imageDao;
@Inject
private DiskImageDao diskImageDao;
@Inject
private StorageDomainDao storageDomainDao;
private final ArrayList<Guid> _imagesToDelete = new ArrayList<>();
public RestoreFromSnapshotCommand(T parameters, CommandContext cmdContext) {
super(parameters, cmdContext);
}
@Override
protected void executeCommand() {
if (removeImages()) {
if (getParameters().getSnapshot().getType() != SnapshotType.REGULAR) {
getImage().setActive(true);
imageDao.update(getImage().getImage());
}
discardHelper.logIfDisksWithIllegalPassDiscardExist(getVmId());
setSucceeded(true);
}
}
private boolean removeImages() {
Guid imageToRemoveId = findImageForSameDrive(getParameters().getRemovedSnapshotId());
switch (getParameters().getSnapshot().getType()) {
case REGULAR:
removeOtherImageAndParents(imageToRemoveId, getDiskImage().getParentId());
break;
case PREVIEW:
case STATELESS:
if (imageToRemoveId != null) {
removeSnapshot(diskImageDao.get(imageToRemoveId));
}
break;
}
return performImageVdsmOperation();
}
@Override
protected AsyncTaskType getTaskType() {
return AsyncTaskType.deleteVolume;
}
@Override
protected void removeSnapshot(DiskImage snapshot) {
super.removeSnapshot(snapshot);
_imagesToDelete.add(_imagesToDelete.size(), snapshot.getImageId());
}
private void removeOtherImageAndParents(Guid imageId, Guid lastParent) {
DiskImage image = diskImageDao.getSnapshotById(imageId);
// store other mapped image's parent Id
Guid currentParent = image.getParentId();
// Remove other mapped image from Irs and db
removeSnapshot(image);
while (!lastParent.equals(currentParent)) {
image = diskImageDao.getSnapshotById(currentParent);
// store current image's parent Id
currentParent = image.getParentId();
removeSnapshot(image);
}
}
@Override
protected boolean performImageVdsmOperation() {
VDSReturnValue vdsReturnValue = null;
try {
Guid storagePoolId = getDiskImage().getStoragePoolId() != null ? getDiskImage().getStoragePoolId()
: Guid.Empty;
Guid storageDomainId =
getDiskImage().getStorageIds() != null && !getDiskImage().getStorageIds().isEmpty() ? getDiskImage().getStorageIds()
.get(0)
: Guid.Empty;
Guid imageGroupId = getDiskImage().getId() != null ? getDiskImage().getId() : Guid.Empty;
Guid taskId = persistAsyncTaskPlaceHolder(VdcActionType.RestoreAllSnapshots);
vdsReturnValue = runVdsCommand(VDSCommandType.DestroyImage,
postDeleteActionHandler.fixParameters(
new DestroyImageVDSCommandParameters(storagePoolId, storageDomainId, imageGroupId,
_imagesToDelete, getDiskImage().isWipeAfterDelete(),
storageDomainDao.get(storageDomainId).isDiscardAfterDelete(), true)));
if (vdsReturnValue.getSucceeded()) {
getReturnValue().getInternalVdsmTaskIdList().add(
createTask(taskId,
vdsReturnValue.getCreationInfo(),
VdcActionType.RestoreAllSnapshots,
VdcObjectType.Storage,
storageDomainId));
}
}
// Don't throw an exception when cannot destroy image in the VDSM.
catch (EngineException e) {
// Set fault for parent command RestoreAllSnapshotCommand to use, if decided to fail the command.
getReturnValue().setFault(new EngineFault(e, e.getVdsError().getCode()));
log.info("Image '{}' not exist in Irs", getDiskImage().getImageId());
}
return vdsReturnValue != null ? vdsReturnValue.getSucceeded() : false;
}
}