Vered Volansky has uploaded a new change for review. Change subject: core: Removed AddVmAndCloneImageCommand ......................................................................
core: Removed AddVmAndCloneImageCommand This was abstract class, only extended by AddVmFromSnapshotCommand. In the interest of clarity, the two are now squashed together. Change-Id: I3cfbeeef8c15b8747ccb5e123ae171e599290e0b Signed-off-by: Vered Volansky <[email protected]> --- D backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmAndCloneImageCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmFromSnapshotCommand.java 2 files changed, 213 insertions(+), 284 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/72/14572/1 diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmAndCloneImageCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmAndCloneImageCommand.java deleted file mode 100644 index 48fba43..0000000 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmAndCloneImageCommand.java +++ /dev/null @@ -1,259 +0,0 @@ -package org.ovirt.engine.core.bll; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.ovirt.engine.core.bll.job.ExecutionHandler; -import org.ovirt.engine.core.bll.validator.StorageDomainValidator; -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.action.VmManagementParametersBase; -import org.ovirt.engine.core.common.businessentities.CopyVolumeType; -import org.ovirt.engine.core.common.businessentities.Disk; -import org.ovirt.engine.core.common.businessentities.DiskImage; -import org.ovirt.engine.core.common.businessentities.ImageOperation; -import org.ovirt.engine.core.common.businessentities.StorageDomain; -import org.ovirt.engine.core.common.errors.VdcBLLException; -import org.ovirt.engine.core.common.errors.VdcBllErrors; -import org.ovirt.engine.core.compat.Guid; -import org.ovirt.engine.core.dal.dbbroker.DbFacade; - -/** - * This abstract class holds helper methods for concrete command classes that require to add a VM and clone an image in - * the process - * - * @param <T> - */ -public abstract class AddVmAndCloneImageCommand<T extends VmManagementParametersBase> extends AddVmCommand<T> { - - protected AddVmAndCloneImageCommand(Guid commandId) { - super(commandId); - } - - public AddVmAndCloneImageCommand(T parameters) { - super(parameters); - } - - @Override - protected boolean validateIsImagesOnDomains() { - return true; - } - - protected void copyDiskImage( - DiskImage diskImage, - Guid srcStorageDomainId, - Guid destStorageDomainId, - VdcActionType parentCommandType) { - DiskImage newDiskImage = cloneDiskImage(getVmId(), - destStorageDomainId, - Guid.NewGuid(), - Guid.NewGuid(), - diskImage); - ImagesHandler.setDiskAlias(newDiskImage, getVm()); - MoveOrCopyImageGroupParameters parameters = createCopyParameters(newDiskImage, - srcStorageDomainId, - diskImage.getId(), - diskImage.getImageId(), parentCommandType); - VdcReturnValueBase result = executeChildCopyingCommand(parameters); - handleCopyResult(newDiskImage, parameters, result); - } - - @Override - protected void removeVmRelatedEntitiesFromDb() { - removeVmImages(); - super.removeVmRelatedEntitiesFromDb(); - } - - private void removeVmImages() { - // Remove vm images, in case they were not already removed by child commands - List<VdcActionParametersBase> imageParams = getParameters().getImagesParameters(); - if (imageParams != null) { - for (VdcActionParametersBase param : imageParams) { - DiskImage diskImage = getDiskImageToRemoveByParam((MoveOrCopyImageGroupParameters) param); - if (diskImage != null) { - ImagesHandler.removeDiskImage(diskImage, getVmId()); - } - } - } - } - - @Override - protected Collection<DiskImage> getImagesToCheckDestinationStorageDomains() { - return getDiskImagesToBeCloned(); - } - - protected MoveOrCopyImageGroupParameters createCopyParameters(DiskImage diskImage, - Guid srcStorageDomainId, - Guid srcImageGroupId, - Guid srcImageId, VdcActionType parentCommandType) { - MoveOrCopyImageGroupParameters params = - new MoveOrCopyImageGroupParameters(getVmId(), - srcImageGroupId, - srcImageId, - diskImage.getId(), - diskImage.getImageId(), - diskImage.getStorageIds().get(0), - ImageOperation.Copy); - params.setAddImageDomainMapping(false); - params.setCopyVolumeType(CopyVolumeType.LeafVol); - params.setVolumeFormat(diskImage.getVolumeFormat()); - params.setVolumeType(diskImage.getVolumeType()); - params.setUseCopyCollapse(true); - params.setSourceDomainId(srcStorageDomainId); - params.setWipeAfterDelete(diskImage.isWipeAfterDelete()); - params.setEntityId(getVmId()); - params.setParentParameters(getParameters()); - params.setParentCommand(parentCommandType); - return params; - } - - @Override - protected boolean canDoAction() { - boolean retValue = false; - if (super.canDoAction()) { - for (DiskImage diskImage : getDiskImagesToBeCloned()) { - retValue = checkImageConfiguration(diskImage); - if (!retValue) { - break; - } - } - retValue = true; - } - return retValue; - } - - protected abstract boolean checkImageConfiguration(DiskImage diskImage); - - protected DiskImage cloneDiskImage(Guid newVmId, - Guid storageDomainId, - Guid newImageGroupId, - Guid newImageGuid, - DiskImage srcDiskImage) { - DiskImage retDiskImage = DiskImage.copyOf(srcDiskImage); - retDiskImage.setImageId(newImageGuid); - retDiskImage.setParentId(Guid.Empty); - retDiskImage.setImageTemplateId(Guid.Empty); - retDiskImage.setVmSnapshotId(getVmSnapshotId()); - retDiskImage.setId(newImageGroupId); - retDiskImage.setLastModifiedDate(new Date()); - retDiskImage.setvolumeFormat(srcDiskImage.getVolumeFormat()); - retDiskImage.setVolumeType(srcDiskImage.getVolumeType()); - ArrayList<Guid> storageIds = new ArrayList<Guid>(); - storageIds.add(storageDomainId); - retDiskImage.setStorageIds(storageIds); - return retDiskImage; - } - - /** - * Handle the result of copying the image - * - * @param copiedDiskImage - * disk image that represents the copied image at VDSM - * @param parameters - * parameters for the child command that executes the copy at VDSM - * @param result - * result of execution of child command - */ - protected void handleCopyResult(DiskImage copiedDiskImage, - VdcActionParametersBase parameters, - VdcReturnValueBase result) { - // If a copy cannot be made, abort - if (!result.getSucceeded()) { - throw new VdcBLLException(VdcBllErrors.VolumeCreationError); - } else { - ImagesHandler.addDiskImageWithNoVmDevice(copiedDiskImage); - getTaskIdList().addAll(result.getInternalTaskIdList()); - newDiskImages.add(copiedDiskImage); - } - } - - /** - * Executes the child command responsible for the image copying - * @param parameters - * parameters for copy - * @return - */ - protected VdcReturnValueBase executeChildCopyingCommand(VdcActionParametersBase parameters) { - VdcReturnValueBase result = Backend.getInstance().runInternalAction( - getChildActionType(), - parameters, - ExecutionHandler.createDefaultContexForTasks(getExecutionContext())); - return result; - } - - @Override - protected boolean buildAndCheckDestStorageDomains() { - if (diskInfoDestinationMap.isEmpty()) { - List<StorageDomain> domains = - DbFacade.getInstance() - .getStorageDomainDao() - .getAllForStoragePool(getStoragePoolId().getValue()); - Map<Guid, StorageDomain> storageDomainsMap = new HashMap<Guid, StorageDomain>(); - for (StorageDomain storageDomain : domains) { - StorageDomainValidator validator = new StorageDomainValidator(storageDomain); - if (validate(validator.isDomainExistAndActive()) && validate(validator.domainIsValidDestination())) { - storageDomainsMap.put(storageDomain.getId(), storageDomain); - } - } - for (Disk disk : getDiskImagesToBeCloned()) { - DiskImage image = (DiskImage) disk; - for (Guid storageId : image.getStorageIds()) { - if (storageDomainsMap.containsKey(storageId)) { - diskInfoDestinationMap.put(image.getId(), image); - break; - } - } - } - if (getDiskImagesToBeCloned().size() != diskInfoDestinationMap.size()) { - logErrorOneOrMoreActiveDomainsAreMissing(); - return false; - } - List<Guid> storageDomainDest = new ArrayList<Guid>(); - for (DiskImage diskImage : diskInfoDestinationMap.values()) { - Guid storageDomainId = diskImage.getStorageIds().get(0); - if (storageDomainDest.contains(storageDomainId)) { - destStorages.put(storageDomainId, storageDomainsMap.get(storageDomainId)); - } - storageDomainDest.add(storageDomainId); - } - return true; - } - return super.buildAndCheckDestStorageDomains(); - } - - /** - * Logs error if one or more active domains are missing for disk images - */ - protected abstract void logErrorOneOrMoreActiveDomainsAreMissing(); - - /** - * Returns collection of DiskImage objects to use for construction of the imageTODestionationDomainMap - * - * @return - */ - protected abstract Collection<DiskImage> getDiskImagesToBeCloned(); - - protected DiskImage getDiskImageToRemoveByParam(MoveOrCopyImageGroupParameters param) { - Guid imageGroupId = param.getDestImageGroupId(); - Guid imageId = param.getDestinationImageId(); - DiskImage diskImage = new DiskImage(); - diskImage.setId(imageGroupId); - diskImage.setImageId(imageId); - return diskImage; - } - - @Override - protected void executeVmCommand() { - super.executeVmCommand(); - setVm(null); - getVm().setVmtGuid(VmTemplateHandler.BlankVmTemplateId); - getVmStaticDao().update(getVm().getStaticData()); - } - -} diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmFromSnapshotCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmFromSnapshotCommand.java index 1319a54..35b7451 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmFromSnapshotCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmFromSnapshotCommand.java @@ -3,25 +3,38 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; +import org.ovirt.engine.core.bll.job.ExecutionHandler; import org.ovirt.engine.core.bll.snapshots.SnapshotsValidator; import org.ovirt.engine.core.bll.utils.PermissionSubject; import org.ovirt.engine.core.bll.utils.VmDeviceUtils; import org.ovirt.engine.core.bll.validator.DiskImagesValidator; +import org.ovirt.engine.core.bll.validator.StorageDomainValidator; import org.ovirt.engine.core.bll.validator.VmValidator; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.AddVmFromSnapshotParameters; +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.businessentities.CopyVolumeType; +import org.ovirt.engine.core.common.businessentities.Disk; import org.ovirt.engine.core.common.businessentities.DiskImage; +import org.ovirt.engine.core.common.businessentities.ImageOperation; import org.ovirt.engine.core.common.businessentities.ImageStatus; import org.ovirt.engine.core.common.businessentities.Snapshot; import org.ovirt.engine.core.common.businessentities.Snapshot.SnapshotStatus; +import org.ovirt.engine.core.common.businessentities.StorageDomain; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.network.VmNetworkInterface; +import org.ovirt.engine.core.common.errors.VdcBLLException; +import org.ovirt.engine.core.common.errors.VdcBllErrors; import org.ovirt.engine.core.common.locks.LockingGroup; import org.ovirt.engine.core.common.queries.GetVmConfigurationBySnapshotQueryParams; import org.ovirt.engine.core.common.queries.VdcQueryReturnValue; @@ -43,7 +56,7 @@ @DisableInPrepareMode @LockIdNameAttribute @NonTransactiveCommandAttribute(forceCompensation = true) -public class AddVmFromSnapshotCommand<T extends AddVmFromSnapshotParameters> extends AddVmAndCloneImageCommand<T> { +public class AddVmFromSnapshotCommand<T extends AddVmFromSnapshotParameters> extends AddVmCommand<T> { private Guid sourceSnapshotId; private Snapshot snapshot; @@ -115,9 +128,9 @@ protected boolean addVmImages() { int numberOfStartedCopyTasks = 0; try { - if (!getDiskImagesFromConfiguration().isEmpty()) { + if (!getImagesToCheckDestinationStorageDomains().isEmpty()) { lockEntities(); - for (DiskImage diskImage : getDiskImagesFromConfiguration()) { + for (DiskImage diskImage : getImagesToCheckDestinationStorageDomains()) { // For illegal image check if it was snapshot as illegal (therefore // still exists at DB, or was it erased after snapshot - therefore the // query returned to UI an illegal image) @@ -149,15 +162,114 @@ return true; } + private void copyDiskImage( + DiskImage diskImage, + Guid srcStorageDomainId, + Guid destStorageDomainId, + VdcActionType parentCommandType) { + DiskImage newDiskImage = cloneDiskImage(getVmId(), + destStorageDomainId, + Guid.NewGuid(), + Guid.NewGuid(), + diskImage); + ImagesHandler.setDiskAlias(newDiskImage, getVm()); + MoveOrCopyImageGroupParameters parameters = createCopyParameters(newDiskImage, + srcStorageDomainId, + diskImage.getId(), + diskImage.getImageId(), parentCommandType); + VdcReturnValueBase result = executeChildCopyingCommand(parameters); + handleCopyResult(newDiskImage, parameters, result); + } + + private MoveOrCopyImageGroupParameters createCopyParameters(DiskImage diskImage, + Guid srcStorageDomainId, + Guid srcImageGroupId, + Guid srcImageId, VdcActionType parentCommandType) { + MoveOrCopyImageGroupParameters params = + new MoveOrCopyImageGroupParameters(getVmId(), + srcImageGroupId, + srcImageId, + diskImage.getId(), + diskImage.getImageId(), + diskImage.getStorageIds().get(0), + ImageOperation.Copy); + params.setAddImageDomainMapping(false); + params.setCopyVolumeType(CopyVolumeType.LeafVol); + params.setVolumeFormat(diskImage.getVolumeFormat()); + params.setVolumeType(diskImage.getVolumeType()); + params.setUseCopyCollapse(true); + params.setSourceDomainId(srcStorageDomainId); + params.setWipeAfterDelete(diskImage.isWipeAfterDelete()); + params.setEntityId(getVmId()); + params.setParentParameters(getParameters()); + params.setParentCommand(parentCommandType); + return params; + } + @Override - protected DiskImage cloneDiskImage(Guid newVmId, + protected void executeVmCommand() { + super.executeVmCommand(); + setVm(null); + getVm().setVmtGuid(VmTemplateHandler.BlankVmTemplateId); + getVmStaticDao().update(getVm().getStaticData()); + } + + /** + * Executes the child command responsible for the image copying + * @param parameters + * parameters for copy + * @return + */ + private VdcReturnValueBase executeChildCopyingCommand(VdcActionParametersBase parameters) { + VdcReturnValueBase result = Backend.getInstance().runInternalAction( + getChildActionType(), + parameters, + ExecutionHandler.createDefaultContexForTasks(getExecutionContext())); + return result; + } + + /** + * Handle the result of copying the image + * + * @param copiedDiskImage + * disk image that represents the copied image at VDSM + * @param parameters + * parameters for the child command that executes the copy at VDSM + * @param result + * result of execution of child command + */ + private void handleCopyResult(DiskImage copiedDiskImage, + VdcActionParametersBase parameters, + VdcReturnValueBase result) { + // If a copy cannot be made, abort + if (!result.getSucceeded()) { + throw new VdcBLLException(VdcBllErrors.VolumeCreationError); + } else { + ImagesHandler.addDiskImageWithNoVmDevice(copiedDiskImage); + getTaskIdList().addAll(result.getInternalTaskIdList()); + newDiskImages.add(copiedDiskImage); + } + } + + private DiskImage cloneDiskImage(Guid newVmId, Guid storageDomainId, Guid newImageGroupId, Guid newImageGuid, DiskImage srcDiskImage) { - DiskImage clonedDiskImage = - super.cloneDiskImage(newVmId, storageDomainId, newImageGroupId, newImageGuid, srcDiskImage); + DiskImage clonedDiskImage = DiskImage.copyOf(srcDiskImage); + clonedDiskImage.setImageId(newImageGuid); + clonedDiskImage.setParentId(Guid.Empty); + clonedDiskImage.setImageTemplateId(Guid.Empty); + clonedDiskImage.setVmSnapshotId(getVmSnapshotId()); + clonedDiskImage.setId(newImageGroupId); + clonedDiskImage.setLastModifiedDate(new Date()); + clonedDiskImage.setvolumeFormat(srcDiskImage.getVolumeFormat()); + clonedDiskImage.setVolumeType(srcDiskImage.getVolumeType()); + ArrayList<Guid> storageIds = new ArrayList<Guid>(); + storageIds.add(storageDomainId); + clonedDiskImage.setStorageIds(storageIds); + // If volume information was changed at client , use its volume information. // If volume information was not changed at client - use the volume information of the ancestral image if (diskInfoDestinationMap != null && diskInfoDestinationMap.containsKey(srcDiskImage.getId())) { @@ -185,7 +297,13 @@ clonedDiskImage.setVolumeType(diskImageFromClient.getVolumeType()); } - protected Collection<DiskImage> getDiskImagesFromConfiguration() { + private void logErrorOneOrMoreActiveDomainsAreMissing() { + log.errorFormat("Can not found any default active domain for one of the disks of snapshot with id : {0}", + sourceSnapshotId); + } + + @Override + protected Collection<DiskImage> getImagesToCheckDestinationStorageDomains() { if (diskImagesFromConfiguration == null) { diskImagesFromConfiguration = ImagesHandler.filterImageDisks(vmFromConfiguration.getDiskMap().values(), @@ -193,17 +311,6 @@ true); } return diskImagesFromConfiguration; - } - - @Override - protected void logErrorOneOrMoreActiveDomainsAreMissing() { - log.errorFormat("Can not found any default active domain for one of the disks of snapshot with id : {0}", - sourceSnapshotId); - } - - @Override - protected Collection<DiskImage> getDiskImagesToBeCloned() { - return getDiskImagesFromConfiguration(); } private void saveIllegalDisk(final DiskImage diskImage) { @@ -248,6 +355,34 @@ unlockEntities(); } + @Override + protected void removeVmRelatedEntitiesFromDb() { + removeVmImages(); + super.removeVmRelatedEntitiesFromDb(); + } + + private void removeVmImages() { + // Remove vm images, in case they were not already removed by child commands + List<VdcActionParametersBase> imageParams = getParameters().getImagesParameters(); + if (imageParams != null) { + for (VdcActionParametersBase param : imageParams) { + DiskImage diskImage = getDiskImageToRemoveByParam((MoveOrCopyImageGroupParameters) param); + if (diskImage != null) { + ImagesHandler.removeDiskImage(diskImage, getVmId()); + } + } + } + } + + private DiskImage getDiskImageToRemoveByParam(MoveOrCopyImageGroupParameters param) { + Guid imageGroupId = param.getDestImageGroupId(); + Guid imageId = param.getDestinationImageId(); + DiskImage diskImage = new DiskImage(); + diskImage.setId(imageGroupId); + diskImage.setImageId(imageId); + return diskImage; + } + protected Snapshot getSnapshot() { if (snapshot == null) { snapshot = getSnapshotDao().get(sourceSnapshotId); @@ -260,7 +395,7 @@ @Override protected boolean canDoAction() { - SnapshotsValidator snapshotsValidator = new SnapshotsValidator(); + SnapshotsValidator snapshotsValidator = createSnapshotsValidator(); // If snapshot does not exist or is broken, there is not point in checking any of the VM related checks if (!validate(snapshotsValidator.snapshotExists(getSnapshot())) @@ -289,11 +424,65 @@ return false; } - // Run all checks for AddVm, now that it is determined snapshot exists - if (!super.canDoAction()) { - return false; + for (DiskImage diskImage : getImagesToCheckDestinationStorageDomains()) { + if (!checkImageConfiguration(diskImage)) { + return false; + } } + // Run all checks for AddVm, now that it is determined snapshot exists + return super.canDoAction(); + } + + protected SnapshotsValidator createSnapshotsValidator() { + return new SnapshotsValidator(); + } + + @Override + protected boolean buildAndCheckDestStorageDomains() { + if (diskInfoDestinationMap.isEmpty()) { + List<StorageDomain> domains = + getStorageDomainDAO().getAllForStoragePool(getStoragePoolId().getValue()); + Map<Guid, StorageDomain> storageDomainsMap = new HashMap<Guid, StorageDomain>(); + for (StorageDomain storageDomain : domains) { + StorageDomainValidator validator = new StorageDomainValidator(storageDomain); + if (validate(validator.isDomainExistAndActive()) && validate(validator.domainIsValidDestination())) { + storageDomainsMap.put(storageDomain.getId(), storageDomain); + } + } + + for (Disk disk : getImagesToCheckDestinationStorageDomains()) { + DiskImage image = (DiskImage) disk; + for (Guid storageId : image.getStorageIds()) { + if (storageDomainsMap.containsKey(storageId)) { + diskInfoDestinationMap.put(image.getId(), image); + break; + } + } + } + + if (getImagesToCheckDestinationStorageDomains().size() != diskInfoDestinationMap.size()) { + logErrorOneOrMoreActiveDomainsAreMissing(); + return false; + } + + List<Guid> storageDomainDest = new ArrayList<Guid>(); + for (DiskImage diskImage : diskInfoDestinationMap.values()) { + Guid storageDomainId = diskImage.getStorageIds().get(0); + if (storageDomainDest.contains(storageDomainId)) { + destStorages.put(storageDomainId, storageDomainsMap.get(storageDomainId)); + } + storageDomainDest.add(storageDomainId); + } + + return true; + } + + return super.buildAndCheckDestStorageDomains(); + } + + @Override + protected boolean validateIsImagesOnDomains() { return true; } @@ -313,7 +502,7 @@ // Get the needed disk size by accumulating disk size // of images on a given storage domain int result = 0; - for (DiskImage img : getDiskImagesFromConfiguration()) { + for (DiskImage img : getImagesToCheckDestinationStorageDomains()) { if (img.getImageStatus() != ImageStatus.ILLEGAL) { if (img.getStorageIds().get(0).getValue().equals(storageDomainId)) { result = result + (int) Math.ceil(img.getActualSize()); @@ -344,8 +533,7 @@ freeLock(); } - @Override - protected boolean checkImageConfiguration(DiskImage diskImage) { + private boolean checkImageConfiguration(DiskImage diskImage) { return ImagesHandler.CheckImageConfiguration(destStorages.get(diskInfoDestinationMap.get(diskImage.getId()) .getStorageIds() .get(0)) -- To view, visit http://gerrit.ovirt.org/14572 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I3cfbeeef8c15b8747ccb5e123ae171e599290e0b Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Vered Volansky <[email protected]> _______________________________________________ Engine-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/engine-patches
