package org.ovirt.engine.core.bll; import static org.ovirt.engine.core.bll.storage.disk.image.DisksFilter.ONLY_ACTIVE; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collections; import java.util.List; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Singleton; import org.ovirt.engine.core.bll.context.CompensationContext; import org.ovirt.engine.core.bll.storage.disk.image.DisksFilter; import org.ovirt.engine.core.bll.storage.disk.image.ImagesHandler; import org.ovirt.engine.core.bll.validator.storage.StorageDomainValidator; import org.ovirt.engine.core.common.BackendService; import org.ovirt.engine.core.common.backendinterfaces.BaseHandler; import org.ovirt.engine.core.common.businessentities.EditableVmField; import org.ovirt.engine.core.common.businessentities.EditableVmTemplateField; import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.common.businessentities.VmBase; import org.ovirt.engine.core.common.businessentities.VmDeviceId; import org.ovirt.engine.core.common.businessentities.VmTemplate; import org.ovirt.engine.core.common.businessentities.VmTemplateStatus; import org.ovirt.engine.core.common.businessentities.storage.Disk; import org.ovirt.engine.core.common.businessentities.storage.DiskImage; import org.ovirt.engine.core.common.businessentities.storage.DiskVmElement; import org.ovirt.engine.core.common.businessentities.storage.ImageStatus; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.DiskDao; import org.ovirt.engine.core.dao.DiskVmElementDao; import org.ovirt.engine.core.dao.StorageDomainDao; import org.ovirt.engine.core.dao.VmTemplateDao; import org.ovirt.engine.core.utils.ObjectIdentityChecker; import org.ovirt.engine.core.utils.transaction.TransactionSupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class VmTemplateHandler implements BackendService { private static final Logger log = LoggerFactory.getLogger(VmTemplateHandler.class); public static final Guid BLANK_VM_TEMPLATE_ID = Guid.Empty; public static final String BLANK_VM_TEMPLATE_NAME = "Blank"; @Inject private VmTemplateDao vmTemplateDao; @Inject private DiskDao diskDao; @Inject private DiskVmElementDao diskVmElementDao; @Inject private StorageDomainDao storageDomainDao; private ObjectIdentityChecker updateVmTemplate; /** * Initialize list containers, for identity and permission check. The initialization should be executed * before calling ObjectIdentityChecker. * * @see Backend#initHandlers() */ @PostConstruct public void init() { final Class<?>[] inspectedClassNames = new Class<?>[]{VmBase.class, VmTemplate.class}; updateVmTemplate = new ObjectIdentityChecker(VmTemplateHandler.class); for (Pair<EditableVmTemplateField, Field> pair : BaseHandler.extractAnnotatedFields(EditableVmTemplateField.class, inspectedClassNames)) { String fieldName = pair.getSecond().getName(); updateVmTemplate.addPermittedFields(fieldName); } for (Pair<EditableVmField, Field> pair : BaseHandler.extractAnnotatedFields(EditableVmField.class, inspectedClassNames)) { EditableVmField annotation = pair.getFirst(); List<VMStatus> statusList = Arrays.asList(annotation.onStatuses()); String fieldName = pair.getSecond().getName(); if (statusList.isEmpty()) { updateVmTemplate.addPermittedFields(fieldName); } } } public boolean isUpdateValid(VmTemplate source, VmTemplate destination) { return updateVmTemplate.isUpdateValid(source, destination); } public void updateDisksFromDb(VmTemplate vmt) { vmt.getDiskTemplateMap().clear(); vmt.getDiskImageMap().clear(); vmt.getDiskList().clear(); List<Disk> diskList = diskDao.getAllForVm(vmt.getId()); for (Disk dit : diskList) { DiskImage diskImage = (DiskImage) dit; vmt.getDiskTemplateMap().put(dit.getId(), diskImage); vmt.getDiskImageMap().put(dit.getId(), diskImage); DiskVmElement dve = diskVmElementDao.get(new VmDeviceId(dit.getId(), vmt.getId())); dit.setDiskVmElements(Collections.singletonList(dve)); vmt.getDiskList().add(diskImage); } } /** * Lock the VM template with the given id in a new transaction, handling the compensation data using the given * {@link CompensationContext}. * * @param vmTemplateGuid * The id of the template to lock. * @param compensationContext * The compensation context for saving the old status (can't be <code>null</code>). */ public void lockVmTemplateInTransaction(final Guid vmTemplateGuid, final CompensationContext compensationContext) { TransactionSupport.executeInNewTransaction(() -> { setVmTemplateStatus(vmTemplateGuid, VmTemplateStatus.Locked, compensationContext); compensationContext.stateChanged(); return null; }); } public void unlockVmTemplate(Guid vmTemplateGuid) { setVmTemplateStatus(vmTemplateGuid, VmTemplateStatus.OK, null); } /** * Set the status of the VM template with the given id to the desired status, saving the old status if necessary. * * @param vmTemplateGuid * The id of the template to set the status for. * @param status * The status to set. * @param compensationContext * The compensation context for saving the old status (can be <code>null</code> if the old status is not * required to be saved). */ private void setVmTemplateStatus( Guid vmTemplateGuid, VmTemplateStatus status, CompensationContext compensationContext) { VmTemplate vmTemplate = vmTemplateDao.get(vmTemplateGuid); if (vmTemplate != null) { if (compensationContext != null) { compensationContext.snapshotEntityStatus(vmTemplate); } vmTemplate.setStatus(status); vmTemplateDao.update(vmTemplate); } else { log.warn( "setVmTemplateStatus: vmTemplate is null, not setting status '{}' to vmTemplate", status); } } public ValidationResult isVmTemplateImagesReady(VmTemplate vmTemplate, Guid storageDomainId, boolean checkImagesExists, boolean checkLocked, boolean checkIllegal, boolean checkStorageDomain, List<DiskImage> providedVmtImages) { List<DiskImage> vmtImages = providedVmtImages; if (checkStorageDomain) { StorageDomainValidator storageDomainValidator = new StorageDomainValidator(storageDomainDao.getForStoragePool( storageDomainId, vmTemplate.getStoragePoolId())); ValidationResult returnValue = storageDomainValidator.isDomainExistAndActive(); if (!returnValue.isValid()) { return returnValue; } } if (checkImagesExists) { if (vmtImages == null) { vmtImages = DisksFilter.filterImageDisks(diskDao.getAllForVm(vmTemplate.getId()), ONLY_ACTIVE); } if (vmtImages.size() > 0 && !ImagesHandler.isImagesExists(vmtImages, vmtImages.get(0).getStoragePoolId())) { return new ValidationResult(EngineMessage.TEMPLATE_IMAGE_NOT_EXIST); } } if (checkLocked) { if (vmTemplate.getStatus() == VmTemplateStatus.Locked) { return new ValidationResult(EngineMessage.VM_TEMPLATE_IMAGE_IS_LOCKED); } if (vmtImages != null) { for (DiskImage image : vmtImages) { if (image.getImageStatus() == ImageStatus.LOCKED) { return new ValidationResult(EngineMessage.VM_TEMPLATE_IMAGE_IS_LOCKED); } } } } if (checkIllegal && (vmTemplate.getStatus() == VmTemplateStatus.Illegal)) { return new ValidationResult(EngineMessage.VM_TEMPLATE_IMAGE_IS_ILLEGAL); } return ValidationResult.VALID; } }