package org.ovirt.engine.core.bll.snapshots; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.inject.Singleton; import org.ovirt.engine.core.bll.VmHandler; import org.ovirt.engine.core.bll.storage.disk.image.ImagesHandler; import org.ovirt.engine.core.common.businessentities.Snapshot; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.network.VmNetworkInterface; import org.ovirt.engine.core.common.businessentities.storage.DiskImage; import org.ovirt.engine.core.common.businessentities.storage.DiskStorageType; import org.ovirt.engine.core.common.businessentities.storage.ImageStatus; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.DiskImageDao; import org.ovirt.engine.core.dao.SnapshotDao; import org.ovirt.engine.core.dao.VmDao; import org.ovirt.engine.core.dao.network.VmNetworkInterfaceDao; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class SnapshotVmConfigurationHelper { private static final Logger log = LoggerFactory.getLogger(SnapshotVmConfigurationHelper.class); @Inject private SnapshotsManager snapshotsManager; @Inject private VmDao vmDao; @Inject private SnapshotDao snapshotDao; @Inject private VmNetworkInterfaceDao vmNetworkInterfaceDao; @Inject private DiskImageDao diskImageDao; @Inject private VmHandler vmHandler; /** * Creates a VM by a specified OVF string. * If configuration is not specified, creates a VM according to the snapshotId * (required for backwards compatibility - @see getVmWithoutConfiguration method). * * @param configuration The OVF String * @param vmId The VM ID * @param snapshotId The snapshot ID * @return a VM object based on the specified parameters. */ public VM getVmFromConfiguration(String configuration, Guid vmId, Guid snapshotId) { VM vm; if (configuration != null) { vm = getVmWithConfiguration(configuration, vmId); Snapshot snapshot = snapshotDao.get(snapshotId); if (snapshot != null && snapshot.getType() != Snapshot.SnapshotType.PREVIEW) { // No need to mark disks of 'PREVIEW' snapshot as illegal // as it represents previous 'Active VM' state and no operations // on disks can be done while previewing a snapshot. markImagesIllegalIfNotInDb(vm, snapshotId); } } else { vm = getVmWithoutConfiguration(vmId, snapshotId); } vmHandler.updateDisksForVm(vm, vm.getImages()); return vm; } protected VM getVmWithConfiguration(String configuration, Guid vmId) { VM result = vmDao.get(vmId); snapshotsManager.updateVmFromConfiguration(result, configuration); return result; } /** * Build a VM entity when configuration is not available, This method is required to create a VM entity for * snapshots which were taken in old engine where full OVF snapshot metadata was not supported. * * See also {@link VmHandler#updateDisksForVm(VM, java.util.List)} * * @return a VM */ protected VM getVmWithoutConfiguration(Guid vmId, Guid snapshotId) { VM vm = vmDao.get(vmId); List<VmNetworkInterface> interfaces = vmNetworkInterfaceDao.getAllForVm(vm.getId()); vm.setInterfaces(interfaces); List<DiskImage> disks = diskImageDao.getAllSnapshotsForVmSnapshot(snapshotId); vm.setImages(new ArrayList<>(disks)); // OvfReader sets disks as active during import which is required by VmHandler.updateDisksForVm to prepare the // VM disks. for (DiskImage currDisk : disks) { currDisk.setActive(true); } return vm; } /** * Gets all images for the VM as stored in DB. Checks if the images stored in the configuration are stored in DB by * comparing Guids. If an image exists in the configuration but does not exist in DB, mark it as illegal (This * scenario might happen when one erases a disk after performing a snapshot). * * @param vm * VM to mark illegal images for * @param snapshotId * The relevant snapshot ID */ protected void markImagesIllegalIfNotInDb(VM vm, Guid snapshotId) { List<DiskImage> imagesInDb = diskImageDao.getAllSnapshotsForVmSnapshot(snapshotId); // Converts to a map of Id to DiskImage in order to check existence only by Image ID (in case not all // image data is written to OVF Map<Guid, DiskImage> imagesInDbMap = ImagesHandler.getDiskImagesByIdMap(imagesInDb); for (DiskImage fromConfigImg : vm.getImages()) { if (fromConfigImg.getDiskStorageType() == DiskStorageType.IMAGE && !imagesInDbMap.containsKey(fromConfigImg.getImageId())) { log.debug("Image '{}' of Disk '{}' cannot be found in database. This image will be returned as ILLEGAL from the query", fromConfigImg.getImageId(), fromConfigImg.getId()); fromConfigImg.setImageStatus(ImageStatus.ILLEGAL); } else { // Return image status as appears in DB (needed in case status is ILLEGAL in DB) DiskImage imageInDb = imagesInDbMap.get(fromConfigImg.getImageId()); fromConfigImg.setImageStatus(imageInDb.getImageStatus()); } } } }