package org.ovirt.engine.core.bll.storage.disk.image; import java.io.IOException; import java.util.List; import javax.inject.Inject; import org.apache.commons.codec.DecoderException; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.bll.QueriesCommandBase; import org.ovirt.engine.core.bll.context.EngineContext; import org.ovirt.engine.core.common.FeatureSupported; import org.ovirt.engine.core.common.action.GetCinderEntityByStorageDomainIdParameters; import org.ovirt.engine.core.common.businessentities.StorageDomain; import org.ovirt.engine.core.common.businessentities.StoragePool; import org.ovirt.engine.core.common.businessentities.storage.DiskImage; import org.ovirt.engine.core.common.businessentities.storage.QemuImageInfo; import org.ovirt.engine.core.common.businessentities.storage.VolumeFormat; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.queries.GetUnregisteredDiskQueryParameters; import org.ovirt.engine.core.common.queries.VdcQueryReturnValue; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.common.vdscommands.GetImageInfoVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.StoragePoolDomainAndGroupIdBaseVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.StorageDomainDao; import org.ovirt.engine.core.dao.StoragePoolDao; public class GetUnregisteredDiskQuery<P extends GetUnregisteredDiskQueryParameters> extends QueriesCommandBase<P> { @Inject private StorageDomainDao storageDomainDao; @Inject private StoragePoolDao storagePoolDao; public GetUnregisteredDiskQuery(P parameters) { super(parameters); } public GetUnregisteredDiskQuery(P parameters, EngineContext context) { super(parameters, context); } @Override protected void executeQueryCommand() { Guid storagePoolId = getParameters().getStoragePoolId(); Guid storageDomainId = getParameters().getStorageDomainId(); Guid diskId = getParameters().getDiskId(); StorageDomain storageDomain = storageDomainDao.get(storageDomainId); if (storageDomain == null) { getQueryReturnValue().setExceptionString(EngineMessage.STORAGE_DOMAIN_DOES_NOT_EXIST.toString()); getQueryReturnValue().setSucceeded(false); return; } if (storageDomain.getStorageType().isCinderDomain()) { VdcQueryReturnValue returnValue = runInternalQuery(VdcQueryType.GetUnregisteredCinderDiskByIdAndStorageDomainId, new GetCinderEntityByStorageDomainIdParameters(diskId, getParameters().getStorageDomainId())); setReturnValue(returnValue.getReturnValue()); return; } // Now get the list of volumes for each new image. StoragePoolDomainAndGroupIdBaseVDSCommandParameters getVolumesParameters = new StoragePoolDomainAndGroupIdBaseVDSCommandParameters( storagePoolId, storageDomainId, diskId); VDSReturnValue volumesListReturn = runVdsCommand(VDSCommandType.GetVolumesList, getVolumesParameters); if (!volumesListReturn.getSucceeded()) { getQueryReturnValue().setExceptionString(volumesListReturn.getExceptionString()); getQueryReturnValue().setSucceeded(false); return; } @SuppressWarnings("unchecked") List<Guid> volumesList = (List<Guid>) volumesListReturn.getReturnValue(); // We can't deal with snapshots, so there should only be a single volume associated with the // image. If there are multiple volumes, skip the image and move on to the next. if (volumesList.size() != 1) { getQueryReturnValue().setSucceeded(false); return; } Guid volumeId = volumesList.get(0); // Get the information about the volume from VDSM. GetImageInfoVDSCommandParameters imageInfoParameters = new GetImageInfoVDSCommandParameters( storagePoolId, storageDomainId, diskId, volumeId); VDSReturnValue imageInfoReturn = runVdsCommand(VDSCommandType.GetImageInfo, imageInfoParameters); if (!imageInfoReturn.getSucceeded()) { getQueryReturnValue().setExceptionString(imageInfoReturn.getExceptionString()); getQueryReturnValue().setSucceeded(false); return; } DiskImage newDiskImage = (DiskImage) imageInfoReturn.getReturnValue(); if (!fetchQcowCompat(storagePoolId, storageDomainId, diskId, volumeId, newDiskImage)) { getQueryReturnValue().setSucceeded(false); return; } if (StringUtils.isNotEmpty(newDiskImage.getDescription())) { try { MetadataDiskDescriptionHandler.getInstance() .enrichDiskByJsonDescription(newDiskImage.getDescription(), newDiskImage); } catch (IOException | DecoderException e) { log.warn("Exception while parsing JSON for disk. Exception: '{}'", e); } } newDiskImage.setStoragePoolId(storagePoolId); getQueryReturnValue().setReturnValue(newDiskImage); getQueryReturnValue().setSucceeded(true); } private boolean fetchQcowCompat(Guid storagePoolId, Guid storageDomainId, Guid diskId, Guid volumeId, DiskImage newDiskImage) { if (newDiskImage.getVolumeFormat().equals(VolumeFormat.COW)) { StoragePool sp = storagePoolDao.get(storagePoolId); QemuImageInfo qemuImageInfo = null; if (sp != null && FeatureSupported.qcowCompatSupported(sp.getCompatibilityVersion())) { qemuImageInfo = ImagesHandler.getQemuImageInfoFromVdsm(storagePoolId, storageDomainId, diskId, volumeId, null, true); if (qemuImageInfo == null) { getQueryReturnValue().setExceptionString("Failed to fetch qemu image info from storage"); return false; } newDiskImage.setQcowCompat(qemuImageInfo.getQcowCompat()); } } return true; } }