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; } }