package org.ovirt.engine.core.bll.network.vm; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.bll.network.macpool.MacPool; import org.ovirt.engine.core.bll.utils.PermissionSubject; import org.ovirt.engine.core.bll.validator.VmNicValidator; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.AddVmInterfaceParameters; import org.ovirt.engine.core.common.action.PlugAction; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.network.VmInterfaceType; import org.ovirt.engine.core.common.businessentities.network.VmNic; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.validation.group.CreateEntity; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.Version; import org.ovirt.engine.core.dao.VmDynamicDao; import org.ovirt.engine.core.dao.VmStaticDao; import org.ovirt.engine.core.dao.network.VmNetworkStatisticsDao; import org.ovirt.engine.core.dao.network.VmNicDao; import org.ovirt.engine.core.utils.transaction.TransactionSupport; @NonTransactiveCommandAttribute(forceCompensation = true) public class AddVmInterfaceCommand<T extends AddVmInterfaceParameters> extends AbstractVmInterfaceCommand<T> { @Inject private VmStaticDao vmStaticDao; @Inject private VmNicDao vmNicDao; @Inject private VmNetworkStatisticsDao vmNetworkStatisticsDao; @Inject private VmDynamicDao vmDynamicDao; private MacPool macPool; public AddVmInterfaceCommand(T parameters, CommandContext cmdContext) { super(parameters, cmdContext); } public AddVmInterfaceCommand(Guid commandId) { super(commandId); } @Override protected void executeVmCommand() { addCustomValue("InterfaceType", VmInterfaceType.forValue(getInterface().getType()).getDescription().toString()); this.setVmName(vmStaticDao.get(getParameters().getVmId()).getName()); boolean succeeded = false; boolean macAddedToPool = false; try { if (StringUtils.isEmpty(getMacAddress())) { getInterface().setMacAddress(macPool.allocateNewMac()); macAddedToPool = true; } else { macAddedToPool = addMacToPool(getMacAddress()); } getInterface().setSpeed(VmInterfaceType.forValue(getInterface().getType()).getSpeed()); getInterface().setId(Guid.newGuid()); getInterface().setVmId(getParameters().getVmId()); TransactionSupport.executeInNewTransaction(() -> { bumpVmVersion(); addInterfaceToDb(getInterface()); addInterfaceDeviceToDb(); getCompensationContext().stateChanged(); return null; }); if (getInterface().isPlugged()) { succeeded = activateNewNic(getInterface()); } else { succeeded = true; } } finally { setSucceeded(succeeded); if (macAddedToPool && !succeeded) { macPool.freeMac(getMacAddress()); } } } private boolean activateNewNic(VmNic vmNic) { return activateOrDeactivateNic(vmNic, PlugAction.PLUG, true); } private void addInterfaceDeviceToDb() { VmDevice vmDevice = getVmDeviceUtils().addInterface( getParameters().getVmId(), getInterface().getId(), getInterface().isPlugged(), getInterface().isPassthrough()); getCompensationContext().snapshotNewEntity(vmDevice); } private void addInterfaceToDb(VmNic vmNetworkInterface) { vmNicDao.save(vmNetworkInterface); getCompensationContext().snapshotNewEntity(vmNetworkInterface); vmNetworkStatisticsDao.save(vmNetworkInterface.getStatistics()); getCompensationContext().snapshotNewEntity(vmNetworkInterface.getStatistics()); } @Override protected boolean validate() { if (getVm() == null) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND); } macPool = getMacPool(); if (!canRunActionOnNonManagedVm()) { return false; } if (getVm().isHostedEngine() && !getVm().isManagedHostedEngine()) { addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_UNMANAGED_HOSTED_ENGINE); } if (!updateVnicForBackwardCompatibility()) { return false; } if (!validate(vmStatusLegal(vmDynamicDao.get(getParameters().getVmId()).getStatus()))) { return false; } List<VmNic> interfaces = vmNicDao.getAllForVm(getParameters().getVmId()); if (!uniqueInterfaceName(interfaces)) { return false; } if (!validate(vmTemplateEmpty())) { return false; } // check that not exceeded PCI and IDE limit List<VmNic> allInterfaces = new ArrayList<>(interfaces); allInterfaces.add(getInterface()); if (!pciAndIdeWithinLimit(getVm(), allInterfaces)) { return false; } Version compatibilityVersion = getVm().getClusterCompatibilityVersion(); VmNicValidator nicValidator = new VmNicValidator(getInterface(), compatibilityVersion, getVm().getOs()); if (!validate(nicValidator.isCompatibleWithOs()) || !validate(nicValidator.profileValid(getVm().getClusterId())) || !validate(nicValidator.typeMatchesProfile()) || !validate(nicValidator.passthroughIsLinked()) || !validate(nicValidator.validateProfileNotEmptyForHostedEngineVm(getVm()))) { return false; } if (StringUtils.isNotEmpty(getMacAddress())) { if (!validate(macAvailable())) { return false; } } else if (macPool.getAvailableMacsCount() <= 0) { addValidationMessage(EngineMessage.MAC_POOL_NOT_ENOUGH_MAC_ADDRESSES); return false; } return true; } @Override protected List<Class<?>> getValidationGroups() { addValidationGroup(CreateEntity.class); return super.getValidationGroups(); } /** * Set the parameters for bll messages, such as type and action, */ @Override protected void setActionMessageParameters() { super.setActionMessageParameters(); addValidationMessage(EngineMessage.VAR__ACTION__ADD); } @Override public AuditLogType getAuditLogTypeValue() { return getSucceeded() ? AuditLogType.NETWORK_ADD_VM_INTERFACE : AuditLogType.NETWORK_ADD_VM_INTERFACE_FAILED; } /** * The permissions list contains the vm and the vnic profile id used by the vnic.<br> */ @Override public List<PermissionSubject> getPermissionCheckSubjects() { List<PermissionSubject> permissionList = super.getPermissionCheckSubjects(); if (getInterface() != null && getInterface().getVnicProfileId() != null && getVm() != null) { permissionList.add(new PermissionSubject(getInterface().getVnicProfileId(), VdcObjectType.VnicProfile, getActionType().getActionGroup())); } return permissionList; } }