package org.ovirt.engine.core.bll.exportimport; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import org.ovirt.engine.core.bll.DisableInPrepareMode; 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.network.vm.VnicProfileHelper; import org.ovirt.engine.core.bll.profiles.CpuProfileHelper; import org.ovirt.engine.core.bll.profiles.DiskProfileHelper; import org.ovirt.engine.core.bll.quota.QuotaConsumptionParameter; import org.ovirt.engine.core.bll.quota.QuotaStorageConsumptionParameter; import org.ovirt.engine.core.bll.quota.QuotaStorageDependent; import org.ovirt.engine.core.bll.storage.disk.image.ImagesHandler; import org.ovirt.engine.core.bll.storage.utils.BlockStorageDiscardFunctionalityHelper; import org.ovirt.engine.core.bll.validator.VmNicMacsUtils; import org.ovirt.engine.core.bll.validator.storage.DiskImagesValidator; import org.ovirt.engine.core.bll.validator.storage.StorageDomainValidator; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.FeatureSupported; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.ImportVmTemplateParameters; import org.ovirt.engine.core.common.action.MoveOrCopyImageGroupParameters; 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.asynctasks.EntityInfo; import org.ovirt.engine.core.common.businessentities.ArchitectureType; import org.ovirt.engine.core.common.businessentities.StorageDomain; import org.ovirt.engine.core.common.businessentities.StorageDomainStatic; import org.ovirt.engine.core.common.businessentities.StorageDomainType; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.VmTemplate; import org.ovirt.engine.core.common.businessentities.VmTemplateStatus; import org.ovirt.engine.core.common.businessentities.network.VmNetworkInterface; import org.ovirt.engine.core.common.businessentities.network.VmNetworkStatistics; import org.ovirt.engine.core.common.businessentities.network.VmNic; import org.ovirt.engine.core.common.businessentities.storage.CopyVolumeType; import org.ovirt.engine.core.common.businessentities.storage.DiskImage; import org.ovirt.engine.core.common.businessentities.storage.DiskImageDynamic; import org.ovirt.engine.core.common.businessentities.storage.DiskVmElement; import org.ovirt.engine.core.common.businessentities.storage.ImageDbOperationScope; import org.ovirt.engine.core.common.businessentities.storage.ImageOperation; import org.ovirt.engine.core.common.businessentities.storage.ImageStorageDomainMap; import org.ovirt.engine.core.common.businessentities.storage.QcowCompat; import org.ovirt.engine.core.common.businessentities.storage.QemuImageInfo; import org.ovirt.engine.core.common.businessentities.storage.StorageType; import org.ovirt.engine.core.common.businessentities.storage.VolumeFormat; import org.ovirt.engine.core.common.businessentities.storage.VolumeType; import org.ovirt.engine.core.common.errors.EngineError; import org.ovirt.engine.core.common.errors.EngineException; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.queries.GetAllFromExportDomainQueryParameters; import org.ovirt.engine.core.common.queries.VdcQueryReturnValue; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.common.utils.CompatibilityVersionUtils; import org.ovirt.engine.core.common.validation.group.ImportClonedEntity; import org.ovirt.engine.core.common.validation.group.ImportEntity; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.Version; import org.ovirt.engine.core.dao.BaseDiskDao; import org.ovirt.engine.core.dao.DiskImageDao; import org.ovirt.engine.core.dao.DiskImageDynamicDao; import org.ovirt.engine.core.dao.DiskVmElementDao; import org.ovirt.engine.core.dao.ImageDao; import org.ovirt.engine.core.dao.StorageDomainDao; import org.ovirt.engine.core.dao.VmDao; import org.ovirt.engine.core.dao.VmTemplateDao; import org.ovirt.engine.core.dao.network.VmNetworkStatisticsDao; import org.ovirt.engine.core.dao.network.VmNicDao; import org.ovirt.engine.core.utils.transaction.TransactionSupport; @DisableInPrepareMode @NonTransactiveCommandAttribute(forceCompensation = true) public class ImportVmTemplateCommand extends MoveOrCopyTemplateCommand<ImportVmTemplateParameters> implements QuotaStorageDependent { /** * Map which contains the disk id (new generated id if the disk is cloned) and the disk parameters from the export * domain. */ private final Map<Guid, DiskImage> newDiskIdForDisk = new HashMap<>(); @Inject VmNicMacsUtils vmNicMacsUtils; @Inject private CpuProfileHelper cpuProfileHelper; @Inject private DiskProfileHelper diskProfileHelper; @Inject private BlockStorageDiscardFunctionalityHelper discardHelper; @Inject private BaseDiskDao baseDiskDao; @Inject private DiskImageDynamicDao diskImageDynamicDao; @Inject private DiskVmElementDao diskVmElementDao; @Inject private VmNetworkStatisticsDao vmNetworkStatisticsDao; @Inject private ImageDao imageDao; @Inject private VmTemplateDao vmTemplateDao; @Inject private StorageDomainDao storageDomainDao; @Inject private VmNicDao vmNicDao; @Inject private DiskImageDao diskImageDao; @Inject private VmDao vmDao; private Version effectiveCompatibilityVersion; private StorageDomain sourceDomain; private Guid sourceDomainId = Guid.Empty; private Guid sourceTemplateId; public ImportVmTemplateCommand(ImportVmTemplateParameters parameters, CommandContext commandContext) { super(parameters, commandContext); setVmTemplate(parameters.getVmTemplate()); parameters.setEntityInfo(new EntityInfo(VdcObjectType.VmTemplate, getVmTemplateId())); setStoragePoolId(parameters.getStoragePoolId()); setClusterId(parameters.getClusterId()); setStorageDomainId(parameters.getStorageDomainId()); } @Override public void init() { super.init(); setEffectiveCompatibilityVersion(CompatibilityVersionUtils.getEffective(getVmTemplate(), this::getCluster)); ImportUtils.updateGraphicsDevices(getVmTemplate(), getEffectiveCompatibilityVersion()); VmHandler.updateMaxMemorySize(getVmTemplate(), getEffectiveCompatibilityVersion()); } public ImportVmTemplateCommand(Guid commandId) { super(commandId); } public Version getEffectiveCompatibilityVersion() { return effectiveCompatibilityVersion; } public void setEffectiveCompatibilityVersion(Version effectiveCompatibilityVersion) { this.effectiveCompatibilityVersion = effectiveCompatibilityVersion; } @Override protected boolean validate() { if (getVmTemplate() == null) { return false; } setDescription(getVmTemplateName()); // check that the storage pool is valid if (!checkStoragePool() || !validateTemplateArchitecture() || !isClusterCompatible()) { return false; } // set the source domain and check that it is ImportExport type and active setSourceDomainId(getParameters().getSourceDomainId()); StorageDomainValidator sourceDomainValidator = new StorageDomainValidator(getSourceDomain()); if (!validate(sourceDomainValidator.isDomainExistAndActive())) { return false; } if ((getSourceDomain().getStorageDomainType() != StorageDomainType.ImportExport) && !getParameters().isImagesExistOnTargetStorageDomain()) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_ILLEGAL); } if (!getParameters().isImagesExistOnTargetStorageDomain()) { // Set the template images from the Export domain and change each image id storage is to the import domain GetAllFromExportDomainQueryParameters tempVar = new GetAllFromExportDomainQueryParameters(getParameters() .getStoragePoolId(), getParameters().getSourceDomainId()); VdcQueryReturnValue qretVal = runInternalQuery( VdcQueryType.GetTemplatesFromExportDomain, tempVar); if (!qretVal.getSucceeded()) { return false; } Map<VmTemplate, List<DiskImage>> templates = qretVal.getReturnValue(); ArrayList<DiskImage> images = new ArrayList<>(); for (Map.Entry<VmTemplate, List<DiskImage>> entry : templates.entrySet()) { if (entry.getKey().getId().equals(getVmTemplate().getId())) { images = new ArrayList<>(entry.getValue()); getVmTemplate().setInterfaces(entry.getKey().getInterfaces()); getVmTemplate().setOvfVersion(entry.getKey().getOvfVersion()); break; } } getParameters().setImages(images); getVmTemplate().setImages(images); ensureDomainMap(getImages(), getParameters().getDestDomainId()); HashMap<Guid, DiskImage> imageMap = new HashMap<>(); for (DiskImage image : images) { if (Guid.Empty.equals(image.getVmSnapshotId())) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_CORRUPTED_VM_SNAPSHOT_ID); } StorageDomain storageDomain = getStorageDomain(imageToDestinationDomainMap.get(image.getId())); StorageDomainValidator validator = new StorageDomainValidator(storageDomain); if (!validate(validator.isDomainExistAndActive()) || !validate(validator.domainIsValidDestination())) { return false; } StorageDomainStatic targetDomain = storageDomain.getStorageStaticData(); changeRawToCowIfSparseOnBlockDevice(targetDomain.getStorageType(), image); if (!ImagesHandler.checkImageConfiguration(targetDomain, image, getReturnValue().getValidationMessages())) { return false; } image.setStoragePoolId(getParameters().getStoragePoolId()); image.setStorageIds(new ArrayList<>(Collections.singletonList(storageDomain.getId()))); imageMap.put(image.getImageId(), image); } getVmTemplate().setDiskImageMap(imageMap); } sourceTemplateId = getVmTemplateId(); if (getParameters().isImportAsNewEntity()) { initImportClonedTemplate(); } VmTemplate duplicateTemplate = vmTemplateDao.get(getParameters().getVmTemplate().getId()); // check that the template does not exists in the target domain if (duplicateTemplate != null) { return failValidation(EngineMessage.VMT_CANNOT_IMPORT_TEMPLATE_EXISTS, String.format("$TemplateName %1$s", duplicateTemplate.getName())); } if (getVmTemplate().isBaseTemplate() && isVmTemplateWithSameNameExist()) { return failValidation(EngineMessage.VM_CANNOT_IMPORT_TEMPLATE_NAME_EXISTS); } if (!validateNoDuplicateDiskImages(getImages())) { return false; } if (getImages() != null && !getImages().isEmpty() && !getParameters().isImagesExistOnTargetStorageDomain()) { if (!validateSpaceRequirements(getImages())) { return false; } } List<VmNetworkInterface> vmNetworkInterfaces = getVmTemplate().getInterfaces(); vmNicMacsUtils.replaceInvalidEmptyStringMacAddressesWithNull(vmNetworkInterfaces); if (!validate(vmNicMacsUtils.validateMacAddress(vmNetworkInterfaces))) { return false; } // if this is a template version, check base template exist if (!getVmTemplate().isBaseTemplate()) { VmTemplate baseTemplate = vmTemplateDao.get(getVmTemplate().getBaseTemplateId()); if (baseTemplate == null) { return failValidation(EngineMessage.VMT_CANNOT_IMPORT_TEMPLATE_VERSION_MISSING_BASE); } } if (!setAndValidateDiskProfiles()) { return false; } if (!setAndValidateCpuProfile()) { return false; } if (!validate(VmHandler.validateMaxMemorySize(getVmTemplate(), getEffectiveCompatibilityVersion()))) { return false; } return true; } protected StorageDomain getSourceDomain() { if (sourceDomain == null && !Guid.Empty.equals(sourceDomainId)) { sourceDomain = storageDomainDao.getForStoragePool(sourceDomainId, getStoragePool().getId()); } return sourceDomain; } protected void setSourceDomainId(Guid storageId) { sourceDomainId = storageId; } @Override protected void setActionMessageParameters() { addValidationMessage(EngineMessage.VAR__ACTION__IMPORT); addValidationMessage(EngineMessage.VAR__TYPE__VM_TEMPLATE); } protected boolean isClusterCompatible () { if (getCluster().getArchitecture() != getVmTemplate().getClusterArch()) { addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_VM_CANNOT_IMPORT_TEMPLATE_ARCHITECTURE_NOT_SUPPORTED_BY_CLUSTER); return false; } return true; } protected boolean validateTemplateArchitecture () { if (getVmTemplate().getClusterArch() == ArchitectureType.undefined) { addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_VM_CANNOT_IMPORT_TEMPLATE_WITH_NOT_SUPPORTED_ARCHITECTURE); return false; } return true; } protected boolean isVmTemplateWithSameNameExist() { return vmTemplateDao.getByName(getParameters().getVmTemplate().getName(), getParameters().getStoragePoolId(), null, false) != null; } private void initImportClonedTemplate() { Guid newTemplateId = Guid.newGuid(); getParameters().getVmTemplate().setId(newTemplateId); for (VmNetworkInterface iface : getParameters().getVmTemplate().getInterfaces()) { iface.setId(Guid.newGuid()); } // cloned template is always base template, as its a new entity getParameters().getVmTemplate().setBaseTemplateId(newTemplateId); } private void initImportClonedTemplateDisks() { for (DiskImage image : getImages()) { if (getParameters().isImportAsNewEntity()) { generateNewDiskId(image); updateManagedDeviceMap(image, getVmTemplate().getManagedDeviceMap()); } else { newDiskIdForDisk.put(image.getId(), image); } } } protected boolean validateNoDuplicateDiskImages(Iterable<DiskImage> images) { if (!getParameters().isImportAsNewEntity() && !getParameters().isImagesExistOnTargetStorageDomain()) { DiskImagesValidator diskImagesValidator = new DiskImagesValidator(images); return validate(diskImagesValidator.diskImagesAlreadyExist()); } return true; } protected List<DiskImage> getImages() { return getParameters().getImages(); } /** * Change the image format to {@link VolumeFormat#COW} in case the SD is a block device and the image format is * {@link VolumeFormat#RAW} and the type is {@link VolumeType#Sparse}. * * @param storageType * The domain type. * @param image * The image to check and change if needed. */ private void changeRawToCowIfSparseOnBlockDevice(StorageType storageType, DiskImage image) { if (storageType.isBlockDomain() && image.getVolumeFormat() == VolumeFormat.RAW && image.getVolumeType() == VolumeType.Sparse) { image.setVolumeFormat(VolumeFormat.COW); } } @Override protected void executeCommand() { TransactionSupport.executeInNewTransaction(() -> { initImportClonedTemplateDisks(); addVmTemplateToDb(); updateOriginalTemplateNameOnDerivedVms(); addVmInterfaces(); getCompensationContext().stateChanged(); vmHandler.addVmInitToDB(getVmTemplate()); return null; }); boolean doesVmTemplateContainImages = !getImages().isEmpty(); if (doesVmTemplateContainImages && !getParameters().isImagesExistOnTargetStorageDomain()) { moveOrCopyAllImageGroups(getVmTemplateId(), getImages()); } getVmDeviceUtils().addImportedDevices(getVmTemplate(), getParameters().isImportAsNewEntity()); if (!doesVmTemplateContainImages || getParameters().isImagesExistOnTargetStorageDomain()) { endMoveOrCopyCommand(); } discardHelper.logIfDisksWithIllegalPassDiscardExist(getVmTemplateId()); checkTrustedService(); setSucceeded(true); } private void updateOriginalTemplateNameOnDerivedVms() { if (!getParameters().isImportAsNewEntity()) { // in case it has been renamed vmDao.updateOriginalTemplateName(getVmTemplate().getId(), getVmTemplate().getName()); } } private void checkTrustedService() { if (getVmTemplate().isTrustedService() && !getCluster().supportsTrustedService()) { auditLogDirector.log(this, AuditLogType.IMPORTEXPORT_IMPORT_TEMPLATE_FROM_TRUSTED_TO_UNTRUSTED); } else if (!getVmTemplate().isTrustedService() && getCluster().supportsTrustedService()) { auditLogDirector.log(this, AuditLogType.IMPORTEXPORT_IMPORT_TEMPLATE_FROM_UNTRUSTED_TO_TRUSTED); } } @Override protected void moveOrCopyAllImageGroups(final Guid containerID, final Iterable<DiskImage> disks) { TransactionSupport.executeInNewTransaction(() -> { for (DiskImage disk : disks) { Guid originalDiskId = newDiskIdForDisk.get(disk.getId()).getId(); Guid destinationDomain = imageToDestinationDomainMap.get(originalDiskId); MoveOrCopyImageGroupParameters p = new MoveOrCopyImageGroupParameters(containerID, originalDiskId, newDiskIdForDisk.get(disk.getId()).getImageId(), disk.getId(), disk.getImageId(), destinationDomain, ImageOperation.Copy); p.setParentCommand(getActionType()); p.setUseCopyCollapse(true); p.setVolumeType(disk.getVolumeType()); p.setVolumeFormat(disk.getVolumeFormat()); p.setCopyVolumeType(CopyVolumeType.SharedVol); p.setSourceDomainId(getParameters().getSourceDomainId()); p.setForceOverride(getParameters().getForceOverride()); p.setImportEntity(true); p.setEntityInfo(new EntityInfo(VdcObjectType.VmTemplate, containerID)); p.setRevertDbOperationScope(ImageDbOperationScope.IMAGE); for (DiskImage diskImage : getParameters().getVmTemplate().getDiskList()) { if (originalDiskId.equals(diskImage.getId())) { p.setQuotaId(diskImage.getQuotaId()); p.setDiskProfileId(diskImage.getDiskProfileId()); break; } } p.setParentParameters(getParameters()); VdcReturnValueBase vdcRetValue = runInternalActionWithTasksContext( VdcActionType.CopyImageGroup, p); if (!vdcRetValue.getSucceeded()) { throw vdcRetValue.getFault() != null ? new EngineException(vdcRetValue.getFault().getError()) : new EngineException(EngineError.ENGINE); } getReturnValue().getVdsmTaskIdList().addAll(vdcRetValue.getInternalVdsmTaskIdList()); } return null; }); } protected void addVmTemplateToDb() { getVmTemplate().setClusterId(getParameters().getClusterId()); // if "run on host" field points to a non existent vds (in the current cluster) -> remove field and continue if(!vmHandler.validateDedicatedVdsExistOnSameCluster(getVmTemplate(), null)){ getVmTemplate().setDedicatedVmForVdsList(Collections.emptyList()); } getVmTemplate().setStatus(VmTemplateStatus.Locked); getVmTemplate().setQuotaId(getParameters().getQuotaId()); vmTemplateDao.save(getVmTemplate()); getCompensationContext().snapshotNewEntity(getVmTemplate()); int count = 1; for (DiskImage image : getImages()) { image.setActive(true); ImageStorageDomainMap map = ImagesHandler.saveImage(image); getCompensationContext().snapshotNewEntity(image.getImage()); getCompensationContext().snapshotNewEntity(map); if (!baseDiskDao.exists(image.getId())) { image.setDiskAlias(ImagesHandler.getSuggestedDiskAlias(image, getVmTemplateName(), count)); count++; baseDiskDao.save(image); getCompensationContext().snapshotNewEntity(image); } DiskImageDynamic diskDynamic = new DiskImageDynamic(); diskDynamic.setId(image.getImageId()); diskDynamic.setActualSize(image.getActualSizeInBytes()); diskImageDynamicDao.save(diskDynamic); DiskVmElement dve = DiskVmElement.copyOf(image.getDiskVmElementForVm(sourceTemplateId), image.getId(), getVmTemplateId()); diskVmElementDao.save(dve); getCompensationContext().snapshotNewEntity(diskDynamic); } } protected void addVmInterfaces() { VnicProfileHelper vnicProfileHelper = new VnicProfileHelper(getVmTemplate().getClusterId(), getStoragePoolId(), AuditLogType.IMPORTEXPORT_IMPORT_TEMPLATE_INVALID_INTERFACES); for (VmNetworkInterface iface : getVmTemplate().getInterfaces()) { if (iface.getId() == null) { iface.setId(Guid.newGuid()); } iface.setVmId(getVmTemplateId()); VmNic nic = new VmNic(); nic.setId(iface.getId()); nic.setVmTemplateId(getVmTemplateId()); nic.setName(iface.getName()); nic.setLinked(iface.isLinked()); nic.setSpeed(iface.getSpeed()); nic.setType(iface.getType()); vnicProfileHelper.updateNicWithVnicProfileForUser(iface, getCurrentUser()); nic.setVnicProfileId(iface.getVnicProfileId()); vmNicDao.save(nic); getCompensationContext().snapshotNewEntity(nic); VmNetworkStatistics iStat = new VmNetworkStatistics(); nic.setStatistics(iStat); iStat.setId(iface.getId()); iStat.setVmId(getVmTemplateId()); vmNetworkStatisticsDao.save(iStat); getCompensationContext().snapshotNewEntity(iStat); } vnicProfileHelper.auditInvalidInterfaces(getVmTemplateName()); } @Override protected void endMoveOrCopyCommand() { vmTemplateHandler.unlockVmTemplate(getVmTemplateId()); endActionOnAllImageGroups(); setSucceeded(true); } protected void removeNetwork() { List<VmNic> list = vmNicDao.getAllForTemplate(getVmTemplateId()); for (VmNic iface : list) { vmNicDao.remove(iface.getId()); } } @Override protected void endActionOnAllImageGroups() { for (VdcActionParametersBase p : getParameters().getImagesParameters()) { p.setTaskGroupSuccess(getParameters().getTaskGroupSuccess()); getBackend().endAction(VdcActionType.CopyImageGroup, p, getContext().clone().withoutCompensationContext().withoutExecutionContext().withoutLock()); } } @Override protected void endWithFailure() { removeNetwork(); endActionOnAllImageGroups(); vmTemplateDao.remove(getVmTemplateId()); setSucceeded(true); } @Override public AuditLogType getAuditLogTypeValue() { switch (getActionState()) { case EXECUTE: return getSucceeded() ? AuditLogType.IMPORTEXPORT_STARTING_IMPORT_TEMPLATE : AuditLogType.IMPORTEXPORT_IMPORT_TEMPLATE_FAILED; case END_SUCCESS: return getSucceeded() ? AuditLogType.IMPORTEXPORT_IMPORT_TEMPLATE : AuditLogType.IMPORTEXPORT_IMPORT_TEMPLATE_FAILED; default: return AuditLogType.IMPORTEXPORT_IMPORT_TEMPLATE_FAILED; } } @Override public Guid getVmTemplateId() { if (getParameters().isImportAsNewEntity()) { return getParameters().getVmTemplate().getId(); } else { return super.getVmTemplateId(); } } @Override public VmTemplate getVmTemplate() { if (getParameters().isImportAsNewEntity()) { return getParameters().getVmTemplate(); } else { return super.getVmTemplate(); } } @Override protected List<Class<?>> getValidationGroups() { if(getParameters().isImportAsNewEntity()){ return addValidationGroup(ImportClonedEntity.class); } return addValidationGroup(ImportEntity.class); } @Override public Map<String, String> getJobMessageProperties() { if (jobProperties == null) { jobProperties = super.getJobMessageProperties(); jobProperties.put(VdcObjectType.VmTemplate.name().toLowerCase(), (getVmTemplateName() == null) ? "" : getVmTemplateName()); } return jobProperties; } protected boolean setAndValidateDiskProfiles() { if (getParameters().getVmTemplate().getDiskList() != null) { Map<DiskImage, Guid> map = new HashMap<>(); for (DiskImage diskImage : getParameters().getVmTemplate().getDiskList()) { map.put(diskImage, imageToDestinationDomainMap.get(diskImage.getId())); } return validate(diskProfileHelper.setAndValidateDiskProfiles(map, getCurrentUser())); } return true; } protected boolean setAndValidateCpuProfile() { getVmTemplate().setClusterId(getClusterId()); getVmTemplate().setCpuProfileId(getParameters().getCpuProfileId()); return validate(cpuProfileHelper.setAndValidateCpuProfile( getVmTemplate(), getUserIdIfExternal().orElse(null))); } @Override public List<QuotaConsumptionParameter> getQuotaStorageConsumptionParameters() { List<QuotaConsumptionParameter> list = new ArrayList<>(); for (DiskImage disk : getParameters().getVmTemplate().getDiskList()) { //TODO: handle import more than once; list.add(new QuotaStorageConsumptionParameter( disk.getQuotaId(), null, QuotaConsumptionParameter.QuotaAction.CONSUME, imageToDestinationDomainMap.get(disk.getId()), (double)disk.getSizeInGigabytes())); } return list; } protected void initQcowVersionForDisks(Guid imageGroupId) { List<DiskImage> diskVolumes = diskImageDao.getAllSnapshotsForImageGroup(imageGroupId); diskVolumes.stream().filter(volume -> volume.getVolumeFormat() == VolumeFormat.COW).forEach(volume -> { try { setQcowCompat(volume); } catch (Exception e) { log.error("Could not set qcow compat version for disk '{} with id '{}/{}'", volume.getDiskAlias(), volume.getId(), volume.getImageId()); } }); } protected void setQcowCompat(DiskImage diskImage) { diskImage.setQcowCompat(QcowCompat.QCOW2_V2); if (FeatureSupported.qcowCompatSupported(getStoragePool().getCompatibilityVersion())) { QemuImageInfo qemuImageInfo = ImagesHandler.getQemuImageInfoFromVdsm(diskImage.getStoragePoolId(), diskImage.getStorageIds().get(0), diskImage.getId(), diskImage.getImageId(), null, true); if (qemuImageInfo != null) { diskImage.setQcowCompat(qemuImageInfo.getQcowCompat()); } } imageDao.update(diskImage.getImage()); } /** * Updating managed device map of VM, with the new disk {@link Guid}s.<br/> * The update of managedDeviceMap is based on the newDiskIdForDisk map, * so this method should be called only after newDiskIdForDisk is initialized. * * @param disk * - The disk which is about to be cloned * @param managedDeviceMap * - The managed device map contained in the VM. */ protected void updateManagedDeviceMap(DiskImage disk, Map<Guid, VmDevice> managedDeviceMap) { Guid oldDiskId = newDiskIdForDisk.get(disk.getId()).getId(); managedDeviceMap.put(disk.getId(), managedDeviceMap.get(oldDiskId)); managedDeviceMap.remove(oldDiskId); } /** * Cloning a new disk with a new generated id, with the same parameters as <code>disk</code>. Also * adding the disk to <code>newDiskGuidForDisk</code> map, so we will be able to link between the new cloned disk * and the old disk id. * * @param disk * - The disk which is about to be cloned */ protected Guid generateNewDiskId(DiskImage disk) { Guid newGuidForDisk = Guid.newGuid(); // Copy the disk so it will preserve the old disk id and image id. newDiskIdForDisk.put(newGuidForDisk, DiskImage.copyOf(disk)); disk.setId(newGuidForDisk); disk.setImageId(Guid.newGuid()); return newGuidForDisk; } protected DiskImage getNewDiskIdForDisk(Guid diskId) { return newDiskIdForDisk.get(diskId); } }