package org.ovirt.engine.core.bll.storage.disk;
import static org.ovirt.engine.core.bll.storage.disk.image.DisksFilter.ONLY_ACTIVE;
import static org.ovirt.engine.core.bll.storage.disk.image.DisksFilter.ONLY_NOT_SHAREABLE;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.Backend;
import org.ovirt.engine.core.bll.CommandBase;
import org.ovirt.engine.core.bll.ConcurrentChildCommandsExecutionCallback;
import org.ovirt.engine.core.bll.DisableInPrepareMode;
import org.ovirt.engine.core.bll.InternalCommandAttribute;
import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute;
import org.ovirt.engine.core.bll.VmHandler;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.job.ExecutionHandler;
import org.ovirt.engine.core.bll.storage.disk.image.DisksFilter;
import org.ovirt.engine.core.bll.tasks.interfaces.CommandCallback;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.common.action.CreateAllTemplateDisksParameters;
import org.ovirt.engine.core.common.action.CreateImageTemplateParameters;
import org.ovirt.engine.core.common.action.ImagesContainterParametersBase;
import org.ovirt.engine.core.common.action.VdcActionParametersBase;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.businessentities.storage.CinderDisk;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.errors.EngineException;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
@DisableInPrepareMode
@NonTransactiveCommandAttribute
@InternalCommandAttribute
public class CreateAllTemplateDisksCommand<T extends CreateAllTemplateDisksParameters> extends CommandBase<T> {
@Inject
protected VmHandler vmHandler;
private final List<DiskImage> images = new ArrayList<>();
private int targetDiskIdIndex;
private List<CinderDisk> cinderDisks;
private final Guid vmSnapshotId = Guid.newGuid();
public CreateAllTemplateDisksCommand(T parameters, CommandContext cmdContext) {
super(parameters, cmdContext);
setVmId(parameters.getVmId());
}
public CreateAllTemplateDisksCommand(Guid commandId) {
super(commandId);
}
@Override
protected void init() {
super.init();
if (getVm() != null) {
images.addAll(getVmDisksFromDb());
}
getParameters().setUseCinderCommandCallback(!getCinderDisks().isEmpty());
}
@Override
protected void executeCommand() {
final Map<Guid, Guid> srcDeviceIdToTargetDeviceIdMapping = new HashMap<>();
if (getVm() != null && !addVmTemplateCinderDisks(srcDeviceIdToTargetDeviceIdMapping)) {
// Error cloning Cinder disks for template
return;
}
TransactionSupport.executeInNewTransaction(() -> {
addVmTemplateImages(srcDeviceIdToTargetDeviceIdMapping);
return null;
});
setActionReturnValue(srcDeviceIdToTargetDeviceIdMapping);
setSucceeded(true);
}
private boolean addVmTemplateCinderDisks(Map<Guid, Guid> srcDeviceIdToTargetDeviceIdMapping) {
List<CinderDisk> cinderDisks = getCinderDisks();
if (cinderDisks.isEmpty()) {
return true;
}
// Create Cinder disk templates
Map<Guid, Guid> diskImageMap = new HashMap<>();
for (CinderDisk cinderDisk : cinderDisks) {
ImagesContainterParametersBase params = buildCloneCinderDiskCommandParameters(cinderDisk);
VdcReturnValueBase returnValue =
runInternalAction(VdcActionType.CloneSingleCinderDisk,
params,
cloneContext().withoutExecutionContext().withoutLock());
if (!returnValue.getSucceeded()) {
log.error("Error cloning Cinder disk '{}'", cinderDisk.getDiskAlias());
getReturnValue().setFault(returnValue.getFault());
return false;
}
Guid imageId = returnValue.getActionReturnValue();
diskImageMap.put(cinderDisk.getId(), imageId);
}
srcDeviceIdToTargetDeviceIdMapping.putAll(diskImageMap);
return true;
}
private ImagesContainterParametersBase buildCloneCinderDiskCommandParameters(CinderDisk cinderDisk) {
ImagesContainterParametersBase createParams = new ImagesContainterParametersBase(cinderDisk.getImageId());
DiskImage templateDisk = getParameters().getDiskInfoDestinationMap().get(cinderDisk.getId());
createParams.setDiskAlias(templateDisk.getDiskAlias());
createParams.setStorageDomainId(templateDisk.getStorageIds().get(0));
createParams.setParentCommand(getActionType());
createParams.setParentParameters(getParameters());
createParams.setVmSnapshotId(vmSnapshotId);
return createParams;
}
private void addVmTemplateImages(Map<Guid, Guid> srcDeviceIdToTargetDeviceIdMapping) {
DisksFilter.filterImageDisks(images, ONLY_NOT_SHAREABLE, ONLY_ACTIVE)
.forEach(diskImage -> addVmTemplateImage(diskImage, srcDeviceIdToTargetDeviceIdMapping));
}
private void addVmTemplateImage(DiskImage diskImage, Map<Guid, Guid> srcDeviceIdToTargetDeviceIdMapping) {
// The return value of this action is the 'copyImage' task GUID:
Guid targetDiskId = getParameters().getTargetDiskIds()[targetDiskIdIndex++];
VdcReturnValueBase returnValue = Backend.getInstance().runInternalAction(
VdcActionType.CreateImageTemplate,
buildCreateImageTemplateCommandParameters(diskImage, targetDiskId),
ExecutionHandler.createDefaultContextForTasks(getContext()));
if (!returnValue.getSucceeded()) {
throw new EngineException(returnValue.getFault().getError(), returnValue.getFault().getMessage());
}
getReturnValue().getVdsmTaskIdList().addAll(returnValue.getInternalVdsmTaskIdList());
DiskImage newImage = returnValue.getActionReturnValue();
srcDeviceIdToTargetDeviceIdMapping.put(diskImage.getId(), newImage.getId());
}
private CreateImageTemplateParameters buildCreateImageTemplateCommandParameters(DiskImage diskImage, Guid vmSnapshotId) {
DiskImage imageFromParams = getParameters().getDiskInfoDestinationMap().get(diskImage.getId());
CreateImageTemplateParameters createParams = new CreateImageTemplateParameters(diskImage.getImageId(),
getParameters().getVmTemplateId(), getParameters().getVmTemplateName(), getVmId());
createParams.setStorageDomainId(diskImage.getStorageIds().get(0));
createParams.setVmSnapshotId(vmSnapshotId);
createParams.setEntityInfo(getParameters().getEntityInfo());
createParams.setDestinationStorageDomainId(imageFromParams.getStorageIds().get(0));
createParams.setDiskAlias(imageFromParams.getDiskAlias());
createParams.setDescription(imageFromParams.getDiskDescription());
createParams.setParentCommand(getActionType());
createParams.setParentParameters(getParameters());
createParams.setQuotaId(imageFromParams.getQuotaId());
createParams.setDiskProfileId(imageFromParams.getDiskProfileId());
createParams.setVolumeFormat(imageFromParams.getVolumeFormat());
createParams.setVolumeType(imageFromParams.getVolumeType());
createParams.setCopyVolumeType(getParameters().getCopyVolumeType());
return createParams;
}
@Override
protected void endSuccessfully() {
for (VdcActionParametersBase params : getParameters().getImagesParameters()) {
Backend.getInstance().endAction(params.getCommandType(),
params,
cloneContextAndDetachFromParent());
}
setSucceeded(true);
}
@Override
protected void endWithFailure() {
for (VdcActionParametersBase params : getParameters().getImagesParameters()) {
params.setTaskGroupSuccess(false);
Backend.getInstance().endAction(params.getCommandType(),
params,
cloneContextAndDetachFromParent());
}
setSucceeded(false);
}
protected List<DiskImage> getVmDisksFromDb() {
vmHandler.updateDisksFromDb(getVm());
vmHandler.filterImageDisksForVM(getVm());
return getVm().getDiskList();
}
private List<CinderDisk> getCinderDisks() {
if (cinderDisks == null) {
cinderDisks = DisksFilter.filterCinderDisks(images);
}
return cinderDisks;
}
@Override
public CommandCallback getCallback() {
return getParameters().isUseCinderCommandCallback() ? new ConcurrentChildCommandsExecutionCallback() : null;
}
@Override
public List<PermissionSubject> getPermissionCheckSubjects() {
return null;
}
}