blob: 56039b52c2ac08f867482cab9f8734ebc8cc569a [file] [log] [blame]
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.api;
import com.google.common.base.MoreObjects;
import org.apache.commons.lang.StringUtils;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.k8snode.api.K8sApiConfig.Mode;
import org.onosproject.net.Annotations;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
import java.util.Objects;
import java.util.UUID;
import static com.google.common.base.Preconditions.checkArgument;
import static org.onosproject.k8snode.api.Constants.DEFAULT_CLUSTER_NAME;
import static org.onosproject.k8snode.api.Constants.EXTERNAL_BRIDGE;
import static org.onosproject.k8snode.api.Constants.GENEVE_TUNNEL;
import static org.onosproject.k8snode.api.Constants.GRE_TUNNEL;
import static org.onosproject.k8snode.api.Constants.INTEGRATION_BRIDGE;
import static org.onosproject.k8snode.api.Constants.INTEGRATION_TO_EXTERNAL_BRIDGE;
import static org.onosproject.k8snode.api.Constants.INTEGRATION_TO_LOCAL_BRIDGE;
import static org.onosproject.k8snode.api.Constants.INTEGRATION_TO_TUN_BRIDGE;
import static org.onosproject.k8snode.api.Constants.LOCAL_BRIDGE;
import static org.onosproject.k8snode.api.Constants.LOCAL_TO_INTEGRATION_BRIDGE;
import static org.onosproject.k8snode.api.Constants.PHYSICAL_EXTERNAL_BRIDGE;
import static org.onosproject.k8snode.api.Constants.TUNNEL_BRIDGE;
import static org.onosproject.k8snode.api.Constants.TUN_TO_INTEGRATION_BRIDGE;
import static org.onosproject.k8snode.api.Constants.VXLAN_TUNNEL;
import static org.onosproject.k8snode.api.K8sApiConfig.Mode.NORMAL;
import static org.onosproject.k8snode.api.K8sApiConfig.Mode.PASSTHROUGH;
import static org.onosproject.net.AnnotationKeys.PORT_NAME;
/**
* Representation of a kubernetes node.
*/
public class DefaultK8sNode implements K8sNode {
private static final String PORT_MAC = "portMac";
private static final String FLOW_KEY = "flow";
private static final int SHORT_NAME_LENGTH = 10;
private final String clusterName;
private final String hostname;
private final Type type;
private final int segmentId;
private final Mode mode;
private final DeviceId intgBridge;
private final DeviceId extBridge;
private final DeviceId localBridge;
private final DeviceId tunBridge;
private final IpAddress managementIp;
private final IpAddress dataIp;
private final K8sNodeState state;
private final String extIntf;
private final K8sExternalNetwork extNetwork;
private final String podCidr;
private static final String NOT_NULL_MSG = "Node % cannot be null";
private static final String OVSDB = "ovsdb:";
/**
* A default constructor of kubernetes Node.
*
* @param clusterName clusterName
* @param hostname hostname
* @param type node type
* @param segmentId segment identifier
* @param mode CNI running mode
* @param intgBridge integration bridge
* @param extBridge external bridge
* @param localBridge local bridge
* @param tunBridge tunnel bridge
* @param extIntf external interface
* @param managementIp management IP address
* @param dataIp data IP address
* @param state node state
* @param extNetwork external network
* @param podCidr POD CIDR
*/
protected DefaultK8sNode(String clusterName, String hostname, Type type,
int segmentId, Mode mode, DeviceId intgBridge,
DeviceId extBridge, DeviceId localBridge,
DeviceId tunBridge, String extIntf, IpAddress managementIp,
IpAddress dataIp, K8sNodeState state,
K8sExternalNetwork extNetwork, String podCidr) {
this.clusterName = clusterName;
this.hostname = hostname;
this.type = type;
this.mode = mode;
this.segmentId = segmentId;
this.intgBridge = intgBridge;
this.extBridge = extBridge;
this.localBridge = localBridge;
this.tunBridge = tunBridge;
this.extIntf = extIntf;
this.managementIp = managementIp;
this.dataIp = dataIp;
this.state = state;
this.extNetwork = extNetwork;
this.podCidr = podCidr;
}
@Override
public String clusterName() {
return clusterName;
}
@Override
public String hostShortName() {
return StringUtils.substring(hostname, 0, SHORT_NAME_LENGTH);
}
@Override
public String uniqueString(int length) {
String uuid = UUID.nameUUIDFromBytes(hostname.getBytes()).toString();
return StringUtils.substring(uuid, 0, length);
}
@Override
public int segmentId() {
return segmentId;
}
@Override
public String tunnelKey() {
if (mode == PASSTHROUGH) {
return String.valueOf(segmentId);
} else {
return FLOW_KEY;
}
}
@Override
public Mode mode() {
return mode;
}
@Override
public String hostname() {
return hostname;
}
@Override
public Type type() {
return type;
}
@Override
public DeviceId ovsdb() {
return DeviceId.deviceId(OVSDB + managementIp().toString());
}
@Override
public DeviceId intgBridge() {
return intgBridge;
}
@Override
public DeviceId extBridge() {
return extBridge;
}
@Override
public DeviceId localBridge() {
return localBridge;
}
@Override
public DeviceId tunBridge() {
return tunBridge;
}
@Override
public String extIntf() {
return extIntf;
}
@Override
public K8sNode updateIntgBridge(DeviceId deviceId) {
return new Builder()
.hostname(hostname)
.clusterName(clusterName)
.type(type)
.segmentId(segmentId)
.mode(mode)
.intgBridge(deviceId)
.extBridge(extBridge)
.localBridge(localBridge)
.tunBridge(tunBridge)
.extIntf(extIntf)
.managementIp(managementIp)
.dataIp(dataIp)
.state(state)
.extBridgeIp(extNetwork.extBridgeIp())
.extGatewayIp(extNetwork.extGatewayIp())
.extGatewayMac(extNetwork.extGatewayMac())
.podCidr(podCidr)
.build();
}
@Override
public K8sNode updateExtBridge(DeviceId deviceId) {
return new Builder()
.hostname(hostname)
.clusterName(clusterName)
.type(type)
.segmentId(segmentId)
.mode(mode)
.intgBridge(intgBridge)
.extBridge(deviceId)
.localBridge(localBridge)
.tunBridge(tunBridge)
.extIntf(extIntf)
.managementIp(managementIp)
.dataIp(dataIp)
.state(state)
.extBridgeIp(extNetwork.extBridgeIp())
.extGatewayIp(extNetwork.extGatewayIp())
.extGatewayMac(extNetwork.extGatewayMac())
.podCidr(podCidr)
.build();
}
@Override
public K8sNode updateLocalBridge(DeviceId deviceId) {
return new Builder()
.hostname(hostname)
.clusterName(clusterName)
.type(type)
.segmentId(segmentId)
.mode(mode)
.intgBridge(intgBridge)
.extBridge(extBridge)
.localBridge(deviceId)
.tunBridge(tunBridge)
.extIntf(extIntf)
.managementIp(managementIp)
.dataIp(dataIp)
.state(state)
.extBridgeIp(extNetwork.extBridgeIp())
.extGatewayIp(extNetwork.extGatewayIp())
.extGatewayMac(extNetwork.extGatewayMac())
.podCidr(podCidr)
.build();
}
@Override
public K8sNode updateTunBridge(DeviceId deviceId) {
return new Builder()
.hostname(hostname)
.clusterName(clusterName)
.type(type)
.segmentId(segmentId)
.mode(mode)
.intgBridge(intgBridge)
.extBridge(extBridge)
.localBridge(localBridge)
.tunBridge(deviceId)
.extIntf(extIntf)
.managementIp(managementIp)
.dataIp(dataIp)
.state(state)
.extBridgeIp(extNetwork.extBridgeIp())
.extGatewayIp(extNetwork.extGatewayIp())
.extGatewayMac(extNetwork.extGatewayMac())
.podCidr(podCidr)
.build();
}
@Override
public IpAddress managementIp() {
return managementIp;
}
@Override
public IpAddress dataIp() {
return dataIp;
}
@Override
public K8sNodeState state() {
return state;
}
@Override
public String podCidr() {
return podCidr;
}
@Override
public K8sNode updateState(K8sNodeState newState) {
return new Builder()
.hostname(hostname)
.clusterName(clusterName)
.type(type)
.segmentId(segmentId)
.mode(mode)
.intgBridge(intgBridge)
.extBridge(extBridge)
.localBridge(localBridge)
.tunBridge(tunBridge)
.extIntf(extIntf)
.managementIp(managementIp)
.dataIp(dataIp)
.state(newState)
.extBridgeIp(extNetwork.extBridgeIp())
.extGatewayIp(extNetwork.extGatewayIp())
.extGatewayMac(extNetwork.extGatewayMac())
.podCidr(podCidr)
.build();
}
@Override
public K8sNode updateExtGatewayMac(MacAddress newMac) {
return new Builder()
.hostname(hostname)
.clusterName(clusterName)
.type(type)
.segmentId(segmentId)
.mode(mode)
.intgBridge(intgBridge)
.extBridge(extBridge)
.localBridge(localBridge)
.tunBridge(tunBridge)
.extIntf(extIntf)
.managementIp(managementIp)
.dataIp(dataIp)
.state(state)
.extBridgeIp(extNetwork.extBridgeIp())
.extGatewayIp(extNetwork.extGatewayIp())
.extGatewayMac(newMac)
.podCidr(podCidr)
.build();
}
@Override
public PortNumber grePortNum() {
return tunnelPortNum(grePortName());
}
@Override
public PortNumber vxlanPortNum() {
return tunnelPortNum(vxlanPortName());
}
@Override
public PortNumber genevePortNum() {
return tunnelPortNum(genevePortName());
}
@Override
public PortNumber intgBridgePortNum() {
return portNumber(intgBridge, intgBridgePortName());
}
@Override
public PortNumber intgToExtPatchPortNum() {
return portNumber(intgBridge, intgToExtPatchPortName());
}
@Override
public PortNumber intgToLocalPatchPortNum() {
return portNumber(intgBridge, intgToLocalPatchPortName());
}
@Override
public PortNumber localToIntgPatchPortNum() {
return portNumber(localBridge, localToIntgPatchPortName());
}
@Override
public PortNumber extToIntgPatchPortNum() {
return portNumber(extBridge, extToIntgPatchPortName());
}
@Override
public PortNumber extBridgePortNum() {
if (this.extIntf == null) {
return null;
}
return portNumber(extBridge, extBridgePortName());
}
@Override
public MacAddress intgBridgeMac() {
return macAddress(intgBridge, intgBridgeName());
}
@Override
public IpAddress extBridgeIp() {
return extNetwork.extBridgeIp();
}
@Override
public MacAddress extBridgeMac() {
return macAddress(extBridge, extBridgeName());
}
@Override
public IpAddress extGatewayIp() {
return extNetwork.extGatewayIp();
}
@Override
public MacAddress extGatewayMac() {
return extNetwork.extGatewayMac();
}
@Override
public String grePortName() {
if (mode == PASSTHROUGH) {
return GRE_TUNNEL + "-" + segmentId;
} else {
return GRE_TUNNEL;
}
}
@Override
public String vxlanPortName() {
if (mode == PASSTHROUGH) {
return VXLAN_TUNNEL + "-" + segmentId;
} else {
return VXLAN_TUNNEL;
}
}
@Override
public String genevePortName() {
if (mode == PASSTHROUGH) {
return GENEVE_TUNNEL + "-" + segmentId;
} else {
return GENEVE_TUNNEL;
}
}
@Override
public String intgBridgeName() {
if (mode == PASSTHROUGH) {
return INTEGRATION_BRIDGE + "-" + uniqueString(5);
} else {
return INTEGRATION_BRIDGE;
}
}
@Override
public String extBridgeName() {
if (mode == PASSTHROUGH) {
return EXTERNAL_BRIDGE + "-" + uniqueString(5);
} else {
return EXTERNAL_BRIDGE;
}
}
@Override
public String localBridgeName() {
if (mode == PASSTHROUGH) {
return LOCAL_BRIDGE + "-" + uniqueString(5);
} else {
return LOCAL_BRIDGE;
}
}
@Override
public String tunBridgeName() {
if (mode == PASSTHROUGH) {
return TUNNEL_BRIDGE + "-" + segmentId;
} else {
return TUNNEL_BRIDGE;
}
}
@Override
public String intgBridgePortName() {
if (mode == PASSTHROUGH) {
return INTEGRATION_BRIDGE + "-" + uniqueString(5);
} else {
return INTEGRATION_BRIDGE;
}
}
@Override
public String extBridgePortName() {
if (mode == PASSTHROUGH) {
return EXTERNAL_BRIDGE + "-" + uniqueString(5);
} else {
return EXTERNAL_BRIDGE;
}
}
@Override
public String localBridgePortName() {
if (mode == PASSTHROUGH) {
return LOCAL_BRIDGE + "-" + uniqueString(5);
} else {
return LOCAL_BRIDGE;
}
}
@Override
public String intgToExtPatchPortName() {
if (mode == PASSTHROUGH) {
return INTEGRATION_TO_EXTERNAL_BRIDGE + "-" + uniqueString(5);
} else {
return INTEGRATION_TO_EXTERNAL_BRIDGE;
}
}
@Override
public String intgToTunPatchPortName() {
if (mode == PASSTHROUGH) {
return INTEGRATION_TO_TUN_BRIDGE + "-" + uniqueString(5);
} else {
return INTEGRATION_TO_TUN_BRIDGE;
}
}
@Override
public String intgToLocalPatchPortName() {
if (mode == PASSTHROUGH) {
return INTEGRATION_TO_LOCAL_BRIDGE + "-" + uniqueString(5);
} else {
return INTEGRATION_TO_LOCAL_BRIDGE;
}
}
@Override
public String localToIntgPatchPortName() {
if (mode == PASSTHROUGH) {
return LOCAL_TO_INTEGRATION_BRIDGE + "-" + uniqueString(5);
} else {
return LOCAL_TO_INTEGRATION_BRIDGE;
}
}
@Override
public String extToIntgPatchPortName() {
if (mode == PASSTHROUGH) {
return PHYSICAL_EXTERNAL_BRIDGE + "-" + uniqueString(5);
} else {
return PHYSICAL_EXTERNAL_BRIDGE;
}
}
@Override
public String tunToIntgPatchPortName() {
if (mode == PASSTHROUGH) {
return TUN_TO_INTEGRATION_BRIDGE + "-" + uniqueString(5);
} else {
return TUN_TO_INTEGRATION_BRIDGE;
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DefaultK8sNode) {
DefaultK8sNode that = (DefaultK8sNode) obj;
return clusterName.equals(that.clusterName) &&
hostname.equals(that.hostname) &&
type == that.type &&
segmentId == that.segmentId &&
mode == that.mode &&
intgBridge.equals(that.intgBridge) &&
extBridge.equals(that.extBridge) &&
localBridge.equals(that.localBridge) &&
tunBridge.equals(that.tunBridge) &&
extIntf.equals(that.extIntf) &&
managementIp.equals(that.managementIp) &&
dataIp.equals(that.dataIp) &&
extNetwork.equals(that.extNetwork) &&
podCidr.equals(that.podCidr) &&
state == that.state;
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(clusterName, hostname, type, segmentId, mode, intgBridge, extBridge,
localBridge, tunBridge, extIntf, managementIp, dataIp, state, extNetwork, podCidr);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("clusterName", clusterName)
.add("hostname", hostname)
.add("type", type)
.add("segmentId", segmentId)
.add("mode", mode)
.add("intgBridge", intgBridge)
.add("extBridge", extBridge)
.add("localBridge", localBridge)
.add("tunBridge", tunBridge)
.add("extIntf", extIntf)
.add("managementIp", managementIp)
.add("dataIp", dataIp)
.add("state", state)
.add("extBridgeIp", extNetwork.extBridgeIp())
.add("extGatewayIp", extNetwork.extGatewayIp())
.add("extGatewayMac", extNetwork.extGatewayMac())
.add("podCidr", podCidr)
.toString();
}
private PortNumber tunnelPortNum(String tunnelType) {
if (dataIp == null) {
return null;
}
return portNumber(tunBridge, tunnelType);
}
private MacAddress macAddress(DeviceId deviceId, String portName) {
Port port = port(deviceId, portName);
Annotations annots = port.annotations();
return annots != null ? MacAddress.valueOf(annots.value(PORT_MAC)) : null;
}
private PortNumber portNumber(DeviceId deviceId, String portName) {
Port port = port(deviceId, portName);
return port != null ? port.number() : null;
}
private Port port(DeviceId deviceId, String portName) {
DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
return deviceService.getPorts(deviceId).stream()
.filter(p -> p.isEnabled() &&
Objects.equals(p.annotations().value(PORT_NAME), portName))
.findAny().orElse(null);
}
/**
* Returns new builder instance.
*
* @return kubernetes node builder
*/
public static Builder builder() {
return new Builder();
}
/**
* Returns new builder instance with the given node as a default value.
*
* @param node kubernetes node
* @return kubernetes node builder
*/
public static Builder from(K8sNode node) {
return new Builder()
.hostname(node.hostname())
.clusterName(node.clusterName())
.type(node.type())
.segmentId(node.segmentId())
.intgBridge(node.intgBridge())
.extBridge(node.extBridge())
.localBridge(node.localBridge())
.tunBridge(node.tunBridge())
.extIntf(node.extIntf())
.managementIp(node.managementIp())
.dataIp(node.dataIp())
.state(node.state())
.extBridgeIp(node.extBridgeIp())
.extGatewayIp(node.extGatewayIp())
.extGatewayMac(node.extGatewayMac())
.podCidr(node.podCidr());
}
public static final class Builder implements K8sNode.Builder {
private String clusterName;
private String hostname;
private Type type;
private int segmentId;
private Mode mode;
private DeviceId intgBridge;
private DeviceId extBridge;
private DeviceId localBridge;
private DeviceId tunBridge;
private IpAddress managementIp;
private IpAddress dataIp;
private K8sNodeState state;
private K8sApiConfig apiConfig;
private String extIntf;
private IpAddress extBridgeIp;
private IpAddress extGatewayIp;
private MacAddress extGatewayMac;
private String podCidr;
// private constructor not intended to use from external
private Builder() {
}
@Override
public K8sNode build() {
checkArgument(hostname != null, NOT_NULL_MSG, "hostname");
checkArgument(type != null, NOT_NULL_MSG, "type");
checkArgument(state != null, NOT_NULL_MSG, "state");
checkArgument(managementIp != null, NOT_NULL_MSG, "management IP");
if (StringUtils.isEmpty(clusterName)) {
clusterName = DEFAULT_CLUSTER_NAME;
}
if (mode == null) {
mode = NORMAL;
}
K8sExternalNetwork extNetwork = DefaultK8sExternalNetwork.builder()
.extBridgeIp(extBridgeIp)
.extGatewayIp(extGatewayIp)
.extGatewayMac(extGatewayMac)
.build();
return new DefaultK8sNode(clusterName,
hostname,
type,
segmentId,
mode,
intgBridge,
extBridge,
localBridge,
tunBridge,
extIntf,
managementIp,
dataIp,
state,
extNetwork,
podCidr);
}
@Override
public Builder clusterName(String clusterName) {
this.clusterName = clusterName;
return this;
}
@Override
public Builder hostname(String hostname) {
this.hostname = hostname;
return this;
}
@Override
public Builder type(Type type) {
this.type = type;
return this;
}
@Override
public Builder segmentId(int segmentId) {
this.segmentId = segmentId;
return this;
}
@Override
public Builder mode(Mode mode) {
this.mode = mode;
return this;
}
@Override
public Builder intgBridge(DeviceId deviceId) {
this.intgBridge = deviceId;
return this;
}
@Override
public Builder extBridge(DeviceId deviceId) {
this.extBridge = deviceId;
return this;
}
@Override
public Builder localBridge(DeviceId deviceId) {
this.localBridge = deviceId;
return this;
}
@Override
public Builder tunBridge(DeviceId deviceId) {
this.tunBridge = deviceId;
return this;
}
@Override
public Builder extIntf(String intf) {
this.extIntf = intf;
return this;
}
@Override
public Builder managementIp(IpAddress managementIp) {
this.managementIp = managementIp;
return this;
}
@Override
public Builder dataIp(IpAddress dataIp) {
this.dataIp = dataIp;
return this;
}
@Override
public Builder state(K8sNodeState state) {
this.state = state;
return this;
}
@Override
public Builder extBridgeIp(IpAddress extBridgeIp) {
this.extBridgeIp = extBridgeIp;
return this;
}
@Override
public Builder extGatewayIp(IpAddress extGatewayIp) {
this.extGatewayIp = extGatewayIp;
return this;
}
@Override
public Builder extGatewayMac(MacAddress extGatewayMac) {
this.extGatewayMac = extGatewayMac;
return this;
}
@Override
public Builder podCidr(String podCidr) {
this.podCidr = podCidr;
return this;
}
}
}