package org.ovirt.engine.core.bll.network.host;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
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.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.validation.groups.Default;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.ovirt.engine.core.bll.HostLocking;
import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute;
import org.ovirt.engine.core.bll.ValidationResult;
import org.ovirt.engine.core.bll.VdsCommand;
import org.ovirt.engine.core.bll.VdsHandler;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.network.FindActiveVmsUsingNetwork;
import org.ovirt.engine.core.bll.network.cluster.ManagementNetworkUtil;
import org.ovirt.engine.core.bll.network.cluster.NetworkClusterHelper;
import org.ovirt.engine.core.bll.validator.network.NetworkAttachmentIpConfigurationValidator;
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.action.LockProperties;
import org.ovirt.engine.core.common.action.LockProperties.Scope;
import org.ovirt.engine.core.common.businessentities.BusinessEntity;
import org.ovirt.engine.core.common.businessentities.BusinessEntityMap;
import org.ovirt.engine.core.common.businessentities.Entities;
import org.ovirt.engine.core.common.businessentities.SeparateNewAndModifiedInstances;
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.HostNetworkQos;
import org.ovirt.engine.core.common.businessentities.network.IpConfiguration;
import org.ovirt.engine.core.common.businessentities.network.Ipv4BootProtocol;
import org.ovirt.engine.core.common.businessentities.network.Ipv6BootProtocol;
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.NetworkCluster;
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.EngineError;
import org.ovirt.engine.core.common.errors.EngineException;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.interfaces.FutureVDSCall;
import org.ovirt.engine.core.common.network.SwitchType;
import org.ovirt.engine.core.common.queries.IdQueryParameters;
import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.common.utils.MapNetworkAttachments;
import org.ovirt.engine.core.common.utils.NetworkCommonUtils;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.common.utils.ValidationUtils;
import org.ovirt.engine.core.common.validation.group.CreateEntity;
import org.ovirt.engine.core.common.validation.group.UpdateEntity;
import org.ovirt.engine.core.common.vdscommands.FutureVDSCommandType;
import org.ovirt.engine.core.common.vdscommands.HostNetwork;
import org.ovirt.engine.core.common.vdscommands.HostSetupNetworksVdsCommandParameters;
import org.ovirt.engine.core.common.vdscommands.UserConfiguredNetworkData;
import org.ovirt.engine.core.common.vdscommands.UserOverriddenNicValues;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
import org.ovirt.engine.core.common.vdscommands.VdsIdAndVdsVDSCommandParametersBase;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dao.VdsDao;
import org.ovirt.engine.core.dao.VdsDynamicDao;
import org.ovirt.engine.core.dao.VmDao;
import org.ovirt.engine.core.dao.network.InterfaceDao;
import org.ovirt.engine.core.dao.network.NetworkAttachmentDao;
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.lock.EngineLock;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
import org.ovirt.engine.core.vdsbroker.EffectiveHostNetworkQos;
import org.ovirt.engine.core.vdsbroker.NetworkImplementationDetailsUtils;
import org.ovirt.engine.core.vdsbroker.vdsbroker.HostNetworkTopologyPersister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@NonTransactiveCommandAttribute
public class HostSetupNetworksCommand<T extends HostSetupNetworksParameters> extends VdsCommand<T> {
private static final Logger log = LoggerFactory.getLogger(HostSetupNetworksCommand.class);
private static final String DEFAULT_BOND_OPTIONS = "mode=4 miimon=100 xmit_hash_policy=2";
private static final Set<Ipv6BootProtocol> IPV6_AUTO_BOOT_PROTOCOL =
EnumSet.of(Ipv6BootProtocol.DHCP, Ipv6BootProtocol.AUTOCONF);
private BusinessEntityMap<Network> networkBusinessEntityMap;
private Set<String> removedNetworks;
private Set<String> removedBondNames;
private List<VdsNetworkInterface> removedBonds;
private Set<String> removedUnmanagedNetworks;
private List<VdsNetworkInterface> existingNics;
private List<NetworkAttachment> existingAttachments;
private BusinessEntityMap<VdsNetworkInterface> existingNicsBusinessEntityMap;
private List<Network> clusterNetworks;
@Inject
private HostNetworkTopologyPersister hostNetworkTopologyPersister;
@Inject
private FindActiveVmsUsingNetwork findActiveVmsUsingNetwork;
private List<Network> modifiedNetworks;
@Inject
private NetworkAttachmentDao networkAttachmentDao;
@Inject
private IpConfigurationCompleter ipConfigurationCompleter;
@Inject
private NetworkIdNetworkNameCompleter networkIdNetworkNameCompleter;
@Inject
HostSetupNetworksValidatorHelper hostSetupNetworksValidatorHelper;
@Inject
private EffectiveHostNetworkQos effectiveHostNetworkQos;
@Inject
private NetworkImplementationDetailsUtils networkImplementationDetailsUtils;
@Inject
private NetworkExclusivenessValidatorResolver networkExclusivenessValidatorResolver;
@Inject
private NetworkAttachmentIpConfigurationValidator networkAttachmentIpConfigurationValidator;
@Inject
private UnmanagedNetworkValidator unmanagedNetworkValidator;
@Inject
private ManagementNetworkUtil managementNetworkUtil;
@Inject
private HostLocking hostLocking;
@Inject
private NetworkClusterHelper networkClusterHelper;
@Inject
private NetworkClusterDao networkClusterDao;
@Inject
private NetworkDao networkDao;
@Inject
private VdsDao vdsDao;
@Inject
private InterfaceDao interfaceDao;
@Inject
private VdsDynamicDao vdsDynamicDao;
@Inject
private VmDao vmDao;
public HostSetupNetworksCommand(T parameters) {
this(parameters, null);
}
public HostSetupNetworksCommand(T parameters, CommandContext commandContext) {
super(parameters, commandContext);
setVdsId(parameters.getVdsId());
}
@Override
protected void setActionMessageParameters() {
addValidationMessage(EngineMessage.VAR__ACTION__SETUP);
addValidationMessage(EngineMessage.VAR__TYPE__NETWORKS);
}
@Override
protected LockProperties applyLockProperties(LockProperties lockProperties) {
return lockProperties.withScope(Scope.Execution);
}
@Override
protected Map<String, Pair<String, String>> getExclusiveLocks() {
return hostLocking.getSetupNetworksLock(getParameters().getVdsId());
}
@Override
protected boolean validate() {
VDS host = getVds();
final ValidationResult hostValidatorResult = new HostValidator(host, isInternalExecution()).validate();
if (!hostValidatorResult.isValid()) {
return validate(hostValidatorResult);
}
completeMissingDataInParameters();
boolean requestValid = validateEntitiesFromRequest(getParameters().getNetworkAttachments()) &&
validateEntitiesFromRequest(getParameters().getCreateOrUpdateBonds());
if (!requestValid) {
return requestValid;
}
fillInUnsetBondingOptions();
IdQueryParameters idParameters = new IdQueryParameters(getVdsId());
VdcQueryReturnValue existingBondsResponse = runInternalQuery(VdcQueryType.GetHostBondsByHostId, idParameters);
if (!existingBondsResponse.getSucceeded()) {
return false;
}
List<VdsNetworkInterface> existingBonds = existingBondsResponse.getReturnValue();
removeUnchangedAttachments();
removeUnchangedBonds(existingBonds);
ValidationResult hostSetupNetworkValidatorResult = validateWithHostSetupNetworksValidator(host);
if (!hostSetupNetworkValidatorResult.isValid()) {
return validate(hostSetupNetworkValidatorResult);
}
return validate(checkForOutOfSyncNetworks());
}
private void completeMissingDataInParameters() {
NicNameNicIdCompleter nicNameNicIdCompleter = new NicNameNicIdCompleter(getExistingNics());
nicNameNicIdCompleter.completeNetworkAttachments(getParameters().getNetworkAttachments());
nicNameNicIdCompleter.completeBonds(getParameters().getCreateOrUpdateBonds());
nicNameNicIdCompleter.completeNetworkAttachments(getExistingAttachments());
nicNameNicIdCompleter.completeLabels(getParameters().getLabels());
ipConfigurationCompleter.fillInUnsetIpConfigs(getParameters().getNetworkAttachments());
networkIdNetworkNameCompleter.completeNetworkAttachments(
getParameters().getNetworkAttachments(),
getNetworkBusinessEntityMap());
networkIdNetworkNameCompleter.completeNetworkAttachments(
getExistingAttachments(),
getNetworkBusinessEntityMap());
NicLabelsCompleter labelsCompleter = new NicLabelsCompleter(getParameters(),
getExistingAttachments(),
getClusterNetworks(),
getExistingNicsBusinessEntityMap());
labelsCompleter.completeNetworkAttachments();
}
private boolean validateEntitiesFromRequest(List<? extends BusinessEntity<?>> newOrUpdateBusinessEntities) {
SeparateNewAndModifiedInstances instances = new SeparateNewAndModifiedInstances(newOrUpdateBusinessEntities);
List<String> validationMessages = new ArrayList<>();
validationMessages.addAll(callValidationOnAllItems(instances.getNewEntities(), CreateEntity.class, Default.class));
validationMessages.addAll(callValidationOnAllItems(instances.getUpdatedEntities(), UpdateEntity.class, Default.class));
return !getReturnValue().getValidationMessages().addAll(validationMessages);
}
private List<String> callValidationOnAllItems(List<BusinessEntity<?>> items, Class<?>... groups) {
List<String> validationMessages = new ArrayList<>();
for (BusinessEntity<?> businessEntity : items) {
validationMessages.addAll(ValidationUtils.validateInputs(Arrays.asList(groups), businessEntity));
}
return validationMessages;
}
private ValidationResult validateWithHostSetupNetworksValidator(VDS host) {
HostSetupNetworksValidator validator = new HostSetupNetworksValidator(host,
getParameters(),
getExistingNics(),
getExistingAttachments(),
getNetworkBusinessEntityMap(),
networkClusterDao,
networkDao,
vdsDao,
findActiveVmsUsingNetwork,
hostSetupNetworksValidatorHelper,
vmDao,
networkExclusivenessValidatorResolver,
networkAttachmentIpConfigurationValidator,
unmanagedNetworkValidator);
return validator.validate();
}
@Override
protected void executeCommand() {
if (noChangesDetected()) {
log.info("No changes were detected in setup networks for host '{}' (ID: '{}')", getVdsName(), getVdsId());
setSucceeded(true);
return;
}
try (EngineLock monitoringLock = acquireMonitorLock("Host setup networks")) {
int timeout = getSetupNetworksTimeout();
FutureVDSCall<VDSReturnValue> setupNetworksTask = invokeSetupNetworksCommand(timeout);
try {
VDSReturnValue retVal = setupNetworksTask.get(timeout, TimeUnit.SECONDS);
if (retVal != null) {
if (!retVal.getSucceeded() && retVal.getVdsError() == null && getParameters().rollbackOnFailure()) {
throw new EngineException(EngineError.SETUP_NETWORKS_ROLLBACK, retVal.getExceptionString());
}
VdsHandler.handleVdsResult(retVal);
if (retVal.getSucceeded()) {
VDSReturnValue returnValue =
runVdsCommand(VDSCommandType.GetCapabilities,
new VdsIdAndVdsVDSCommandParametersBase(getVds()));
VDS updatedHost = (VDS) returnValue.getReturnValue();
persistNetworkChanges(updatedHost);
}
setSucceeded(true);
}
} catch (TimeoutException e) {
log.debug("Host Setup networks command timed out for {} seconds", timeout);
}
}
}
private void removeUnchangedBonds(List<VdsNetworkInterface> existingNics) {
Map<Guid, VdsNetworkInterface> nicsById = Entities.businessEntitiesById(existingNics);
List<CreateOrUpdateBond> createOrUpdateBonds = getParameters().getCreateOrUpdateBonds();
for (Iterator<CreateOrUpdateBond> iterator = createOrUpdateBonds.iterator(); iterator.hasNext();) {
CreateOrUpdateBond bondFromRequest = iterator.next();
Guid idOfBondFromRequest = bondFromRequest.getId();
boolean bondFromRequestIsNewBond = idOfBondFromRequest == null;
if (!bondFromRequestIsNewBond) {
if (bondFromRequest.equalToBond((Bond) nicsById.get(idOfBondFromRequest))) {
iterator.remove();
}
}
}
}
/**
* @param existingNetworkAttachment {@link NetworkAttachment} to compare.
* @return true if passed in {@link NetworkAttachment networkAttachment} is deeply equal to {@code this}
* {@link NetworkAttachment}
*/
private boolean attachmentFromRequestIsEqualToAlreadyExistingOne(NetworkAttachment networkAttachmentFromRequest, NetworkAttachment existingNetworkAttachment) {
return existingNetworkAttachment != null
&& Objects.equals(networkAttachmentFromRequest.getId(), existingNetworkAttachment.getId())
&& Objects.equals(networkAttachmentFromRequest.getNetworkId(), existingNetworkAttachment.getNetworkId())
&& Objects.equals(networkAttachmentFromRequest.getNetworkName(), existingNetworkAttachment.getNetworkName())
&& Objects.equals(networkAttachmentFromRequest.getNicId(), existingNetworkAttachment.getNicId())
&& Objects.equals(networkAttachmentFromRequest.getHostNetworkQos(), existingNetworkAttachment.getHostNetworkQos())
&& Objects.equals(networkAttachmentFromRequest.getNicName(), existingNetworkAttachment.getNicName())
&& Objects.equals(networkAttachmentFromRequest.getIpConfiguration(), existingNetworkAttachment.getIpConfiguration())
&& Objects.equals(networkAttachmentFromRequest.getProperties(), existingNetworkAttachment.getProperties());
}
private void removeUnchangedAttachments() {
Map<Guid, NetworkAttachment> existingAttachmentsById = Entities.businessEntitiesById(getExistingAttachments());
for (Iterator<NetworkAttachment> iterator = getParameters().getNetworkAttachments().iterator(); iterator.hasNext();) {
NetworkAttachment attachmentFromRequest = iterator.next();
Guid idOfAttachmentFromRequest = attachmentFromRequest.getId();
boolean attachmentFromRequestIsNewAttachment = idOfAttachmentFromRequest == null;
// when flag 'isOverrideConfiguration' is set, NetworkAttachment from request cannot be ignored.
boolean overridingConfiguration = attachmentFromRequest.isOverrideConfiguration();
if (!attachmentFromRequestIsNewAttachment && !overridingConfiguration) {
NetworkAttachment existingAttachment = existingAttachmentsById.get(idOfAttachmentFromRequest);
if (attachmentFromRequestIsEqualToAlreadyExistingOne(attachmentFromRequest, existingAttachment)) {
iterator.remove();
}
}
}
}
private void fillInUnsetBondingOptions() {
for (CreateOrUpdateBond createOrUpdateBond : getParameters().getCreateOrUpdateBonds()) {
if (StringUtils.isEmpty(createOrUpdateBond.getBondOptions())) {
createOrUpdateBond.setBondOptions(DEFAULT_BOND_OPTIONS);
}
}
}
private ValidationResult checkForOutOfSyncNetworks() {
for (NetworkAttachment networkAttachment : getParameters().getNetworkAttachments()) {
boolean newNetworkAttachment = networkAttachment.getId() == null;
if (newNetworkAttachment) {
//attachment to be yet created cannot be out of sync.
continue;
}
boolean doNotCheckForOutOfSync = networkAttachment.isOverrideConfiguration();
if (doNotCheckForOutOfSync) {
continue;
}
Map<Guid, NetworkAttachment> existingNetworkAttachmentMap =
Entities.businessEntitiesById(getExistingAttachments());
NetworkAttachment existingNetworkAttachment = existingNetworkAttachmentMap.get(networkAttachment.getId());
VdsNetworkInterface nic =
NetworkUtils.hostInterfacesByNetworkName(getExistingNics())
.get(existingNetworkAttachment.getNetworkName());
NetworkImplementationDetails networkImplementationDetails = nic.getNetworkImplementationDetails();
boolean networkIsNotInSync = networkImplementationDetails != null && !networkImplementationDetails.isInSync();
if (networkIsNotInSync) {
return new ValidationResult(EngineMessage.NETWORKS_NOT_IN_SYNC,
ReplacementUtils.createSetVariableString("NETWORK_NOT_IN_SYNC",
existingNetworkAttachment.getNetworkName()));
}
}
return ValidationResult.VALID;
}
private FutureVDSCall<VDSReturnValue> invokeSetupNetworksCommand(int timeout) {
final HostSetupNetworksVdsCommandParameters parameters = createSetupNetworksParameters(timeout);
FutureVDSCall<VDSReturnValue> setupNetworksTask =
getVdsBroker().runFutureVdsCommand(FutureVDSCommandType.HostSetupNetworks, parameters);
if (parameters.isRollbackOnFailure()) {
HostSetupNetworkPoller poller = new HostSetupNetworkPoller();
while (!setupNetworksTask.isDone()) {
poller.poll(getVdsId());
}
}
return setupNetworksTask;
}
private HostSetupNetworksVdsCommandParameters createSetupNetworksParameters(int timeout) {
SwitchType clusterSwitchType = getCluster().getRequiredSwitchTypeForCluster();
List<HostNetwork> networksToConfigure = calculateNetworksToConfigure();
final HostSetupNetworksVdsCommandParameters hostCmdParams = new HostSetupNetworksVdsCommandParameters(
getVds(),
networksToConfigure,
getAllNetworksToRemove(),
getParameters().getCreateOrUpdateBonds(),
getRemovedBondNames(),
clusterSwitchType);
hostCmdParams.setRollbackOnFailure(getParameters().rollbackOnFailure());
hostCmdParams.setConnectivityTimeout(timeout);
hostCmdParams.setManagementNetworkChanged(isManagementNetworkChanged(networksToConfigure));
return hostCmdParams;
}
private Set<String> getAllNetworksToRemove() {
Set<String> result = new HashSet<>(getRemovedNetworks().size() + getRemovedUnmanagedNetworks().size());
result.addAll(getRemovedNetworks());
result.addAll(getRemovedUnmanagedNetworks());
return result;
}
private Integer getSetupNetworksTimeout() {
return getParameters().getConectivityTimeout() != null ? getParameters().getConectivityTimeout()
: Config.<Integer> getValue(ConfigValues.NetworkConnectivityCheckTimeoutInSeconds);
}
private boolean shouldSetDefaultRouteFlag(NetworkCluster networkCluster, NetworkAttachment networkAttachment) {
IpConfiguration ipConfiguration = networkAttachment.getIpConfiguration();
return networkCluster.isDefaultRoute()
&& ipConfiguration != null
&& (isIpv4GatewaySet(ipConfiguration) || isIpv6GatewaySet(ipConfiguration));
}
private boolean isIpv4GatewaySet(IpConfiguration ipConfiguration) {
return ipConfiguration.hasIpv4PrimaryAddressSet()
&& (ipConfiguration.getIpv4PrimaryAddress().getBootProtocol() == Ipv4BootProtocol.DHCP
|| ipConfiguration.getIpv4PrimaryAddress().getBootProtocol() == Ipv4BootProtocol.STATIC_IP
&& StringUtils.isNotEmpty(ipConfiguration.getIpv4PrimaryAddress().getGateway()));
}
private boolean isIpv6GatewaySet(IpConfiguration ipConfiguration) {
return ipConfiguration.hasIpv6PrimaryAddressSet()
&& (IPV6_AUTO_BOOT_PROTOCOL.contains(ipConfiguration.getIpv6PrimaryAddress().getBootProtocol())
|| ipConfiguration.getIpv6PrimaryAddress().getBootProtocol() == Ipv6BootProtocol.STATIC_IP
&& StringUtils.isNotEmpty(ipConfiguration.getIpv6PrimaryAddress().getGateway()));
}
private boolean noChangesDetected() {
return getParameters().isEmptyRequest();
}
private List<VdsNetworkInterface> getRemovedBonds() {
if (removedBonds == null) {
Set<Guid> removedBondIds = getParameters().getRemovedBonds();
removedBonds = Entities.filterEntitiesByRequiredIds(removedBondIds, getExistingNics());
}
return removedBonds;
}
private Set<String> getRemovedBondNames() {
if (removedBondNames == null) {
List<VdsNetworkInterface> existingVdsInterfaceToBeRemoved = getRemovedBonds();
Set<String> removedBondNames = new HashSet<>(existingVdsInterfaceToBeRemoved.size());
for (VdsNetworkInterface removedBondInterface : existingVdsInterfaceToBeRemoved) {
removedBondNames.add(removedBondInterface.getName());
}
this.removedBondNames = removedBondNames;
}
return removedBondNames;
}
private List<VdsNetworkInterface> getExistingNics() {
if (existingNics == null) {
existingNics = interfaceDao.getAllInterfacesForVds(getVdsId());
NetworkCommonUtils.fillBondSlaves(existingNics);
for (VdsNetworkInterface iface : existingNics) {
Network network = getNetworkBusinessEntityMap().get(iface.getNetworkName());
NetworkImplementationDetails networkImplementationDetails =
networkImplementationDetailsUtils.calculateNetworkImplementationDetails(iface, network);
iface.setNetworkImplementationDetails(networkImplementationDetails);
}
}
return existingNics;
}
private List<NetworkAttachment> getExistingAttachments() {
if (existingAttachments == null) {
existingAttachments = networkAttachmentDao.getAllForHost(getVdsId());
}
return existingAttachments;
}
private Set<String> getRemovedNetworks() {
if (removedNetworks == null) {
List<NetworkAttachment> removedNetworkAttachments =
Entities.filterEntitiesByRequiredIds(getParameters().getRemovedNetworkAttachments(),
existingAttachments);
removedNetworks = new HashSet<>(removedNetworkAttachments.size());
Map<Guid, NetworkAttachment> networkIdToAttachment =
new MapNetworkAttachments(getParameters().getNetworkAttachments()).byNetworkId();
for (NetworkAttachment removedAttachment : removedNetworkAttachments) {
if (!networkIdToAttachment.containsKey(removedAttachment.getNetworkId())) {
removedNetworks.add(existingNetworkRelatedToAttachment(removedAttachment).getName());
}
}
}
return removedNetworks;
}
private Set<String> getRemovedUnmanagedNetworks() {
if (removedUnmanagedNetworks == null) {
this.removedUnmanagedNetworks = new HashSet<>(getParameters().getRemovedUnmanagedNetworks());
}
return removedUnmanagedNetworks;
}
private List<HostNetwork> calculateNetworksToConfigure() {
List<HostNetwork> networksToConfigure = new ArrayList<>(getParameters().getNetworkAttachments().size());
BusinessEntityMap<VdsNetworkInterface> nics = getExistingNicsBusinessEntityMap();
for (NetworkAttachment attachment : getParameters().getNetworkAttachments()) {
Network network = existingNetworkRelatedToAttachment(attachment);
NetworkCluster networkCluster = network.getCluster();
HostNetwork networkToConfigure = new HostNetwork(network, attachment);
networkToConfigure.setBonding(isBonding(attachment, nics));
if (defaultRouteSupported() && shouldSetDefaultRouteFlag(networkCluster, attachment)) {
// TODO: YZ - should default route be set separately for IPv4 and IPv6
networkToConfigure.setDefaultRoute(true);
}
if (NetworkUtils.qosConfiguredOnInterface(attachment, network)) {
networkToConfigure.setQosConfiguredOnInterface(true);
HostNetworkQos hostNetworkQos = effectiveHostNetworkQos.getQos(attachment, network);
networkToConfigure.setQos(hostNetworkQos);
}
networksToConfigure.add(networkToConfigure);
}
return networksToConfigure;
}
private BusinessEntityMap<VdsNetworkInterface> getExistingNicsBusinessEntityMap() {
if (existingNicsBusinessEntityMap == null) {
existingNicsBusinessEntityMap = new BusinessEntityMap<>(getExistingNics());
}
return existingNicsBusinessEntityMap;
}
private boolean defaultRouteSupported() {
Set<Version> supportedClusterVersionsSet = getVds().getSupportedClusterVersionsSet();
if (supportedClusterVersionsSet == null || supportedClusterVersionsSet.isEmpty()) {
log.warn("Host '{}' ('{}') doesn't contain Supported Cluster Versions, "
+ "therefore 'defaultRoute' will not be sent via the SetupNetworks",
getVdsName(),
getVdsId());
return false;
}
return true;
}
private boolean isBonding(NetworkAttachment attachment, BusinessEntityMap<VdsNetworkInterface> nics) {
for (CreateOrUpdateBond bond : getParameters().getCreateOrUpdateBonds()) {
if (bond.getName() != null && bond.getName().equals(attachment.getNicName())) {
return true;
}
}
VdsNetworkInterface attachedNic = nics.get(attachment.getNicId(), attachment.getNicName());
Validate.notNull(attachedNic, "NicId/NicName must refer to a resolvable interface");
return Boolean.TRUE.equals(attachedNic.getBonded());
}
private Map<String, UserOverriddenNicValues> applyUserConfiguredNics() {
List<VdsNetworkInterface> nicsToConfigure = getExistingInterfacesAndNewlyCreatedBonds();
updateLabelsOnNicsToConfigure(nicsToConfigure);
return nicsToConfigure.stream()
.collect(Collectors.toMap(VdsNetworkInterface::getName,
nic -> new UserOverriddenNicValues(nic.getLabels())));
}
private void updateLabelsOnNicsToConfigure(List<VdsNetworkInterface> nicsToConfigure) {
Map<String, VdsNetworkInterface> nicsToConfigureByName = Entities.entitiesByName(nicsToConfigure);
clearLabelsFromRemovedBonds(nicsToConfigureByName);
updateAddedModifiedLabelsOnNics(nicsToConfigureByName);
updateRemovedLabelOnNics(nicsToConfigureByName);
}
private void updateRemovedLabelOnNics(Map<String, VdsNetworkInterface> nicsToConfigureByName) {
Map<String, VdsNetworkInterface> labelToNic = getLabelToNic(nicsToConfigureByName.values());
for (String removedLabel : getParameters().getRemovedLabels()) {
VdsNetworkInterface nicWithLabel = labelToNic.get(removedLabel);
if (nicWithLabel != null) {
nicWithLabel.getLabels().remove(removedLabel);
}
}
}
private void updateAddedModifiedLabelsOnNics(Map<String, VdsNetworkInterface> nicsToConfigureByName) {
Map<String, VdsNetworkInterface> labelToExistingNic = getLabelToNic(nicsToConfigureByName.values());
for (NicLabel nicLabel : getParameters().getLabels()) {
VdsNetworkInterface currentLabelNic = labelToExistingNic.get(nicLabel.getLabel());
VdsNetworkInterface newLabelNic = nicsToConfigureByName.get(nicLabel.getNicName());
moveLabel(nicLabel.getLabel(), currentLabelNic, newLabelNic);
}
}
private void moveLabel(String label,
VdsNetworkInterface currentLabelNic,
VdsNetworkInterface newLabelNic) {
if (currentLabelNic != null && currentLabelNic.getName().equals(newLabelNic.getName())) {
return;
}
// Add label to new nic
Set<String> labelsOnNic = newLabelNic.getLabels();
if (labelsOnNic == null) {
labelsOnNic = new HashSet<>();
newLabelNic.setLabels(labelsOnNic);
}
labelsOnNic.add(label);
// Remove labels from current nic
if (currentLabelNic != null) {
currentLabelNic.getLabels().remove(label);
}
}
private void clearLabelsFromRemovedBonds(Map<String, VdsNetworkInterface> nicsToConfigureByName) {
for (VdsNetworkInterface existingBondToRemove : getRemovedBonds()) {
nicsToConfigureByName.get(existingBondToRemove.getName()).setLabels(null);
}
}
private List<VdsNetworkInterface> getExistingInterfacesAndNewlyCreatedBonds() {
List<VdsNetworkInterface> nicsToConfigure = new ArrayList<>();
nicsToConfigure.addAll(interfaceDao.getAllInterfacesForVds(getVdsId()));
for (CreateOrUpdateBond createOrUpdateBond : getParameters().getCreateOrUpdateBonds()) {
if (createOrUpdateBond.getId() == null) {
Bond newBond = new Bond(createOrUpdateBond.getName());
nicsToConfigure.add(newBond);
}
}
return nicsToConfigure;
}
private Map<String, VdsNetworkInterface> getLabelToNic(Collection<VdsNetworkInterface> nics) {
Map<String, VdsNetworkInterface> labelToNic = new HashMap<>();
for (VdsNetworkInterface nic : nics) {
if (NetworkUtils.isLabeled(nic)) {
for (String label : nic.getLabels()) {
labelToNic.put(label, nic);
}
}
}
return labelToNic;
}
private List<Network> getModifiedNetworks() {
if (modifiedNetworks == null) {
List<NetworkAttachment> networkAttachments = getParameters().getNetworkAttachments();
modifiedNetworks = new ArrayList<>(networkAttachments.size());
for (NetworkAttachment attachment : networkAttachments) {
modifiedNetworks.add(existingNetworkRelatedToAttachment(attachment));
}
}
return modifiedNetworks;
}
private Network existingNetworkRelatedToAttachment(NetworkAttachment attachment) {
return getNetworkBusinessEntityMap().get(attachment.getNetworkId());
}
private void persistNetworkChanges(final VDS updatedHost) {
TransactionSupport.executeInNewTransaction(() -> {
UserConfiguredNetworkData userConfiguredNetworkData =
new UserConfiguredNetworkData(getParameters().getNetworkAttachments(),
getParameters().getRemovedNetworkAttachments(),
applyUserConfiguredNics());
// save the new network topology to DB
hostNetworkTopologyPersister.persistAndEnforceNetworkCompliance(updatedHost,
false,
userConfiguredNetworkData);
vdsDynamicDao.updateNetConfigDirty(updatedHost.getId(), updatedHost.getNetConfigDirty());
// Update cluster networks (i.e. check if need to activate each new network)
networkClusterHelper.setStatus(getClusterId(), getModifiedNetworks());
return null;
});
}
private BusinessEntityMap<Network> getNetworkBusinessEntityMap() {
if (networkBusinessEntityMap == null) {
networkBusinessEntityMap = new BusinessEntityMap<>(getClusterNetworks());
}
return networkBusinessEntityMap;
}
private List<Network> getClusterNetworks() {
if (clusterNetworks == null) {
clusterNetworks = networkDao.getAllForCluster(getClusterId());
}
return clusterNetworks;
}
private boolean isManagementNetworkChanged(List<HostNetwork> networksToConfigure){
Network managementNetwork = managementNetworkUtil.getManagementNetwork(getClusterNetworks(), getClusterId());
String managementNetworkName = managementNetwork.getName();
for (HostNetwork network : networksToConfigure) {
if (managementNetworkName.equals(network.getNetworkName())){
return true;
}
}
for (CreateOrUpdateBond createOrUpdateBond : getParameters().getCreateOrUpdateBonds()) {
// We are only interested in existing bonds, whose bonding options/slave have changed, so it
// enough to check existing bonds. New bonds which have the management network
// are covered by network attachments
VdsNetworkInterface bondNic = getExistingNicsBusinessEntityMap().get(createOrUpdateBond.getId());
if (bondNic != null && managementNetworkName.equals(bondNic.getNetworkName())) {
return true;
}
}
return false;
}
}