package org.ovirt.engine.core.bll.storage.disk.cinder;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.ConcurrentChildCommandsExecutionCallback;
import org.ovirt.engine.core.bll.InternalCommandAttribute;
import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute;
import org.ovirt.engine.core.bll.VmCommand;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.tasks.CommandCoordinatorUtil;
import org.ovirt.engine.core.bll.tasks.interfaces.CommandCallback;
import org.ovirt.engine.core.common.action.ImagesContainterParametersBase;
import org.ovirt.engine.core.common.action.RemoveCinderDiskParameters;
import org.ovirt.engine.core.common.action.RemoveCinderDiskVolumeParameters;
import org.ovirt.engine.core.common.action.RestoreAllCinderSnapshotsParameters;
import org.ovirt.engine.core.common.action.VdcActionParametersBase.EndProcedure;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.businessentities.Snapshot;
import org.ovirt.engine.core.common.businessentities.storage.CinderDisk;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
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.ImageStorageDomainMapDao;
import org.ovirt.engine.core.dao.SnapshotDao;
@InternalCommandAttribute
@NonTransactiveCommandAttribute
public class RestoreAllCinderSnapshotsCommand<T extends RestoreAllCinderSnapshotsParameters> extends VmCommand<T> {
@Inject
private DiskImageDao diskImageDao;
@Inject
private ImageStorageDomainMapDao imageStorageDomainMapDao;
@Inject
private ImageDao imageDao;
@Inject
private SnapshotDao snapshotDao;
public RestoreAllCinderSnapshotsCommand(T parameters, CommandContext cmdContext) {
super(parameters, cmdContext);
}
@Override
protected void executeVmCommand() {
for (CinderDisk cinderDisk : getParameters().getCinderDisksToRestore()) {
ImagesContainterParametersBase params = getRestoreFromSnapshotParams(cinderDisk);
restoreCinderDisk(cinderDisk, params);
// In case we want to undo the previewed snapshot.
if (getParameters().getSnapshot().getType() == Snapshot.SnapshotType.STATELESS) {
Guid activeSnapshotId = snapshotDao.get(
getParameters().getVmId(), Snapshot.SnapshotType.ACTIVE).getId();
updateCinderDiskSnapshot(cinderDisk.getId(), activeSnapshotId, cinderDisk.getVmSnapshotId());
} else if (getParameters().getSnapshot().getType() != Snapshot.SnapshotType.REGULAR) {
updateCinderDiskSnapshot(cinderDisk.getId(), getParameters().getSnapshot().getId(), null);
}
}
List<CinderDisk> cinderDisksToRemove = getParameters().getCinderDisksToRemove();
for (CinderDisk cinderDisk : cinderDisksToRemove) {
RemoveCinderDiskParameters removeDiskParam =
new RemoveCinderDiskParameters(cinderDisk.getImageId());
removeDiskParam.setRemovedVolume(cinderDisk);
removeDiskParam.setParentCommand(getActionType());
removeDiskParam.setStorageDomainId(cinderDisk.getStorageIds().get(0));
removeDiskParam.setParentParameters(getParameters());
removeDiskParam.setEndProcedure(EndProcedure.COMMAND_MANAGED);
Future<VdcReturnValueBase> future = CommandCoordinatorUtil.executeAsyncCommand(
VdcActionType.RemoveCinderDisk,
removeDiskParam,
cloneContextAndDetachFromParent());
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
log.error("Error removing Cinder disk", e);
}
}
List<CinderDisk> cinderVolumesToRemove = getParameters().getCinderVolumesToRemove();
for (CinderDisk cinderVolume : cinderVolumesToRemove) {
RemoveCinderDiskVolumeParameters removeDiskVolumeParam =
new RemoveCinderDiskVolumeParameters(cinderVolume);
removeDiskVolumeParam.setParentCommand(getActionType());
removeDiskVolumeParam.setParentParameters(getParameters());
removeDiskVolumeParam.setEndProcedure(EndProcedure.COMMAND_MANAGED);
Future<VdcReturnValueBase> future = CommandCoordinatorUtil.executeAsyncCommand(
VdcActionType.RemoveCinderDiskVolume,
removeDiskVolumeParam,
cloneContextAndDetachFromParent());
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
log.error("Error removing Cinder disk", e);
}
}
setSucceeded(true);
}
private void updateCinderDiskSnapshot(Guid cinderDiskId, Guid snapshotId, Guid vmSnapshotId) {
DiskImage diskFromSnapshot = diskImageDao.getDiskSnapshotForVmSnapshot(cinderDiskId, snapshotId);
diskFromSnapshot.setActive(true);
if (!Guid.isNullOrEmpty(vmSnapshotId)) {
// Needed for stateless snapshot
diskFromSnapshot.setVmSnapshotId(vmSnapshotId);
}
imageDao.update(diskFromSnapshot.getImage());
}
private ImagesContainterParametersBase getRestoreFromSnapshotParams(CinderDisk cinderDisk) {
RemoveCinderDiskParameters params =
new RemoveCinderDiskParameters(cinderDisk.getImageId());
params.setRemovedVolume(cinderDisk);
params.setParentCommand(getActionType());
params.setStorageDomainId(cinderDisk.getStorageIds().get(0));
params.setParentParameters(getParameters());
return params;
}
private VdcReturnValueBase restoreCinderDisk(CinderDisk cinderDisk, ImagesContainterParametersBase params) {
Future<VdcReturnValueBase> future = CommandCoordinatorUtil.executeAsyncCommand(
VdcActionType.RestoreFromCinderSnapshot,
params,
cloneContextAndDetachFromParent());
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
log.error("Error restoring snapshot", e);
}
return null;
}
@Override
protected void endSuccessfully() {
removeRedundantVolumesForOrphanedDisks();
if (!getParameters().isParentHasTasks()) {
unlockSnapshot(getParameters().getSnapshot().getId());
super.endSuccessfully();
}
setSucceeded(true);
}
@Override
protected void endWithFailure() {
removeRedundantVolumesForOrphanedDisks();
if (!getParameters().isParentHasTasks()) {
unlockSnapshot(getParameters().getSnapshot().getId());
super.endWithFailure();
}
setSucceeded(true);
}
private void removeRedundantVolumesForOrphanedDisks() {
List<CinderDisk> cinderVolumesToRemove = getParameters().getCinderVolumesToRemove();
for (CinderDisk cinderVolume : cinderVolumesToRemove) {
imageStorageDomainMapDao.remove(cinderVolume.getImageId());
imageDao.remove(cinderVolume.getImageId());
}
}
@Override
public CommandCallback getCallback() {
return new ConcurrentChildCommandsExecutionCallback();
}
}