package org.ovirt.engine.core.bll; import java.util.Collections; 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.VdcObjectType; import org.ovirt.engine.core.common.action.AddVmTemplateParameters; import org.ovirt.engine.core.common.action.CreateImageTemplateParameters; 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.DiskImage; import org.ovirt.engine.core.common.businessentities.VmInterfaceType; import org.ovirt.engine.core.common.businessentities.StorageDomainStatus; import org.ovirt.engine.core.common.businessentities.StorageDomainType; import org.ovirt.engine.core.common.businessentities.VDSGroup; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.common.businessentities.VmDynamic; import org.ovirt.engine.core.common.businessentities.VmNetworkInterface; import org.ovirt.engine.core.common.businessentities.VmTemplate; import org.ovirt.engine.core.common.businessentities.VmTemplateStatus; import org.ovirt.engine.core.common.businessentities.permissions; import org.ovirt.engine.core.common.businessentities.storage_domains; import org.ovirt.engine.core.common.errors.VdcBLLException; import org.ovirt.engine.core.common.errors.VdcBllErrors; import org.ovirt.engine.core.common.validation.group.CreateEntity; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.LogCompat; import org.ovirt.engine.core.compat.LogFactoryCompat; import org.ovirt.engine.core.dal.VdcBllMessages; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.utils.transaction.TransactionMethod; import org.ovirt.engine.core.utils.transaction.TransactionSupport; @NonTransactiveCommandAttribute(forceCompensation = true) public class AddVmTemplateCommand<T extends AddVmTemplateParameters> extends VmTemplateCommand<T> { private final java.util.ArrayList<DiskImage> mImages = new java.util.ArrayList<DiskImage>(); /** * Constructor for command creation when compensation is applied on startup * * @param commandId */ protected AddVmTemplateCommand(Guid commandId) { super(commandId); } public AddVmTemplateCommand(T parameters) { super(parameters); super.setVmId(parameters.getMasterVm().getId()); super.setVmTemplateName(parameters.getName()); setVdsGroupId(parameters.getMasterVm().getvds_group_id()); if (getVm() != null) { VmHandler.updateDisksFromDb(getVm()); } } @Override public AuditLogType getAuditLogTypeValue() { switch (getActionState()) { case EXECUTE: return getSucceeded() ? AuditLogType.USER_ADD_VM_TEMPLATE : AuditLogType.USER_FAILED_ADD_VM_TEMPLATE; case END_SUCCESS: return getSucceeded() ? AuditLogType.USER_ADD_VM_TEMPLATE_FINISHED_SUCCESS : AuditLogType.USER_ADD_VM_TEMPLATE_FINISHED_FAILURE; default: return AuditLogType.USER_ADD_VM_TEMPLATE_FINISHED_FAILURE; } } @Override protected void executeCommand() { // get vm status from db to check its really down before locking VmDynamic vmDynamic = DbFacade.getInstance().getVmDynamicDAO().get(getVmId()); if (vmDynamic.getstatus() != VMStatus.Down) { throw new VdcBLLException(VdcBllErrors.IRS_IMAGE_STATUS_ILLEGAL); } VmHandler.LockVm(vmDynamic, getCompensationContext()); setActionReturnValue(Guid.Empty); setVmTemplateId(Guid.NewGuid()); getParameters().setVmTemplateID(getVmTemplateId()); getParameters().setEntityId(getVmTemplateId()); TransactionSupport.executeInNewTransaction(new TransactionMethod<Void>() { @Override public Void runInTransaction() { AddVmTemplateToDb(); getCompensationContext().stateChanged(); return null; } }); TransactionSupport.executeInNewTransaction(new TransactionMethod<Void>() { @Override public Void runInTransaction() { addPermission(); AddVmTemplateImages(); AddVmInterfaces(); setSucceeded(true); return null; } }); } @Override protected boolean canDoAction() { if (getVdsGroup() == null || !getVm().getstorage_pool_id().equals(getVdsGroup().getstorage_pool_id())) { addCanDoActionMessage(VdcBllMessages.VDS_CLUSTER_IS_NOT_VALID); return false; } for (DiskImage diskImage : getVm().getDiskList()) { mImages.add(diskImage); } if (mImages.isEmpty()) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_HAS_NO_DISKS); return false; } if (!VmHandler.isMemorySizeLegal(getParameters().getMasterVm().getos(), getParameters().getMasterVm().getmem_size_mb(), getReturnValue().getCanDoActionMessages(), getVdsGroup().getcompatibility_version().toString())) { return false; } if (!IsVmPriorityValueLegal(getParameters().getMasterVm().getpriority(), getReturnValue() .getCanDoActionMessages())) { return false; } Guid srcStorageDomainId = mImages.get(0).getstorage_id().getValue(); // get storage from parameters // or populate storage domain id from the vm domain (of the first disk) if (getParameters().getDestinationStorageDomainId() != null) { setStorageDomainId(getParameters().getDestinationStorageDomainId()); } else { setStorageDomainId(srcStorageDomainId); } if (!ImagesHandler.PerformImagesChecks(getParameters().getMasterVm().getId(), getReturnValue().getCanDoActionMessages(), getVm().getstorage_pool_id(), srcStorageDomainId, true, true, true, true, true, false, true)) { return false; } VM vm = DbFacade.getInstance().getVmDAO().getById(getParameters().getMasterVm().getId()); if (vm.getstatus() != VMStatus.Down) { addCanDoActionMessage(VdcBllMessages.VMT_CANNOT_CREATE_TEMPLATE_FROM_DOWN_VM.toString()); return false; } if (isVmTemlateWithSameNameExist(getVmTemplateName())) { addCanDoActionMessage(VdcBllMessages.VMT_CANNOT_CREATE_DUPLICATE_NAME); return false; } if (getStorageDomainId() != null) { storage_domains storage = DbFacade.getInstance().getStorageDomainDAO().getForStoragePool( getStorageDomainId().getValue(), getVm().getstorage_pool_id()); // if source and destination domains are different we need to check destination domain also if (!srcStorageDomainId.equals(getStorageDomainId().getValue())) { if (storage == null) { // if storage is null then we need to check if it doesn't exist or // domain is not in the same storage pool as the vm if (DbFacade.getInstance().getStorageDomainStaticDAO().get(getStorageDomainId().getValue()) == null) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_EXIST.toString()); } else { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_IN_STORAGE_POOL); } return false; } if (storage.getstatus() == null || storage.getstatus() != StorageDomainStatus.Active) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_STATUS_ILLEGAL.toString()); return false; } } if (storage.getstorage_domain_type() == StorageDomainType.ImportExport || storage.getstorage_domain_type() == StorageDomainType.ISO) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_ILLEGAL); return false; } // update vm snapshots for storage free space check for (DiskImage diskImage : getVm().getDiskMap().values()) { diskImage.getSnapshots().addAll( ImagesHandler.getAllImageSnapshots(diskImage.getId(), diskImage.getit_guid())); } if (!StorageDomainSpaceChecker.hasSpaceForRequest(storage, (int) getVm().getActualDiskWithSnapshotsSize())) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_DISK_SPACE_LOW); return false; } } if (!AddVmCommand.CheckCpuSockets(getParameters().getMasterVm().getnum_of_sockets(), getParameters().getMasterVm().getcpu_per_socket(), getVdsGroup() .getcompatibility_version().toString(), getReturnValue().getCanDoActionMessages())) { return false; } return true; } protected void AddVmTemplateToDb() { // TODO: add timezone handling setVmTemplate(new VmTemplate(0, getNow(), getParameters().getDescription(), getParameters().getMasterVm().getmem_size_mb(), getVmTemplateName(), getParameters().getMasterVm().getnum_of_sockets(), getParameters().getMasterVm() .getcpu_per_socket(), getParameters().getMasterVm().getos(), getParameters().getMasterVm().getvds_group_id(), getVmTemplateId(), getParameters().getMasterVm().getdomain(), getParameters().getMasterVm() .getnum_of_monitors(), (VmTemplateStatus.Locked.getValue()), (getParameters().getMasterVm() .getusb_policy().getValue()), getParameters().getMasterVm().gettime_zone(), getParameters().getMasterVm().getis_auto_suspend(), getParameters().getMasterVm() .getnice_level(), getParameters().getMasterVm().getfail_back(), getParameters().getMasterVm().getdefault_boot_sequence(), getParameters() .getMasterVm().getvm_type(), getParameters().getMasterVm().gethypervisor_type(), getParameters().getMasterVm().getoperation_mode())); getVmTemplate().setauto_startup(getParameters().getMasterVm().getauto_startup()); getVmTemplate().setpriority(getParameters().getMasterVm().getpriority()); getVmTemplate().setdefault_display_type(getParameters().getMasterVm().getdefault_display_type()); getVmTemplate().setinitrd_url(getParameters().getMasterVm().getinitrd_url()); getVmTemplate().setkernel_url(getParameters().getMasterVm().getkernel_url()); getVmTemplate().setkernel_params(getParameters().getMasterVm().getkernel_params()); getVmTemplate().setis_stateless(getParameters().getMasterVm().getis_stateless()); DbFacade.getInstance().getVmTemplateDAO().save(getVmTemplate()); getCompensationContext().snapshotNewEntity(getVmTemplate()); setActionReturnValue(getVmTemplate().getId()); } protected void AddVmInterfaces() { List<VmNetworkInterface> interfaces = DbFacade .getInstance() .getVmNetworkInterfaceDAO() .getAllForVm( getParameters().getMasterVm().getId()); for (VmNetworkInterface iface : interfaces) { VmNetworkInterface iDynamic = new VmNetworkInterface(); // \\interface_statistics iStat = new interface_statistics(); iDynamic.setId(Guid.NewGuid()); iDynamic.setVmTemplateId(getVmTemplateId()); // TODO why is a VM interface getting 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(VmInterfaceType.forValue(iface.getType()).getSpeed()); // iDynamic.setSubnet(iface.getInterfaceDynamic().getSubnet()); iDynamic.setType(iface.getType()); DbFacade.getInstance().getVmNetworkInterfaceDAO().save(iDynamic); // \\DbFacade.Instance.addInterfaceStatistics(iStat); } } protected void AddVmTemplateImages() { Guid srcStorageDomain = mImages.get(0).getstorage_id().getValue(); Guid vmSnapshotId = Guid.NewGuid(); for (DiskImage diskImage : mImages) { CreateImageTemplateParameters createParams = new CreateImageTemplateParameters(diskImage.getId(), getVmTemplateId(), getVmTemplateName(), getVmId()); createParams.setStorageDomainId(srcStorageDomain); createParams.setVmSnapshotId(vmSnapshotId); createParams.setEntityId(getParameters().getEntityId()); createParams.setDestinationStorageDomainId(getStorageDomainId().getValue()); createParams.setParentParemeters(getParameters()); getParameters().getImagesParameters().add(createParams); // The return value of this action is the 'copyImage' task GUID: VdcReturnValueBase retValue = Backend.getInstance().runInternalAction( VdcActionType.CreateImageTemplate, createParams); getReturnValue().getTaskIdList().addAll(retValue.getInternalTaskIdList()); } } @Override protected void EndSuccessfully() { setVmTemplateId(getParameters().getVmTemplateId()); // set it to null to reload from db setVmTemplate(null); for (VdcActionParametersBase p : getParameters().getImagesParameters()) { Backend.getInstance().EndAction(VdcActionType.CreateImageTemplate, p); } if (getVmTemplate() != null) { UpdateTemplateInSpm(getVmTemplate().getstorage_pool_id().getValue(), new java.util.ArrayList<VmTemplate>( java.util.Arrays.asList(new VmTemplate[] { getVmTemplate() }))); if (getVm() != null) { VmHandler.UnLockVm(getVm().getvm_guid()); } else { log.warn("AddVmTemplateCommand::EndSuccessfully: Vm is null, cannot unlock Vm"); } VmTemplateHandler.UnLockVmTemplate(getVmTemplateId()); } else { setCommandShouldBeLogged(false); log.warn("AddVmTemplateCommand::EndSuccessfully: VmTemplate is null - not performing full EndAction"); } setSucceeded(true); } @Override protected void EndWithFailure() { // We evaluate 'VmTemplate' so it won't be null in the last 'if' // statement. // (a template without images doesn't exist in the 'vm_template_view'). setVmTemplateId(getParameters().getVmTemplateId()); VmTemplate template = getVmTemplate(); for (VdcActionParametersBase p : getParameters().getImagesParameters()) { Backend.getInstance().EndAction(VdcActionType.CreateImageTemplate, p); } // if template exist in db remove it if (getVmTemplate() != null) { RemoveTemplateInSpm(getVmTemplate().getstorage_pool_id().getValue(), getVmTemplateId()); DbFacade.getInstance().getVmTemplateDAO().remove(getVmTemplateId()); RemoveNetwork(); } if (!getVmId().equals(Guid.Empty) && getVm() != null) { VmHandler.UnLockVm(getVmId()); } setSucceeded(true); } private static LogCompat log = LogFactoryCompat.getLog(AddVmTemplateCommand.class); /** * in case of non-existing cluster the backend query will return a null */ @Override public Map<Guid, VdcObjectType> getPermissionCheckSubjects() { VDSGroup vdsGroup = getVdsGroup(); return Collections.singletonMap(vdsGroup == null || vdsGroup.getstorage_pool_id() == null ? null : vdsGroup .getstorage_pool_id().getValue(), VdcObjectType.StoragePool); } private void addPermission() { // if the template is for public use, set EVERYONE as a TEMPLATE_USER. if (getParameters().isPublicUse()) { permissions perms = new permissions(); perms.setad_element_id(MultiLevelAdministrationHandler.EVERYONE_OBJECT_ID); perms.setObjectType(VdcObjectType.VmTemplate); perms.setObjectId(getParameters().getVmTemplateId()); perms.setrole_id(PredefinedRoles.TEMPLATE_USER.getId()); MultiLevelAdministrationHandler.addPermission(perms); } } @Override protected List<Class<?>> getValidationGroups() { addValidationGroup(CreateEntity.class); return super.getValidationGroups(); } @Override protected void setActionMessageParameters() { addCanDoActionMessage(VdcBllMessages.VAR__ACTION__ADD); addCanDoActionMessage(VdcBllMessages.VAR__TYPE__VM_TEMPLATE); } }