package org.ovirt.engine.core.bll.network.host; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.bll.Backend; import org.ovirt.engine.core.bll.ValidationResult; import org.ovirt.engine.core.bll.network.FindActiveVmsUsingNetwork; import org.ovirt.engine.core.bll.validator.HostInterfaceValidator; import org.ovirt.engine.core.bll.validator.HostNetworkQosValidator; import org.ovirt.engine.core.bll.validator.NetworkAttachmentValidator; import org.ovirt.engine.core.bll.validator.NetworkAttachmentsValidator; import org.ovirt.engine.core.bll.validator.network.NetworkAttachmentIpConfigurationValidator; import org.ovirt.engine.core.bll.validator.network.NetworkExclusivenessValidator; import org.ovirt.engine.core.bll.validator.network.NetworkExclusivenessValidatorResolver; import org.ovirt.engine.core.common.action.CreateOrUpdateBond; import org.ovirt.engine.core.common.action.HostSetupNetworksParameters; import org.ovirt.engine.core.common.businessentities.BusinessEntitiesDefinitions; import org.ovirt.engine.core.common.businessentities.BusinessEntityMap; import org.ovirt.engine.core.common.businessentities.Entities; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.network.Bond; import org.ovirt.engine.core.common.businessentities.network.BondMode; import org.ovirt.engine.core.common.businessentities.network.HostNetworkQos; import org.ovirt.engine.core.common.businessentities.network.Network; import org.ovirt.engine.core.common.businessentities.network.NetworkAttachment; import org.ovirt.engine.core.common.businessentities.network.NicLabel; import org.ovirt.engine.core.common.businessentities.network.VdsNetworkInterface; import org.ovirt.engine.core.common.businessentities.network.VdsNetworkInterface.NetworkImplementationDetails; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.utils.MapNetworkAttachments; import org.ovirt.engine.core.common.utils.NetworkCommonUtils; import org.ovirt.engine.core.common.utils.customprop.SimpleCustomPropertiesUtil; import org.ovirt.engine.core.common.utils.customprop.ValidationError; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.VdsDao; import org.ovirt.engine.core.dao.VmDao; import org.ovirt.engine.core.dao.network.NetworkClusterDao; import org.ovirt.engine.core.dao.network.NetworkDao; import org.ovirt.engine.core.utils.NetworkUtils; import org.ovirt.engine.core.utils.ReplacementUtils; import org.ovirt.engine.core.utils.collections.MultiValueMapUtils; import org.ovirt.engine.core.utils.collections.MultiValueMapUtils.ListCreator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HostSetupNetworksValidator { private static final Logger log = LoggerFactory.getLogger(HostSetupNetworksValidator.class); static final String VAR_BOND_NAME = "BondName"; static final String VAR_NETWORK_NAME = "networkName"; static final String VAR_VM_NAMES = "vmNames"; static final String VAR_ATTACHMENT_IDS = "attachmentIds"; static final String VAR_INTERFACE_NAME = "interfaceName"; static final String VAR_NIC_ID = "nicId"; static final String VAR_LABELED_NIC_NAME = "labeledNicName"; static final String VAR_NIC_NAME = "nicName"; static final String VAR_LABEL = "label"; private static final String SEPARATOR = ","; private final NetworkExclusivenessValidator networkExclusivenessValidator; private HostSetupNetworksParameters params; private VDS host; private BusinessEntityMap<VdsNetworkInterface> existingInterfacesMap; private List<NetworkAttachment> existingAttachments; private List<VdsNetworkInterface> removedBondVdsNetworkInterface; private BusinessEntityMap<VdsNetworkInterface> removedBondVdsNetworkInterfaceMap; private List<NetworkAttachment> removedNetworkAttachments; private BusinessEntityMap<Network> networkBusinessEntityMap; private final Map<Guid, NetworkAttachment> existingAttachmentsById; private final NetworkClusterDao networkClusterDao; private final NetworkDao networkDao; private final VdsDao vdsDao; private final BusinessEntityMap<CreateOrUpdateBond> createOrUpdateBondBusinessEntityMap; private final FindActiveVmsUsingNetwork findActiveVmsUsingNetwork; private final VmDao vmDao; private Map<Guid, NetworkAttachment> existingAttachmentsByNetworkId; private Map<String, NicLabel> nicLabelByLabel; private HostSetupNetworksValidatorHelper hostSetupNetworksValidatorHelper; private List<VdsNetworkInterface> existingInterfaces; private NetworkAttachmentIpConfigurationValidator networkAttachmentIpConfigurationValidator; private UnmanagedNetworkValidator unmanagedNetworkValidator; public HostSetupNetworksValidator(VDS host, HostSetupNetworksParameters params, List<VdsNetworkInterface> existingInterfaces, List<NetworkAttachment> existingAttachments, BusinessEntityMap<Network> networkBusinessEntityMap, NetworkClusterDao networkClusterDao, NetworkDao networkDao, VdsDao vdsDao, FindActiveVmsUsingNetwork findActiveVmsUsingNetwork, HostSetupNetworksValidatorHelper hostSetupNetworksValidatorHelper, VmDao vmDao, NetworkExclusivenessValidatorResolver networkExclusivenessValidatorResolver, NetworkAttachmentIpConfigurationValidator networkAttachmentIpConfigurationValidator, UnmanagedNetworkValidator unmanagedNetworkValidator) { this.host = host; this.params = params; this.existingAttachments = existingAttachments; this.networkClusterDao = networkClusterDao; this.networkDao = networkDao; this.vdsDao = vdsDao; this.findActiveVmsUsingNetwork = findActiveVmsUsingNetwork; this.vmDao = vmDao; this.existingInterfacesMap = new BusinessEntityMap<>(existingInterfaces); this.networkBusinessEntityMap = networkBusinessEntityMap; this.existingInterfaces = existingInterfaces; this.removedBondVdsNetworkInterface = Entities.filterEntitiesByRequiredIds(params.getRemovedBonds(), existingInterfaces); this.removedBondVdsNetworkInterfaceMap = new BusinessEntityMap<>(removedBondVdsNetworkInterface); this.removedNetworkAttachments = Entities.filterEntitiesByRequiredIds(params.getRemovedNetworkAttachments(), existingAttachments); existingAttachmentsByNetworkId = new MapNetworkAttachments(existingAttachments).byNetworkId(); networkExclusivenessValidator = networkExclusivenessValidatorResolver.resolveNetworkExclusivenessValidator(); existingAttachmentsById = Entities.businessEntitiesById(existingAttachments); createOrUpdateBondBusinessEntityMap = new BusinessEntityMap<>(params.getCreateOrUpdateBonds()); nicLabelByLabel = Entities.entitiesByName(params.getLabels()); this.hostSetupNetworksValidatorHelper = hostSetupNetworksValidatorHelper; this.networkAttachmentIpConfigurationValidator = networkAttachmentIpConfigurationValidator; this.unmanagedNetworkValidator = unmanagedNetworkValidator; } List<String> translateErrorMessages(List<String> messages) { return Backend.getInstance().getErrorsTranslator().translateErrorText(messages); } public ValidationResult validate() { Collection<NetworkAttachment> attachmentsToConfigure = getAttachmentsToConfigure(); ValidationResult vr = ValidationResult.VALID; vr = skipValidation(vr) ? vr : new NicLabelValidator(params, existingInterfacesMap, createOrUpdateBondBusinessEntityMap, hostSetupNetworksValidatorHelper).validate(); vr = skipValidation(vr) ? vr : validNewOrModifiedNetworkAttachments(); vr = skipValidation(vr) ? vr : validRemovedNetworkAttachments(); vr = skipValidation(vr) ? vr : validNewOrModifiedBonds(); vr = skipValidation(vr) ? vr : validRemovedBonds(attachmentsToConfigure); vr = skipValidation(vr) ? vr : bondNotUpdatedAndRemovedSimultaneously(); vr = skipValidation(vr) ? vr : attachmentsDontReferenceSameNetworkDuplicately(attachmentsToConfigure); vr = skipValidation(vr) ? vr : networksUniquelyConfiguredOnHost(attachmentsToConfigure); vr = skipValidation(vr) ? vr : validateNetworkExclusiveOnNics(attachmentsToConfigure); vr = skipValidation(vr) ? vr : new NetworkMtuValidator(networkBusinessEntityMap).validateMtu( attachmentsToConfigure); vr = skipValidation(vr) ? vr : validateCustomProperties(); vr = skipValidation(vr) ? vr : validateQos(attachmentsToConfigure); vr = skipValidation(vr) ? vr : validateBondModeVsNetworksAttachedToIt(attachmentsToConfigure); vr = skipValidation(vr) ? vr : unmanagedNetworkValidator.validate(params, existingInterfaces, networkBusinessEntityMap); return vr; } protected ValidationResult validateBondModeVsNetworksAttachedToIt( Collection<NetworkAttachment> attachmentsToConfigure) { Map<String, VdsNetworkInterface> hostInterfacesByNetworkName = NetworkUtils.hostInterfacesByNetworkName(existingInterfaces); for (NetworkAttachment attachment : attachmentsToConfigure){ if (!mustAttachementBeCheckedForBondMode(attachment, hostInterfacesByNetworkName)){ continue; } CreateOrUpdateBond bondToCheck = createOrUpdateBondBusinessEntityMap.get(attachment.getNicName()); if (bondToCheck == null){ VdsNetworkInterface existingNetworkInterfaceForAttachement = existingInterfacesMap.get(attachment.getNicName()); if(existingNetworkInterfaceForAttachement == null || !existingNetworkInterfaceForAttachement.isBond()){ continue; } bondToCheck = CreateOrUpdateBond.fromBond((Bond) existingNetworkInterfaceForAttachement); } String networkLabel = networkBusinessEntityMap.get(attachment.getNetworkName()).getLabel(); ValidationResult validationResult = checkBondMode(bondToCheck, networkLabel, attachment.getNetworkName()); if (!validationResult.isValid()){ return validationResult; } } return ValidationResult.VALID; } private ValidationResult checkBondMode(CreateOrUpdateBond createOrUpdateBond, String networkLabel, String networkName) { if (BondMode.isBondModeValidForVmNetwork(createOrUpdateBond.getBondOptions())){ return ValidationResult.VALID; } if (networkLabel != null && isNicToConfigureContainTheLabel(createOrUpdateBond.getName(), networkLabel)){ return new ValidationResult(EngineMessage.INVALID_BOND_MODE_FOR_BOND_WITH_LABELED_VM_NETWORK, ReplacementUtils.createSetVariableString(VAR_BOND_NAME, createOrUpdateBond.getName()), ReplacementUtils.createSetVariableString(VAR_LABEL, networkLabel), ReplacementUtils.createSetVariableString(VAR_NETWORK_NAME, networkName)); } return new ValidationResult(EngineMessage.INVALID_BOND_MODE_FOR_BOND_WITH_VM_NETWORK, ReplacementUtils.createSetVariableString(VAR_BOND_NAME, createOrUpdateBond.getName()), ReplacementUtils.createSetVariableString(VAR_NETWORK_NAME, networkName)); } private boolean mustAttachementBeCheckedForBondMode(NetworkAttachment attachment, Map<String, VdsNetworkInterface> hostInterfacesByNetworkName){ Network network = networkBusinessEntityMap.get(attachment.getNetworkName()); String networkName = attachment.getNetworkName(); if (!network.isVmNetwork()){ return false; } VdsNetworkInterface nic = hostInterfacesByNetworkName.get(networkName); if (nic == null){ return true; } NetworkImplementationDetails networkImplementationDetails = nic.getNetworkImplementationDetails(); return networkImplementationDetails == null || networkImplementationDetails.isInSync() || attachment.isOverrideConfiguration(); } private ValidationResult validateQos(Collection<NetworkAttachment> attachmentsToConfigure) { ValidationResult vr = ValidationResult.VALID; vr = skipValidation(vr) ? vr : validateQosOverriddenInterfaces(); vr = skipValidation(vr) ? vr : validateQosNotPartiallyConfigured(attachmentsToConfigure); return vr; } private ValidationResult attachmentsDontReferenceSameNetworkDuplicately(Collection<NetworkAttachment> attachments) { return new NetworkAttachmentsValidator(attachments, networkBusinessEntityMap, networkExclusivenessValidator) .verifyUserAttachmentsDoesNotReferenceSameNetworkDuplicately(); } /** * Validates that the feature is supported if any QoS configuration was specified, and that the values associated * with it are valid. */ ValidationResult validateQosOverriddenInterfaces() { for (NetworkAttachment networkAttachment : params.getNetworkAttachments()) { if (networkAttachment.isQosOverridden()) { Network network = getNetworkRelatedToAttachment(networkAttachment); String networkName = network.getName(); HostNetworkQos hostNetworkQos = HostNetworkQos.fromAnonymousHostNetworkQos(networkAttachment.getHostNetworkQos()); HostNetworkQosValidator qosValidator = createHostNetworkQosValidator(hostNetworkQos); ValidationResult requiredValuesPresent = qosValidator.requiredQosValuesPresentForOverriding(networkName); if (!requiredValuesPresent.isValid()) { return requiredValuesPresent; } ValidationResult valuesConsistent = qosValidator.valuesConsistent(networkName); if (!valuesConsistent.isValid()) { return valuesConsistent; } } } return ValidationResult.VALID; } HostNetworkQosValidator createHostNetworkQosValidator(HostNetworkQos hostNetworkQos) { return new HostNetworkQosValidator(hostNetworkQos); } private Network getNetworkRelatedToAttachment(NetworkAttachment networkAttachment) { Guid networkId = networkAttachment.getNetworkId(); return getNetworkByNetworkId(networkId); } private Network getNetworkByNetworkId(Guid networkId) { return networkBusinessEntityMap.get(networkId); } /** * Ensure that either none or all of the networks on a single interface have QoS configured on them. */ ValidationResult validateQosNotPartiallyConfigured(Collection<NetworkAttachment> attachmentsToConfigure) { Set<String> someSubInterfacesHaveQos = new HashSet<>(); Set<String> notAllSubInterfacesHaveQos = new HashSet<>(); // first map which interfaces have some QoS configured on them, and which interfaces lack some QoS configuration for (NetworkAttachment networkAttachment : attachmentsToConfigure) { Network network = getNetworkRelatedToAttachment(networkAttachment); if (NetworkUtils.qosConfiguredOnInterface(networkAttachment, network)) { someSubInterfacesHaveQos.add(networkAttachment.getNicName()); } else { notAllSubInterfacesHaveQos.add(networkAttachment.getNicName()); } } // if any base interface has some sub-interfaces with QoS and some without - this is a partial configuration for (String ifaceName : someSubInterfacesHaveQos) { if (notAllSubInterfacesHaveQos.contains(ifaceName)) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_HOST_NETWORK_QOS_INTERFACES_WITHOUT_QOS, ReplacementUtils.createSetVariableString( "ACTION_TYPE_FAILED_HOST_NETWORK_QOS_INTERFACES_WITHOUT_QOS_LIST", ifaceName)); } } return ValidationResult.VALID; } private ValidationResult validateNetworkExclusiveOnNics(Collection<NetworkAttachment> attachmentsToConfigure) { NetworkAttachmentsValidator validator = new NetworkAttachmentsValidator(attachmentsToConfigure, networkBusinessEntityMap, networkExclusivenessValidator); return validator.validateNetworkExclusiveOnNics(); } ValidationResult networksUniquelyConfiguredOnHost(Collection<NetworkAttachment> attachmentsToConfigure) { Set<Guid> usedNetworkIds = new HashSet<>(attachmentsToConfigure.size()); for (NetworkAttachment attachment : attachmentsToConfigure) { boolean alreadyUsedNetworkId = usedNetworkIds.contains(attachment.getNetworkId()); if (alreadyUsedNetworkId) { Network network = existingNetworkRelatedToAttachment(attachment); EngineMessage engineMessage = EngineMessage.NETWORKS_ALREADY_ATTACHED_TO_IFACES; return new ValidationResult(engineMessage, ReplacementUtils.getVariableAssignmentStringWithMultipleValues(engineMessage, network.getName())); } else { usedNetworkIds.add(attachment.getNetworkId()); } } return ValidationResult.VALID; } @SuppressWarnings("unchecked") ValidationResult validateNotRemovingUsedNetworkByVms(String removedNetworkName) { final List<String> removedNetworkNames = Collections.singletonList(removedNetworkName); final List<String> vmsNames = findActiveVmsUsingNetwork.findNamesOfActiveVmsUsingNetworks(host.getId(), removedNetworkNames); if (vmsNames.isEmpty()) { return ValidationResult.VALID; } EngineMessage engineMessage = EngineMessage.NETWORK_CANNOT_DETACH_NETWORK_USED_BY_VMS; return new ValidationResult(engineMessage, Stream.concat( ReplacementUtils.replaceWith(VAR_NETWORK_NAME, removedNetworkNames, SEPARATOR).stream(), ReplacementUtils.replaceWith(VAR_VM_NAMES, vmsNames, SEPARATOR).stream() ).collect(Collectors.toList())); } ValidationResult validRemovedBonds(Collection<NetworkAttachment> attachmentsToConfigure) { List<Guid> invalidBondIds = Entities.idsNotReferencingExistingRecords(params.getRemovedBonds(), existingInterfacesMap.unmodifiableEntitiesByIdMap()); if (!invalidBondIds.isEmpty()) { EngineMessage engineMessage = EngineMessage.NETWORK_BOND_RECORDS_DOES_NOT_EXISTS; return new ValidationResult(engineMessage, ReplacementUtils.getListVariableAssignmentString(engineMessage, invalidBondIds)); } Map<String, List<Guid>> nicNameToAttachedNetworkAttachmentIds = getIdsOfNetworkAttachmentsRelatedToInterfaceNames(attachmentsToConfigure); for (VdsNetworkInterface removedBond : removedBondVdsNetworkInterface) { String bondName = removedBond.getName(); VdsNetworkInterface existingBond = existingInterfacesMap.get(bondName); ValidationResult interfaceIsBondOrNull = createHostInterfaceValidator(existingBond).interfaceIsBondOrNull(); if (!interfaceIsBondOrNull.isValid()) { return interfaceIsBondOrNull; } boolean cantRemoveRequiredInterface = nicNameToAttachedNetworkAttachmentIds.containsKey(bondName); if (cantRemoveRequiredInterface) { List<Guid> networkAttachmentsForNic = nicNameToAttachedNetworkAttachmentIds.get(bondName); EngineMessage engineMessage = EngineMessage.BOND_USED_BY_NETWORK_ATTACHMENTS; List<String> replacements = new ArrayList<>(); replacements.add(ReplacementUtils.getVariableAssignmentString(engineMessage, bondName)); replacements.addAll(ReplacementUtils.replaceWith(VAR_ATTACHMENT_IDS, networkAttachmentsForNic)); return new ValidationResult(engineMessage, replacements); } } return ValidationResult.VALID; } private Map<String, List<Guid>> getIdsOfNetworkAttachmentsRelatedToInterfaceNames(Collection<NetworkAttachment> networkAttachments) { Map<String, List<Guid>> map = new HashMap<>(); for (NetworkAttachment attachment : networkAttachments) { MultiValueMapUtils.addToMap(attachment.getNicName(), attachment.getId(), map, new ListCreator<>()); } return map; } /** * @return all attachments passed in {@link HostSetupNetworksParameters#networkAttachments} plus * all previously existing attachments not mentioned in user request, but except for those listed in * {@link org.ovirt.engine.core.common.action.HostSetupNetworksParameters#removedNetworkAttachments} */ Collection<NetworkAttachment> getAttachmentsToConfigure() { Map<Guid, NetworkAttachment> networkAttachmentsMap = new HashMap<>( existingAttachments.size() + params.getNetworkAttachments().size()); List<NetworkAttachment> newAttachments = new ArrayList<>(); for (NetworkAttachment attachment : params.getNetworkAttachments()) { if (attachment.getId() == null) { newAttachments.add(attachment); } else { networkAttachmentsMap.put(attachment.getId(), attachment); } } for (NetworkAttachment existingAttachment : existingAttachments) { Guid existingAttachmentId = existingAttachment.getId(); if (!networkAttachmentsMap.containsKey(existingAttachmentId) && !params.getRemovedNetworkAttachments().contains(existingAttachmentId)) { networkAttachmentsMap.put(existingAttachmentId, existingAttachment); } } List<NetworkAttachment> result = new ArrayList<>(networkAttachmentsMap.values()); result.addAll(newAttachments); return result; } public ValidationResult bondNotUpdatedAndRemovedSimultaneously() { List<String> bondsUpdatedAndRemovedSimultaneously = params.getCreateOrUpdateBonds() .stream() .filter(bond -> params.getRemovedBonds().contains(bond.getId())) .map(CreateOrUpdateBond::getName) .collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(bondsUpdatedAndRemovedSimultaneously)) { EngineMessage engineMessage = EngineMessage.BONDS_UPDATED_AND_REMOVED_SIMULTANEOUSLY; return new ValidationResult(engineMessage, ReplacementUtils.getListVariableAssignmentString(engineMessage, bondsUpdatedAndRemovedSimultaneously)); } return ValidationResult.VALID; } ValidationResult validNewOrModifiedBonds() { for (CreateOrUpdateBond modifiedOrNewBond : params.getCreateOrUpdateBonds()) { String bondName = modifiedOrNewBond.getName(); Guid bondId = modifiedOrNewBond.getId(); /* * following code relies on fact, that completors were ran and fixed the user input, so we need to consider * what original user input looked like, and how it was altered by completors. */ /* * bondId is provided, but bondName not. This means that user attempted update, but bond of such ID does not * exit, thus completors did not complete name. */ if (bondId != null && bondName == null) { return new ValidationResult(EngineMessage.HOST_NETWORK_INTERFACE_HAVING_ID_DOES_NOT_EXIST, ReplacementUtils.createSetVariableString(VAR_NIC_ID, bondId)); } /* * user did not provide neither bondId nor bondName. That means he probably attempted new bond creation * but forgot to provide bondName. */ if (bondId == null && bondName == null) { return new ValidationResult(EngineMessage.BOND_DOES_NOT_HAVE_NEITHER_ID_NOR_NAME_SPECIFIED); } /* * if (bondId == null && bondName != null) … * User provided only bondName, and completors failed to find existing bonds id for that name. * We cannot tell, what user wanted to do(create/update). We have to assume, it's new record creation, which * is valid scenario. */ ValidationResult validateCoherentNicIdentification = validateCoherentNicIdentification(modifiedOrNewBond); if (!validateCoherentNicIdentification.isValid()) { return validateCoherentNicIdentification; } boolean validBondName = bondName.matches(BusinessEntitiesDefinitions.BOND_NAME_PATTERN); if (!validBondName) { EngineMessage engineMessage = EngineMessage.NETWORK_BOND_NAME_BAD_FORMAT; return new ValidationResult(engineMessage, ReplacementUtils.getVariableAssignmentString(engineMessage, bondName)); } //either it's newly create bond, thus non existing, or given name must reference existing bond. ValidationResult interfaceIsBondOrNull = createHostInterfaceValidator(existingInterfacesMap.get(bondName)).interfaceIsBondOrNull(); if (!interfaceIsBondOrNull.isValid()) { return interfaceIsBondOrNull; } //count of bond slaves must be at least two. if (modifiedOrNewBond.getSlaves().size() < 2) { return new ValidationResult(EngineMessage.NETWORK_BONDS_INVALID_SLAVE_COUNT, ReplacementUtils.getVariableAssignmentString(EngineMessage.NETWORK_BONDS_INVALID_SLAVE_COUNT, bondName)); } ValidationResult validateModifiedBondSlaves = validateModifiedBondSlaves(modifiedOrNewBond); if (!validateModifiedBondSlaves.isValid()) { return validateModifiedBondSlaves; } } return ValidationResult.VALID; } ValidationResult validateModifiedBondSlaves(CreateOrUpdateBond modifiedOrNewBond) { for (String slaveName : modifiedOrNewBond.getSlaves()) { VdsNetworkInterface potentialSlave = existingInterfacesMap.get(slaveName); HostInterfaceValidator slaveHostInterfaceValidator = createHostInterfaceValidator(potentialSlave); ValidationResult interfaceExists = slaveHostInterfaceValidator.interfaceExists(slaveName); if (!interfaceExists.isValid()) { return interfaceExists; } ValidationResult interfaceIsValidSlave = slaveHostInterfaceValidator.interfaceIsValidSlave(); if (!interfaceIsValidSlave.isValid()) { return interfaceIsValidSlave; } /* * definition of currently processed bond references this slave, but this slave already 'slaves' for * another bond. This is ok only when this bond will be removed as a part of this request * or the slave will be removed from its former bond, as a part of this request. */ String currentSlavesBondName = potentialSlave.getBondName(); if (potentialSlave.isPartOfBond() && /* * we're creating new bond, and it's definition contains reference to slave already assigned * to a different bond. */ (!potentialSlave.isPartOfBond(modifiedOrNewBond.getName()) //… but this bond is also removed in this request, so it's ok. && !isBondRemoved(currentSlavesBondName) //… or slave was removed from its former bond && !bondIsUpdatedAndDoesNotContainCertainSlave(slaveName, currentSlavesBondName))) { EngineMessage engineMessage = EngineMessage.NETWORK_INTERFACE_ALREADY_IN_BOND; return new ValidationResult(engineMessage, ReplacementUtils.getVariableAssignmentString(engineMessage, slaveName)); } ValidationResult slaveHasAttachedNetworksValidationResult = validateSlaveHasNoNetworks(potentialSlave.getName()); if (!slaveHasAttachedNetworksValidationResult.isValid()) { return slaveHasAttachedNetworksValidationResult; } if (slaveUsedMultipleTimesInDifferentBonds(slaveName)) { return new ValidationResult(EngineMessage.NETWORK_INTERFACE_REFERENCED_AS_A_SLAVE_MULTIPLE_TIMES, ReplacementUtils.createSetVariableString( "NETWORK_INTERFACE_REFERENCED_AS_A_SLAVE_MULTIPLE_TIMES_ENTITY", slaveName)); } ValidationResult slaveHasNoLabelsValidationResult = validateSlaveHasNoLabels(slaveName); if (!slaveHasNoLabelsValidationResult.isValid()) { return slaveHasNoLabelsValidationResult; } } return ValidationResult.VALID; } ValidationResult validateSlaveHasNoLabels(String slaveName) { Set<String> labelsToConfigureOnNic = getLabelsToConfigureOnNic(slaveName); return ValidationResult.failWith(EngineMessage.LABEL_ATTACH_TO_IMPROPER_INTERFACE, ReplacementUtils.createSetVariableString( "LABEL_ATTACH_TO_IMPROPER_INTERFACE_ENTITY", slaveName)).unless(labelsToConfigureOnNic == null || labelsToConfigureOnNic.isEmpty()); } private ValidationResult validateSlaveHasNoNetworks(String slaveName) { for (NetworkAttachment attachment : getAttachmentsToConfigure()) { if (Objects.equals(attachment.getNicName(), slaveName)) { if (attachment.getId() == null) { EngineMessage engineMessage = EngineMessage.NETWORK_INTERFACE_ADDED_TO_BOND_AND_NETWORK_IS_ATTACHED_TO_IT_AT_THE_SAME_TIME; return new ValidationResult(engineMessage, ReplacementUtils.getVariableAssignmentString(engineMessage, slaveName), ReplacementUtils.createSetVariableString(VAR_NETWORK_NAME, attachment.getNetworkName())); } else { EngineMessage engineMessage = EngineMessage.NETWORK_INTERFACE_ATTACHED_TO_NETWORK_CANNOT_BE_SLAVE; return new ValidationResult(engineMessage, ReplacementUtils.getVariableAssignmentString(engineMessage, slaveName), ReplacementUtils.createSetVariableString(VAR_NETWORK_NAME, attachment.getNetworkName())); } } } for (VdsNetworkInterface iface : existingInterfaces) { if (slaveName.equals(NetworkCommonUtils.stripVlan(iface))) { if (iface.getNetworkImplementationDetails() != null && !iface.getNetworkImplementationDetails().isManaged()) { return new ValidationResult(EngineMessage.NETWORK_INTERFACE_WITH_UNMANAGED_NETWORK_CANNOT_BE_SLAVE, ReplacementUtils.createSetVariableString(VAR_NETWORK_NAME, iface.getNetworkName()), ReplacementUtils.createSetVariableString(VAR_NIC_NAME, slaveName)); } } } return ValidationResult.VALID; } private boolean slaveUsedMultipleTimesInDifferentBonds(String potentiallyDuplicateSlaveName) { int count = 0; for (CreateOrUpdateBond createOrUpdateBond : params.getCreateOrUpdateBonds()) { for (String slaveName : createOrUpdateBond.getSlaves()) { if (slaveName.equals(potentiallyDuplicateSlaveName)) { count++; } } } return count >= 2; } HostInterfaceValidator createHostInterfaceValidator(VdsNetworkInterface vdsNetworkInterface) { return new HostInterfaceValidator(vdsNetworkInterface); } /** * looks into new/modified bonds for bond of given name, whether it contains certain slave. * * @param slaveName slave which should not be present * @param bondName name of bond we're examining * * @return true if bond specified by name is present in request and does not contain given slave. */ private boolean bondIsUpdatedAndDoesNotContainCertainSlave(String slaveName, String bondName) { CreateOrUpdateBond createOrUpdateBond = this.createOrUpdateBondBusinessEntityMap.get(bondName); return createOrUpdateBond != null && !createOrUpdateBond.getSlaves().contains(slaveName); } /** * @param bondName name of bonded interface. * * @return true if there's request to remove bond of given name. */ private boolean isBondRemoved(String bondName) { for (VdsNetworkInterface removedBond : removedBondVdsNetworkInterface) { if (bondName.equals(removedBond.getName())) { return true; } } return false; } ValidationResult validNewOrModifiedNetworkAttachments() { ValidationResult vr = ValidationResult.VALID; Iterator<NetworkAttachment> iterator = params.getNetworkAttachments().iterator(); while (iterator.hasNext() && vr.isValid()) { NetworkAttachment attachment = iterator.next(); NetworkAttachmentValidator validator = createNetworkAttachmentValidator(attachment); vr = skipValidation(vr) ? vr : validator.networkAttachmentIsSet(); vr = skipValidation(vr) ? vr : modifiedAttachmentExists(attachment.getId()); vr = skipValidation(vr) ? vr : validator.networkExists(); vr = skipValidation(vr) ? vr : validateCoherentNicIdentification(attachment); vr = skipValidation(vr) ? vr : validateCoherentNetworkIdentification(attachment); vr = skipValidation(vr) ? vr : modifiedAttachmentNotRemoved(attachment); vr = skipValidation(vr) ? vr : validateAttachmentNotReferenceVlanDevice(attachment); vr = skipValidation(vr) ? vr : validator.existingAttachmentIsReused(existingAttachmentsByNetworkId); vr = skipValidation(vr) ? vr : validateAttachmentAndNicReferenceSameLabelNotConflict(attachment); vr = skipValidation(vr) ? vr : validator.notExternalNetwork(); vr = skipValidation(vr) ? vr : validator.networkAttachedToCluster(); vr = skipValidation(vr) ? vr : validator.bootProtocolSetForRoleNetwork(); vr = skipValidation(vr) ? vr : validator.nicNameIsSet(); vr = skipValidation(vr) ? vr : nicActuallyExistsOrReferencesNewBond(attachment); vr = skipValidation(vr) ? vr : validator.networkNotChanged(existingAttachmentsById.get(attachment.getId())); vr = skipValidation(vr) ? vr : networkAttachmentIpConfigurationValidator.validateNetworkAttachmentIpConfiguration(params.getNetworkAttachments()); boolean attachmentUpdated = !isNewAttachment(attachment.getId()); if (attachmentUpdated) { vr = skipValidation(vr) ? vr : notMovingLabeledNetworkToDifferentNic(attachment); } } return vr; } private ValidationResult validateCoherentNetworkIdentification(NetworkAttachment attachment) { Guid networkId = attachment.getNetworkId(); String networkName = attachment.getNetworkName(); Guid violatingEntityId = attachment.getId(); return hostSetupNetworksValidatorHelper.validateCoherentIdentification(String.valueOf(violatingEntityId), networkId, networkName, EngineMessage.NETWORK_ATTACHMENT_REFERENCES_NETWORK_INCOHERENTLY, networkBusinessEntityMap); } private ValidationResult validateCoherentNicIdentification(NetworkAttachment attachment) { return hostSetupNetworksValidatorHelper.validateCoherentIdentification(String.valueOf(attachment.getId()), attachment.getNicId(), attachment.getNicName(), EngineMessage.NETWORK_ATTACHMENT_REFERENCES_NICS_INCOHERENTLY, existingInterfacesMap); } private ValidationResult validateCoherentNicIdentification(CreateOrUpdateBond createOrUpdateBond) { Guid nicId = createOrUpdateBond.getId(); String nicName = createOrUpdateBond.getName(); EngineMessage message = EngineMessage.BOND_REFERENCES_NICS_INCOHERENTLY; return hostSetupNetworksValidatorHelper.validateCoherentIdentification(nicName, nicId, nicName, message, existingInterfacesMap); } private ValidationResult modifiedAttachmentExists(Guid networkAttachmentId) { if (isNewAttachment(networkAttachmentId)) { return ValidationResult.VALID; } for (NetworkAttachment existingAttachment : existingAttachments) { if (existingAttachment.getId().equals(networkAttachmentId)) { return ValidationResult.VALID; } } EngineMessage engineMessage = EngineMessage.MODIFIED_NETWORK_ATTACHMENT_DOES_NOT_EXISTS; String replacement = ReplacementUtils.getVariableAssignmentString(engineMessage, networkAttachmentId.toString()); return new ValidationResult(engineMessage, replacement); } ValidationResult modifiedAttachmentNotRemoved(NetworkAttachment networkAttachment) { Guid networkAttachmentId = networkAttachment.getId(); if (isNewAttachment(networkAttachmentId)) { return ValidationResult.VALID; } boolean attachmentInRemoveList = params.getRemovedNetworkAttachments().contains(networkAttachmentId); EngineMessage engineMessage = EngineMessage.NETWORK_ATTACHMENT_IN_BOTH_LISTS; return ValidationResult.failWith(engineMessage, ReplacementUtils.getVariableAssignmentString(engineMessage, networkAttachmentId.toString())) .when(attachmentInRemoveList); } private boolean isNewAttachment(Guid networkAttachmentId) { return networkAttachmentId == null; } private ValidationResult nicActuallyExistsOrReferencesNewBond(NetworkAttachment attachment) { String nicName = attachment.getNicName(); Guid nicId = attachment.getNicId(); boolean nicActuallyExistsOrReferencesNewBond = isNicActuallyExistsOrReferencesNewBond(nicName, nicId); return ValidationResult.failWith(EngineMessage.HOST_NETWORK_INTERFACE_HAVING_ID_OR_NAME_DOES_NOT_EXIST, ReplacementUtils.createSetVariableString(VAR_NIC_ID, nicId), ReplacementUtils.createSetVariableString(VAR_NIC_NAME, nicName) ).when(!nicActuallyExistsOrReferencesNewBond); } private boolean isNicActuallyExistsOrReferencesNewBond(String nicName, Guid nicId) { return hostSetupNetworksValidatorHelper.isNicActuallyExistsOrReferencesNewBond(existingInterfacesMap, createOrUpdateBondBusinessEntityMap, nicName, nicId); } private ValidationResult validRemovedNetworkAttachments() { List<Guid> invalidIds = Entities.idsNotReferencingExistingRecords(params.getRemovedNetworkAttachments(), existingAttachments); if (!invalidIds.isEmpty()) { EngineMessage engineMessage = EngineMessage.NETWORK_ATTACHMENTS_TO_BE_REMOVED_DOES_NOT_EXISTS; return new ValidationResult(engineMessage, ReplacementUtils.getListVariableAssignmentString(engineMessage, invalidIds)); } ValidationResult vr = ValidationResult.VALID; Iterator<NetworkAttachment> iterator = removedNetworkAttachments.iterator(); while (iterator.hasNext() && vr.isValid()) { NetworkAttachment attachment = iterator.next(); NetworkAttachmentValidator validator = createNetworkAttachmentValidator(attachment); vr = skipValidation(vr) ? vr : validator.networkAttachmentIsSet(); vr = skipValidation(vr) ? vr : validator.notExternalNetwork(); vr = skipValidation(vr) ? vr : validator.notRemovingManagementNetwork(); vr = skipValidation(vr) ? vr : notRemovingLabeledNetworks(attachment); vr = skipValidation(vr) ? vr : validateNotRemovingUsedNetworkByVms(attachment.getNetworkName()); } return vr; } private NetworkAttachmentValidator createNetworkAttachmentValidator(NetworkAttachment attachmentToValidate) { return new NetworkAttachmentValidator(attachmentToValidate, host, networkClusterDao, networkDao, vdsDao, vmDao); } /** * @param attachment attachment obtained from db, record validity is assumed. * * @return removed attachment relates to network and nic. Method returns true such network is not labeled, * such nic is currently being removed bond, * or such nic is not labeled by same label as network is. */ ValidationResult notRemovingLabeledNetworks(NetworkAttachment attachment) { Network removedNetwork = existingNetworkRelatedToAttachment(attachment); if (!NetworkUtils.isLabeled(removedNetwork)) { return ValidationResult.VALID; } EngineMessage engineMessage = EngineMessage.ACTION_TYPE_FAILED_CANNOT_REMOVE_LABELED_NETWORK_FROM_NIC; return ValidationResult.failWith(engineMessage, ReplacementUtils.getVariableAssignmentStringWithMultipleValues(engineMessage, removedNetwork.getName())) .when(isNicToConfigureContainTheLabel(attachment.getNicName(), removedNetwork.getLabel())); } ValidationResult notMovingLabeledNetworkToDifferentNic(NetworkAttachment newOrModifedAttachmet) { Network movedNetwork = existingNetworkRelatedToAttachment(newOrModifedAttachmet); if (!NetworkUtils.isLabeled(movedNetwork)) { return ValidationResult.VALID; } NetworkAttachment existingAttachment = existingAttachmentsById.get(newOrModifedAttachmet.getId()); boolean movedToDifferentNic = !existingAttachment.getNicId().equals(newOrModifedAttachmet.getNicId()); EngineMessage engineMessage = EngineMessage.ACTION_TYPE_FAILED_CANNOT_MOVE_LABELED_NETWORK_TO_ANOTHER_NIC; return ValidationResult.failWith(engineMessage, ReplacementUtils.createSetVariableString(VAR_NETWORK_NAME, movedNetwork.getName()), ReplacementUtils.getVariableAssignmentString(engineMessage, movedNetwork.getLabel())) .when(movedToDifferentNic && isNicToConfigureContainTheLabel(existingAttachment.getNicName(), movedNetwork.getLabel())); } ValidationResult validateAttachmentAndNicReferenceSameLabelNotConflict(NetworkAttachment attachment) { Network network = existingNetworkRelatedToAttachment(attachment); if (!NetworkUtils.isLabeled(network)) { return ValidationResult.VALID; } String label = network.getLabel(); String nicThatShouldHaveTheLabel = nicLabelByLabel.containsKey(label) ? nicLabelByLabel.get(label).getNicName() : null; EngineMessage engineMessage = EngineMessage.NETWORK_SHOULD_BE_ATTACHED_VIA_LABEL_TO_ANOTHER_NIC; return ValidationResult.failWith(engineMessage, ReplacementUtils.getVariableAssignmentString(engineMessage, network.getName()), ReplacementUtils.createSetVariableString(VAR_NIC_NAME, attachment.getNicName()), ReplacementUtils.createSetVariableString(VAR_LABELED_NIC_NAME, nicThatShouldHaveTheLabel)) .unless(nicThatShouldHaveTheLabel == null || nicThatShouldHaveTheLabel.equals(attachment.getNicName())); } private Set<String> getLabelsToConfigureOnNic(String nicName) { VdsNetworkInterface existingNic = existingInterfacesMap.get(nicName); Set<String> labelsToConfigure = new HashSet<>(); if (existingNic != null) { boolean nicWasRemoved = removedBondVdsNetworkInterfaceMap.containsKey(existingNic.getName()); if (nicWasRemoved) { return null; } Set<String> oldLabels = existingNic.getLabels(); if (oldLabels != null) { for (String label : oldLabels) { NicLabel nicLabel = nicLabelByLabel.get(label); boolean labelRemovedFromNic = params.getRemovedLabels().contains(label) || (nicLabel != null && !Objects.equals(nicLabel.getNicName(), existingNic.getName())); if (!labelRemovedFromNic) { labelsToConfigure.add(label); } } } for (NicLabel nicLabel : params.getLabels()) { if (existingNic.getName().equals(nicLabel.getNicName())) { labelsToConfigure.add(nicLabel.getLabel()); } } } return labelsToConfigure; } private boolean isNicToConfigureContainTheLabel(String nicName, String label) { Set<String> labelsToConfigure = getLabelsToConfigureOnNic(nicName); return labelsToConfigure != null && labelsToConfigure.contains(label); } private ValidationResult validateCustomProperties() { String version = host.getClusterCompatibilityVersion().getValue(); SimpleCustomPropertiesUtil util = SimpleCustomPropertiesUtil.getInstance(); Map<String, String> validPropertiesForVmNetwork = util.convertProperties(Config.<String> getValue(ConfigValues.PreDefinedNetworkCustomProperties, version)); validPropertiesForVmNetwork.putAll(util.convertProperties(Config.<String> getValue(ConfigValues.UserDefinedNetworkCustomProperties, version))); Map<String, String> validPropertiesForNonVm = new HashMap<>(validPropertiesForVmNetwork); validPropertiesForNonVm.remove("bridge_opts"); return validateCustomProperties(util, validPropertiesForVmNetwork, validPropertiesForNonVm); } ValidationResult validateCustomProperties(SimpleCustomPropertiesUtil util, Map<String, String> validPropertiesForVm, Map<String, String> validPropertiesForNonVm) { for (NetworkAttachment attachment : params.getNetworkAttachments()) { Network network = existingNetworkRelatedToAttachment(attachment); if (attachment.hasProperties()) { List<ValidationError> errors = util.validateProperties(network.isVmNetwork() ? validPropertiesForVm : validPropertiesForNonVm, attachment.getProperties()); if (!errors.isEmpty()) { handleCustomPropertiesError(util, errors); EngineMessage engineMessage = EngineMessage.ACTION_TYPE_FAILED_NETWORK_CUSTOM_PROPERTIES_BAD_INPUT; return new ValidationResult(engineMessage, ReplacementUtils.getVariableAssignmentStringWithMultipleValues(engineMessage, network.getName())); } } } return ValidationResult.VALID; } private void handleCustomPropertiesError(SimpleCustomPropertiesUtil util, List<ValidationError> errors) { List<String> messages = new ArrayList<>(); util.handleCustomPropertiesError(errors, messages); log.error(StringUtils.join(translateErrorMessages(messages), ',')); } private ValidationResult validateAttachmentNotReferenceVlanDevice(NetworkAttachment attachment) { VdsNetworkInterface nic = existingInterfacesMap.get(attachment.getNicName()); EngineMessage engineMessage = EngineMessage.ATTACHMENT_REFERENCE_VLAN_DEVICE; return ValidationResult.failWith(engineMessage, ReplacementUtils.getVariableAssignmentString(engineMessage, attachment.getNetworkName()), ReplacementUtils.createSetVariableString(VAR_NIC_NAME, attachment.getNicName())) .when(nic != null && NetworkCommonUtils.isVlan(nic)); } private Network existingNetworkRelatedToAttachment(NetworkAttachment attachment) { return networkBusinessEntityMap.get(attachment.getNetworkId()); } private boolean skipValidation(ValidationResult validationResult) { return !validationResult.isValid(); } }