blob: 16f70347e713f1eff3e1736f6fc8c0885f90a856 [file] [log] [blame]
/*
* Copyright 2020-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.kubevirtnode.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.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
import static org.onosproject.kubevirtnode.api.Constants.DEFAULT_CLUSTER_NAME;
import static org.onosproject.kubevirtnode.api.Constants.GENEVE;
import static org.onosproject.kubevirtnode.api.Constants.GRE;
import static org.onosproject.kubevirtnode.api.Constants.INTEGRATION_TO_PHYSICAL_PREFIX;
import static org.onosproject.kubevirtnode.api.Constants.STT;
import static org.onosproject.kubevirtnode.api.Constants.VXLAN;
import static org.onosproject.net.AnnotationKeys.PORT_NAME;
/**
* Representation of a KubeVirt node.
*/
public class DefaultKubevirtNode implements KubevirtNode {
private static final String NOT_NULL_MSG = "Node % cannot be null";
private static final String OVSDB = "ovsdb:";
private static final int PORT_NAME_MAX_LENGTH = 15;
private final String clusterName;
private final String hostname;
private final Type type;
private final DeviceId intgBridge;
private final DeviceId tunBridge;
private final IpAddress managementIp;
private final IpAddress dataIp;
private final KubevirtNodeState state;
private final Collection<KubevirtPhyInterface> phyIntfs;
private final String gatewayBridgeName;
private final String elbBridgeName;
private final IpAddress elbIp;
private final IpAddress elbGwIp;
private final MacAddress elbGwMac;
/**
* A default constructor of kubevirt node.
*
* @param clusterName clusterName
* @param hostname hostname
* @param type node type
* @param intgBridge integration bridge
* @param tunBridge tunnel bridge
* @param managementIp management IP address
* @param dataIp data IP address
* @param state node state
* @param phyIntfs physical interfaces
* @param gatewayBridgeName gateway bridge name
* @param elbBridgeName elb bridge name
* @param elbIp elb IP address
* @param elbGwIp elb gw IP address
* @param elbGwMac elb gw MAC address
*/
protected DefaultKubevirtNode(String clusterName, String hostname, Type type,
DeviceId intgBridge, DeviceId tunBridge,
IpAddress managementIp, IpAddress dataIp,
KubevirtNodeState state,
Collection<KubevirtPhyInterface> phyIntfs,
String gatewayBridgeName, String elbBridgeName, IpAddress elbIp,
IpAddress elbGwIp, MacAddress elbGwMac) {
this.clusterName = clusterName;
this.hostname = hostname;
this.type = type;
this.intgBridge = intgBridge;
this.tunBridge = tunBridge;
this.managementIp = managementIp;
this.dataIp = dataIp;
this.state = state;
this.phyIntfs = phyIntfs;
this.gatewayBridgeName = gatewayBridgeName;
this.elbBridgeName = elbBridgeName;
this.elbIp = elbIp;
this.elbGwIp = elbGwIp;
this.elbGwMac = elbGwMac;
}
@Override
public String clusterName() {
return clusterName;
}
@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 tunBridge() {
return tunBridge;
}
@Override
public IpAddress managementIp() {
return managementIp;
}
@Override
public IpAddress dataIp() {
return dataIp;
}
@Override
public KubevirtNodeState state() {
return state;
}
@Override
public KubevirtNode updateState(KubevirtNodeState newState) {
return new Builder()
.hostname(hostname)
.clusterName(clusterName)
.type(type)
.intgBridge(intgBridge)
.tunBridge(tunBridge)
.managementIp(managementIp)
.dataIp(dataIp)
.state(newState)
.phyIntfs(phyIntfs)
.gatewayBridgeName(gatewayBridgeName)
.elbBridgeName(elbBridgeName)
.elbIp(elbIp)
.elbGwIp(elbGwIp)
.elbGwMac(elbGwMac)
.build();
}
@Override
public KubevirtNode updateIntgBridge(DeviceId deviceId) {
return new Builder()
.hostname(hostname)
.clusterName(clusterName)
.type(type)
.intgBridge(deviceId)
.tunBridge(tunBridge)
.managementIp(managementIp)
.dataIp(dataIp)
.state(state)
.phyIntfs(phyIntfs)
.gatewayBridgeName(gatewayBridgeName)
.elbBridgeName(elbBridgeName)
.elbIp(elbIp)
.elbGwIp(elbGwIp)
.elbGwMac(elbGwMac)
.build();
}
@Override
public KubevirtNode updateTunBridge(DeviceId deviceId) {
return new Builder()
.hostname(hostname)
.clusterName(clusterName)
.type(type)
.intgBridge(intgBridge)
.tunBridge(deviceId)
.managementIp(managementIp)
.dataIp(dataIp)
.state(state)
.phyIntfs(phyIntfs)
.gatewayBridgeName(gatewayBridgeName)
.elbBridgeName(elbBridgeName)
.elbIp(elbIp)
.elbGwIp(elbGwIp)
.elbGwMac(elbGwMac)
.build();
}
@Override
public Collection<KubevirtPhyInterface> phyIntfs() {
if (phyIntfs == null) {
return new ArrayList<>();
}
return phyIntfs;
}
@Override
public Set<PortNumber> physPatchPorts() {
Set<PortNumber> portNumbers = new HashSet<>();
for (KubevirtPhyInterface phyIntf : this.phyIntfs()) {
String portName = structurePortName(
INTEGRATION_TO_PHYSICAL_PREFIX + phyIntf.network());
PortNumber portNumber = patchPort(portName);
if (portNumber != null) {
portNumbers.add(portNumber);
}
}
return portNumbers;
}
@Override
public PortNumber vxlanPort() {
return tunnelPort(VXLAN);
}
@Override
public PortNumber grePort() {
return tunnelPort(GRE);
}
@Override
public PortNumber genevePort() {
return tunnelPort(GENEVE);
}
@Override
public PortNumber sttPort() {
return tunnelPort(STT);
}
@Override
public String gatewayBridgeName() {
return gatewayBridgeName;
}
@Override
public String elbBridgeName() {
return elbBridgeName;
}
@Override
public IpAddress elbIp() {
return elbIp;
}
@Override
public IpAddress elbGwIp() {
return elbGwIp;
}
@Override
public MacAddress elbGwMac() {
return elbGwMac;
}
private PortNumber tunnelPort(String tunnelType) {
if (dataIp == null) {
return null;
}
DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
Port port = deviceService.getPorts(tunBridge).stream()
.filter(p -> p.isEnabled() &&
Objects.equals(p.annotations().value(PORT_NAME), tunnelType))
.findAny().orElse(null);
return port != null ? port.number() : null;
}
private PortNumber patchPort(String portName) {
DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
Port port = deviceService.getPorts(intgBridge).stream()
.filter(p -> p.isEnabled() &&
Objects.equals(p.annotations().value(PORT_NAME), portName))
.findAny().orElse(null);
return port != null ? port.number() : null;
}
/**
* Re-structures the OVS port name.
* The length of OVS port name should be not large than 15.
*
* @param portName original port name
* @return re-structured OVS port name
*/
private String structurePortName(String portName) {
// The size of OVS port name should not be larger than 15
if (portName.length() > PORT_NAME_MAX_LENGTH) {
return StringUtils.substring(portName, 0, PORT_NAME_MAX_LENGTH);
}
return portName;
}
/**
* Returns new builder instance.
*
* @return kubevirt node builder
*/
public static Builder builder() {
return new Builder();
}
/**
* Returns new builder instance with the given node as a default value.
*
* @param node kubevirt node
* @return kubevirt node builder
*/
public static Builder from(KubevirtNode node) {
return new Builder()
.hostname(node.hostname())
.clusterName(node.clusterName())
.type(node.type())
.intgBridge(node.intgBridge())
.tunBridge(node.tunBridge())
.managementIp(node.managementIp())
.dataIp(node.dataIp())
.state(node.state())
.phyIntfs(node.phyIntfs())
.gatewayBridgeName(node.gatewayBridgeName())
.elbBridgeName(node.elbBridgeName())
.elbIp(node.elbIp())
.elbGwIp(node.elbGwIp())
.elbGwMac(node.elbGwMac());
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DefaultKubevirtNode that = (DefaultKubevirtNode) o;
return clusterName.equals(that.clusterName) &&
hostname.equals(that.hostname) &&
type == that.type &&
intgBridge.equals(that.intgBridge) &&
tunBridge.equals(that.tunBridge) &&
managementIp.equals(that.managementIp) &&
dataIp.equals(that.dataIp);
}
@Override
public int hashCode() {
return Objects.hash(clusterName, hostname, type, intgBridge, tunBridge,
managementIp, dataIp);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("clusterName", clusterName)
.add("hostname", hostname)
.add("type", type)
.add("intgBridge", intgBridge)
.add("tunBridge", tunBridge)
.add("managementIp", managementIp)
.add("dataIp", dataIp)
.add("state", state)
.add("phyIntfs", phyIntfs)
.add("gatewayBridgeName", gatewayBridgeName)
.add("elbBridgeName", elbBridgeName)
.add("elbIp", elbIp)
.add("elbGwIp", elbGwIp)
.add("elbGwMac", elbGwMac)
.toString();
}
public static final class Builder implements KubevirtNode.Builder {
private String clusterName;
private String hostname;
private Type type;
private DeviceId intgBridge;
private DeviceId tunBridge;
private IpAddress managementIp;
private IpAddress dataIp;
private KubevirtNodeState state;
private Collection<KubevirtPhyInterface> phyIntfs;
private String gatewayBridgeName;
private String elbBridgeName;
private IpAddress elbIp;
private IpAddress elbGwIp;
private MacAddress elbGwMac;
// private constructor not intended to use from external
private Builder() {
}
@Override
public KubevirtNode 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;
}
return new DefaultKubevirtNode(
clusterName,
hostname,
type,
intgBridge,
tunBridge,
managementIp,
dataIp,
state,
phyIntfs,
gatewayBridgeName,
elbBridgeName,
elbIp,
elbGwIp,
elbGwMac
);
}
@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 intgBridge(DeviceId deviceId) {
this.intgBridge = deviceId;
return this;
}
@Override
public Builder tunBridge(DeviceId deviceId) {
this.tunBridge = deviceId;
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 phyIntfs(Collection<KubevirtPhyInterface> phyIntfs) {
this.phyIntfs = phyIntfs;
return this;
}
@Override
public Builder state(KubevirtNodeState state) {
this.state = state;
return this;
}
@Override
public Builder gatewayBridgeName(String gatewayBridgeName) {
this.gatewayBridgeName = gatewayBridgeName;
return this;
}
@Override
public Builder elbBridgeName(String elbBridgeName) {
this.elbBridgeName = elbBridgeName;
return this;
}
@Override
public Builder elbIp(IpAddress elbIp) {
this.elbIp = elbIp;
return this;
}
@Override
public Builder elbGwIp(IpAddress elbGwIp) {
this.elbGwIp = elbGwIp;
return this;
}
@Override
public Builder elbGwMac(MacAddress elbGwMac) {
this.elbGwMac = elbGwMac;
return this;
}
}
}