package org.ovirt.engine.core.bll; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.ovirt.engine.core.bll.command.utils.StorageDomainSpaceChecker; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.ImprotVmTemplateParameters; import org.ovirt.engine.core.common.action.MoveOrCopyImageGroupParameters; 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.DiskImage; import org.ovirt.engine.core.common.businessentities.DiskImageDynamic; import org.ovirt.engine.core.common.businessentities.DiskImageTemplate; import org.ovirt.engine.core.common.businessentities.StorageDomainType; import org.ovirt.engine.core.common.businessentities.StorageType; import org.ovirt.engine.core.common.businessentities.VmNetworkInterface; import org.ovirt.engine.core.common.businessentities.VmNetworkStatistics; import org.ovirt.engine.core.common.businessentities.VmTemplate; import org.ovirt.engine.core.common.businessentities.VmTemplateStatus; import org.ovirt.engine.core.common.businessentities.VolumeFormat; import org.ovirt.engine.core.common.businessentities.VolumeType; import org.ovirt.engine.core.common.businessentities.storage_domain_static; import org.ovirt.engine.core.common.errors.VdcBLLException; import org.ovirt.engine.core.common.errors.VdcBllErrors; import org.ovirt.engine.core.common.queries.DiskImageList; import org.ovirt.engine.core.common.queries.GetAllFromExportDomainQueryParamenters; import org.ovirt.engine.core.common.queries.VdcQueryReturnValue; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.VdcBllMessages; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.dao.StorageDomainStaticDAO; import org.ovirt.engine.core.utils.linq.LinqUtils; import org.ovirt.engine.core.utils.linq.Predicate; import org.ovirt.engine.core.utils.transaction.TransactionMethod; import org.ovirt.engine.core.utils.transaction.TransactionSupport; @NonTransactiveCommandAttribute(forceCompensation = true) public class ImportVmTemplateCommand<T extends ImprotVmTemplateParameters> extends MoveOrCopyTemplateCommand<T> { final int BYTE_TO_GB_FACTOR = 1073741824; public ImportVmTemplateCommand(T parameters) { super(parameters); setVmTemplate(parameters.getVmTemplate()); parameters.setEntityId(getVmTemplate().getId()); setStoragePoolId(parameters.getStoragePoolId()); setVdsGroupId(parameters.getVdsGroupId()); } protected ImportVmTemplateCommand(Guid commandId) { super(commandId); } @Override protected boolean canDoAction() { boolean retVal = true; // Set the template images from the Export domain and change each image // id storage is to the import domain if (retVal) { GetAllFromExportDomainQueryParamenters tempVar = new GetAllFromExportDomainQueryParamenters(getParameters() .getStoragePoolId(), getParameters().getSourceDomainId()); tempVar.setGetAll(true); VdcQueryReturnValue qretVal = getBackend().runInternalQuery( VdcQueryType.GetTemplatesFromExportDomain, tempVar); if (qretVal.getSucceeded()) { Map<VmTemplate, DiskImageList> templates = (Map) qretVal.getReturnValue(); // java.util.ArrayList<DiskImage> images = null; //LINQ // templates.FirstOrDefault(t => t.Key.vmt_guid == // ImprotVmTemplateParameters.VmTemplate.vmt_guid).Value; DiskImageList images = templates.get(LinqUtils.firstOrNull(templates.keySet(), new Predicate<VmTemplate>() { @Override public boolean eval(VmTemplate t) { return t.getId().equals(getParameters().getVmTemplate().getId()); } })); List<DiskImage> list = Arrays.asList(images.getDiskImages()); getParameters().setImages(list); storage_domain_static storageDomain = getStorageDomainStaticDAO().get(getParameters().getDestDomainId()); Map<String, DiskImage> imageMap = new HashMap<String, DiskImage>(); for (DiskImage image : list) { changeRawToCowIfSparseOnBlockDevice(storageDomain.getstorage_type(), image); retVal = ImagesHandler.CheckImageConfiguration(storageDomain, image, getReturnValue().getCanDoActionMessages()); if (!retVal) { break; } else { image.setstorage_pool_id(getParameters().getStoragePoolId()); image.setstorage_id(getParameters().getSourceDomainId()); imageMap.put(image.getId().toString(), image); } } getVmTemplate().setDiskImageMap(imageMap); } } if (getVmTemplate() == null) { retVal = false; } else { setDescription(getVmTemplateName()); } if (retVal) { VmTemplate duplicateTemplate = getVmTemplateDAO() .get(getParameters().getVmTemplate().getId()); // check that the template does not exists in the target domain if (duplicateTemplate != null) { addCanDoActionMessage(VdcBllMessages.VMT_CANNOT_IMPORT_TEMPLATE_EXISTS); getReturnValue().getCanDoActionMessages().add( String.format("$TemplateName %1$s", duplicateTemplate.getname())); retVal = false; } else if (VmTemplateCommand.isVmTemlateWithSameNameExist(getParameters().getVmTemplate().getname())) { addCanDoActionMessage(VdcBllMessages.VM_CANNOT_IMPORT_TEMPLATE_NAME_EXISTS); retVal = false; } } // check that the source domain is valid if (retVal) { retVal = ImportExportCommon.CheckStorageDomain(getParameters().getSourceDomainId(), getReturnValue() .getCanDoActionMessages()); } // check that the destination domain is valid if (retVal) { retVal = ImportExportCommon.CheckStorageDomain(getParameters().getDestDomainId(), getReturnValue() .getCanDoActionMessages()); } // check that the storage pool is valid if (retVal) { retVal = ImportExportCommon.CheckStoragePool(getParameters().getStoragePoolId(), getReturnValue() .getCanDoActionMessages()); } // check that template has images if (retVal) { if (getParameters().getImages() == null || getParameters().getImages().size() <= 0) { retVal = false; addCanDoActionMessage(VdcBllMessages.TEMPLATE_IMAGE_NOT_EXIST); } } // check if domains are active if (retVal) { retVal = (IsDomainActive(getParameters().getSourceDomainId(), getParameters().getStoragePoolId()) && IsDomainActive( getParameters().getDestDomainId(), getParameters().getStoragePoolId())); } // check that the destination domain is not ISO and not Export domain if (retVal) { if (getStorageDomain().getstorage_domain_type() == StorageDomainType.ISO || getStorageDomain().getstorage_domain_type() == StorageDomainType.ImportExport) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_ILLEGAL); retVal = false; } } // set the source domain and check that it is ImportExport type if (retVal) { SetSourceDomainId(getParameters().getSourceDomainId()); if (getSourceDomain() == null) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_EXIST); retVal = false; } if (getSourceDomain().getstorage_domain_type() != StorageDomainType.ImportExport) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_ILLEGAL); retVal = false; } } if (retVal) { int sz = 0; if (getVmTemplate().getDiskImageMap() != null) { for (DiskImage image : getVmTemplate().getDiskImageMap().values()) { sz += image.getsize(); } } int sizeInGB = sz / BYTE_TO_GB_FACTOR; retVal = StorageDomainSpaceChecker.hasSpaceForRequest(getStorageDomain(), sizeInGB); if (!retVal) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_DISK_SPACE_LOW); } } if (!retVal) { addCanDoActionMessage(VdcBllMessages.VAR__ACTION__IMPORT); addCanDoActionMessage(VdcBllMessages.VAR__TYPE__VM_TEMPLATE); } return retVal; } /** * 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 cheange if needed. */ private void changeRawToCowIfSparseOnBlockDevice(StorageType storageType, DiskImage image) { if ((storageType == StorageType.FCP || storageType == StorageType.ISCSI) && image.getvolume_format() == VolumeFormat.RAW && image.getvolume_type() == VolumeType.Sparse) { image.setvolume_format(VolumeFormat.COW); } } protected StorageDomainStaticDAO getStorageDomainStaticDAO() { return DbFacade.getInstance().getStorageDomainStaticDAO(); } @Override protected void executeCommand() { TransactionSupport.executeInNewTransaction(new TransactionMethod<Void>() { @Override public Void runInTransaction() { AddVmTemplateToDb(); AddVmInterfaces(); getCompensationContext().stateChanged(); return null; } }); MoveOrCopyAllImageGroups(getVmTemplateId(), getParameters().getImages()); setSucceeded(true); } @Override protected void MoveOrCopyAllImageGroups(final Guid containerID, final Iterable<DiskImage> disks) { TransactionSupport.executeInNewTransaction(new TransactionMethod<Void>() { @Override public Void runInTransaction() { for (DiskImage disk : disks) { MoveOrCopyImageGroupParameters tempVar = new MoveOrCopyImageGroupParameters(containerID, disk .getimage_group_id().getValue(), disk.getId(), getParameters().getStorageDomainId(), getMoveOrCopyImageOperation()); tempVar.setParentCommand(getActionType()); tempVar.setEntityId(getParameters().getEntityId()); tempVar.setUseCopyCollapse(true); tempVar.setVolumeType(disk.getvolume_type()); tempVar.setVolumeFormat(disk.getvolume_format()); tempVar.setCopyVolumeType(CopyVolumeType.SharedVol); tempVar.setPostZero(disk.getwipe_after_delete()); tempVar.setForceOverride(true); MoveOrCopyImageGroupParameters p = tempVar; p.setParentParemeters(getParameters()); VdcReturnValueBase vdcRetValue = Backend.getInstance().runInternalAction( VdcActionType.MoveOrCopyImageGroup, p); if (!vdcRetValue.getSucceeded()) { throw ((vdcRetValue.getFault() != null) ? new VdcBLLException(vdcRetValue.getFault().getError()) : new VdcBLLException(VdcBllErrors.ENGINE)); } getParameters().getImagesParameters().add(p); getReturnValue().getTaskIdList().addAll(vdcRetValue.getInternalTaskIdList()); } return null; } }); } protected void AddVmTemplateToDb() { getVmTemplate().setvds_group_id(getParameters().getVdsGroupId()); getVmTemplate().setstatus(VmTemplateStatus.Locked); DbFacade.getInstance().getVmTemplateDAO().save(getVmTemplate()); getCompensationContext().snapshotNewEntity(getVmTemplate()); for (DiskImage image : getParameters().getImages()) { DiskImageTemplate dt = new DiskImageTemplate(image.getId(), getParameters().getVmTemplate() .getId(), image.getinternal_drive_mapping(), image.getId(), "", "", getNow(), image.getsize(), image.getdescription(), null); DbFacade.getInstance().getDiskImageDAO().save(image); DbFacade.getInstance().getDiskImageTemplateDAO().save(dt); getCompensationContext().snapshotNewEntity(image); getCompensationContext().snapshotNewEntity(dt); DiskImageDynamic diskDynamic = new DiskImageDynamic(); diskDynamic.setId(image.getId()); diskDynamic.setactual_size(image.getactual_size()); DbFacade.getInstance().getDiskImageDynamicDAO().save(diskDynamic); getCompensationContext().snapshotNewEntity(diskDynamic); } } protected void AddVmInterfaces() { List<VmNetworkInterface> interfaces = getVmTemplate().getInterfaces(); for (VmNetworkInterface iface : interfaces) { VmNetworkInterface iDynamic = new VmNetworkInterface(); VmNetworkStatistics iStat = new VmNetworkStatistics(); iDynamic.setStatistics(iStat); iDynamic.setId(Guid.NewGuid()); iStat.setId(iDynamic.getId()); iDynamic.setVmTemplateId(getVmTemplateId()); // TODO why does a VM interface get VDS details? // iDynamic.setAddress(iface.getInterfaceDynamic().getAddress()); // iDynamic.setBondName(iface.getInterfaceDynamic().getBondName()); // iDynamic.setBondType(iface.getInterfaceDynamic().getBondType()); // iDynamic.setGateway(iface.getInterfaceDynamic().getGateway()); iDynamic.setName(iface.getName()); iDynamic.setNetworkName(iface.getNetworkName()); iDynamic.setSpeed(iface.getSpeed()); // iDynamic.setSubnet(iface.getInterfaceDynamic().getSubnet()); iDynamic.setType(iface.getType()); DbFacade.getInstance().getVmNetworkInterfaceDAO().save(iDynamic); getCompensationContext().snapshotNewEntity(iDynamic); DbFacade.getInstance().getVmNetworkStatisticsDAO().save(iStat); getCompensationContext().snapshotNewEntity(iStat); } } @Override protected void EndMoveOrCopyCommand() { VmTemplateHandler.UnLockVmTemplate(getVmTemplateId()); EndActionOnAllImageGroups(); UpdateTemplateInSpm(); setSucceeded(true); } protected void RemoveNetwork() { List<VmNetworkInterface> list = DbFacade.getInstance().getVmNetworkInterfaceDAO().getAllForTemplate(getVmTemplateId()); for (VmNetworkInterface iface : list) { DbFacade.getInstance().getVmNetworkInterfaceDAO().remove(iface.getId()); } } protected void RemoveImages() { for (DiskImage image : getParameters().getImages()) { DbFacade.getInstance().getDiskImageDynamicDAO().remove(image.getId()); DbFacade.getInstance().getDiskImageTemplateDAO().remove(image.getId()); DbFacade.getInstance().getDiskImageDAO().remove(image.getId()); } } @Override protected void EndWithFailure() { RemoveNetwork(); RemoveImages(); DbFacade.getInstance().getVmTemplateDAO().remove(getVmTemplateId()); setSucceeded(true); } @Override protected void UpdateTemplateInSpm() { VmTemplateCommand.UpdateTemplateInSpm(getParameters().getStoragePoolId(), new java.util.ArrayList<VmTemplate>( java.util.Arrays.asList(new VmTemplate[] { getParameters().getVmTemplate() })), Guid.Empty, getParameters().getImages()); } @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; } return super.getAuditLogTypeValue(); } }