package org.ovirt.engine.core.bll.network; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Function; import org.ovirt.engine.core.bll.Backend; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.bll.host.HostConnectivityChecker; import org.ovirt.engine.core.bll.interfaces.BackendInternal; import org.ovirt.engine.core.bll.network.cluster.ManagementNetworkUtil; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.FeatureSupported; import org.ovirt.engine.core.common.action.HostSetupNetworksParameters; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.common.action.VdsActionParameters; import org.ovirt.engine.core.common.businessentities.Entities; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.network.IpConfiguration; 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.VdsNetworkInterface; import org.ovirt.engine.core.common.utils.NetworkCommonUtils; import org.ovirt.engine.core.common.vdscommands.CollectHostNetworkDataVdsCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogable; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableImpl; import org.ovirt.engine.core.di.Injector; import org.ovirt.engine.core.utils.NetworkUtils; import org.ovirt.engine.core.utils.network.function.NicToIpv4AddressFunction; import org.ovirt.engine.core.utils.network.function.NicToIpv6AddressFunction; import org.ovirt.engine.core.utils.network.predicate.InterfaceByNetworkNamePredicate; import org.ovirt.engine.core.utils.transaction.TransactionSupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class NetworkConfigurator { private static final Logger log = LoggerFactory.getLogger(NetworkConfigurator.class); private static final String MANAGEMENT_NETWORK_CONFIG_ERR = "Failed to configure management network"; private final VDS host; private final AuditLogDirector auditLogDirector; private final Network managementNetwork; private CommandContext commandContext; NetworkConfigurator(VDS host, CommandContext commandContext, AuditLogDirector auditLogDirector) { this.host = host; this.commandContext = commandContext; this.auditLogDirector = auditLogDirector; this.managementNetwork = getManagementNetworkUtil().getManagementNetwork(host.getClusterId()); } public NetworkConfigurator(VDS host, CommandContext commandContext) { this(host, commandContext, new AuditLogDirector()); } public void createManagementNetworkIfRequired() { if (host == null) { return; } final String hostIp = NetworkUtils.getHostIp(host); final String managementNetworkName = managementNetwork.getName(); final String hostManagementNetworkIpv4Address = getIpv4AddressOfNetwork(managementNetworkName); final String hostManagementNetworkIpv6Address = getIpv6AddressOfNetwork(managementNetworkName); if ((hostManagementNetworkIpv4Address != null && hostManagementNetworkIpv4Address.equals(hostIp)) || (hostManagementNetworkIpv6Address != null && hostManagementNetworkIpv6Address.equals(hostIp))) { log.info("The management network '{}' is already configured on host '{}'", managementNetworkName, host.getName()); return; } VdsNetworkInterface nic = findNicToSetupManagementNetwork(); if (nic == null) { return; } List<VdsNetworkInterface> interfaces = filterBondsWithoutSlaves(host.getInterfaces()); if (interfaces.contains(nic)) { configureManagementNetwork(createSetupNetworkParams(nic)); } else { final AuditLogable event = createEvent(); event.addCustomValue("InterfaceName", nic.getName()); auditLogDirector.log(event, AuditLogType.INVALID_BOND_INTERFACE_FOR_MANAGEMENT_NETWORK_CONFIGURATION); throw new NetworkConfiguratorException(MANAGEMENT_NETWORK_CONFIG_ERR); } } String getIpv4AddressOfNetwork(String networkName) { return resolveHostNetworkAddress(networkName, VdsNetworkInterface::getIpv4Address); } String getIpv6AddressOfNetwork(String networkName) { return resolveHostNetworkAddress(networkName, VdsNetworkInterface::getIpv6Address); } private String resolveHostNetworkAddress(String networkName, Function<VdsNetworkInterface, String> ipFunction) { if (networkName == null) { return null; } return host.getInterfaces() .stream() .filter(new InterfaceByNetworkNamePredicate(networkName)) .map(ipFunction) .filter(Objects::nonNull) .findFirst() .orElse(null); } private ManagementNetworkUtil getManagementNetworkUtil() { return Injector.get(ManagementNetworkUtil.class); } public boolean awaitVdsmResponse() { return new HostConnectivityChecker().check(host); } public void refreshNetworkConfiguration() { TransactionSupport.executeInNewTransaction(() -> { getBackend().getResourceManager().runVdsCommand(VDSCommandType.CollectVdsNetworkDataAfterInstallation, new CollectHostNetworkDataVdsCommandParameters(host)); return null; }); } public HostSetupNetworksParameters createSetupNetworkParams(VdsNetworkInterface nic) { HostSetupNetworksParameters parameters = new HostSetupNetworksParameters(host.getId()); NetworkAttachment managementAttachment = new NetworkAttachment(); managementAttachment.setNetworkId(managementNetwork.getId()); Map<String, VdsNetworkInterface> nicNameToNic = Entities.entitiesByName(host.getInterfaces()); Guid baseNicId = nicNameToNic.get(NetworkCommonUtils.stripVlan(nic)).getId(); managementAttachment.setNicId(baseNicId); IpConfiguration ipConfiguration = new IpConfiguration(); ipConfiguration.setIPv4Addresses(Collections.singletonList(new NicToIpv4AddressFunction().apply(nic))); if (FeatureSupported.ipv6Supported(host.getClusterCompatibilityVersion())) { ipConfiguration.setIpV6Addresses(Collections.singletonList(new NicToIpv6AddressFunction().apply(nic))); } managementAttachment.setIpConfiguration(ipConfiguration); parameters.getNetworkAttachments().add(managementAttachment); return parameters; } private VdsNetworkInterface findNicToSetupManagementNetwork() { VdsNetworkInterface nic = Entities.entitiesByName(host.getInterfaces()).get(host.getActiveNic()); if (nic == null) { log.warn("Failed to find a valid interface for the management network of host {}." + " If the interface {} is a bridge, it should be torn-down manually.", host.getName(), host.getActiveNic()); throw new NetworkConfiguratorException( String.format("Interface %s is invalid for management network", host.getActiveNic())); } if (managementNetwork.getName().equals(nic.getNetworkName())) { return null; } if (!nicHasValidVlanId(managementNetwork, nic)) { final AuditLogable event = createEvent(); event.addCustomValue("VlanId", resolveVlanId(nic.getVlanId())); event.addCustomValue("MgmtVlanId", resolveVlanId(managementNetwork.getVlanId())); event.addCustomValue("InterfaceName", nic.getName()); auditLogDirector.log(event, AuditLogType.VLAN_ID_MISMATCH_FOR_MANAGEMENT_NETWORK_CONFIGURATION); throw new NetworkConfiguratorException(MANAGEMENT_NETWORK_CONFIG_ERR); } return nic; } private AuditLogable createEvent() { final AuditLogable event = new AuditLogableImpl(); event.setVdsName(host.getName()); event.setVdsId(host.getId()); return event; } private String resolveVlanId(Integer vlanId) { return vlanId == null ? "none" : vlanId.toString(); } private boolean nicHasValidVlanId(Network network, VdsNetworkInterface nic) { int nicVlanId = nic.getVlanId() == null ? 0 : nic.getVlanId(); int mgmtVlanId = network.getVlanId() == null ? 0 : network.getVlanId(); return nicVlanId == mgmtVlanId; } /** * filters out bonds with less than two slaves. * @return all non-bonds and bonds with two or more slaves. */ public List<VdsNetworkInterface> filterBondsWithoutSlaves(List<VdsNetworkInterface> interfaces) { List<VdsNetworkInterface> filteredList = new ArrayList<>(); Map<String, Integer> bonds = new HashMap<>(); for (VdsNetworkInterface iface : interfaces) { if (Boolean.TRUE.equals(iface.getBonded())) { bonds.put(iface.getName(), 0); } } for (VdsNetworkInterface iface : interfaces) { if (bonds.containsKey(iface.getBondName())) { bonds.put(iface.getBondName(), bonds.get(iface.getBondName()) + 1); } } for (VdsNetworkInterface iface : interfaces) { if (!bonds.containsKey(iface.getName()) || bonds.get(iface.getName()) >= 2) { filteredList.add(iface); } } return filteredList; } private void configureManagementNetwork(HostSetupNetworksParameters parameters) { VdcReturnValueBase retVal = getBackend().runInternalAction(VdcActionType.HostSetupNetworks, parameters, cloneContextAndDetachFromParent()); if (retVal.getSucceeded()) { retVal = getBackend().runInternalAction(VdcActionType.CommitNetworkChanges, new VdsActionParameters(parameters.getVdsId()), cloneContextAndDetachFromParent()); if (!retVal.getSucceeded()) { auditLogDirector.log(createEvent(), AuditLogType.PERSIST_NETWORK_FAILED_FOR_MANAGEMENT_NETWORK); throw new NetworkConfiguratorException(MANAGEMENT_NETWORK_CONFIG_ERR); } } else { auditLogDirector.log(createEvent(), AuditLogType.SETUP_NETWORK_FAILED_FOR_MANAGEMENT_NETWORK_CONFIGURATION); throw new NetworkConfiguratorException(MANAGEMENT_NETWORK_CONFIG_ERR); } } BackendInternal getBackend() { return Backend.getInstance(); } private CommandContext cloneContextAndDetachFromParent() { return commandContext.clone().withoutCompensationContext().withoutExecutionContext().withoutLock(); } public static class NetworkConfiguratorException extends RuntimeException { private static final long serialVersionUID = 3526212482581207006L; public NetworkConfiguratorException(String message) { super(message); } } }