blob: 220f7fc209208dc60f2dba89ff2c8c94ecb872a6 [file] [log] [blame]
/*
* Copyright 2017-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.openstacknode.api;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
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.behaviour.ControllerInfo;
import org.onosproject.net.device.DeviceService;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkArgument;
import static org.onosproject.net.AnnotationKeys.PORT_MAC;
import static org.onosproject.net.AnnotationKeys.PORT_NAME;
import static org.onosproject.openstacknode.api.Constants.DEFAULT_TUNNEL;
import static org.onosproject.openstacknode.api.Constants.PATCH_INTG_BRIDGE;
/**
* Representation of a openstack node.
*/
public class DefaultOpenstackNode implements OpenstackNode {
private final String hostname;
private final NodeType type;
private final DeviceId intgBridge;
private final IpAddress managementIp;
private final IpAddress dataIp;
private final String vlanIntf;
private final String uplinkPort;
private final NodeState state;
private final Collection<OpenstackPhyInterface> phyIntfs;
private final Collection<ControllerInfo> controllers;
private final OpenstackAuth auth;
private final String endpoint;
private final OpenstackSshAuth sshAuth;
private final DatapathType datapathType;
private final String socketDir;
private static final String NOT_NULL_MSG = "Node % cannot be null";
private static final String OVSDB = "ovsdb:";
/**
* A default constructor of Openstack Node.
*
* @param hostname hostname
* @param type node type
* @param intgBridge integration bridge
* @param managementIp management IP address
* @param dataIp data IP address
* @param vlanIntf VLAN interface
* @param uplinkPort uplink port name
* @param state node state
* @param phyIntfs physical interfaces
* @param controllers customized controllers
* @param auth keystone authentication info
* @param endpoint openstack endpoint URL
* @param sshAuth ssh authentication info
* @param datapathType data path type
* @param socketDir socket directory
*/
protected DefaultOpenstackNode(String hostname, NodeType type,
DeviceId intgBridge,
IpAddress managementIp,
IpAddress dataIp,
String vlanIntf,
String uplinkPort,
NodeState state,
Collection<OpenstackPhyInterface> phyIntfs,
Collection<ControllerInfo> controllers,
OpenstackAuth auth,
String endpoint,
OpenstackSshAuth sshAuth,
DatapathType datapathType,
String socketDir) {
this.hostname = hostname;
this.type = type;
this.intgBridge = intgBridge;
this.managementIp = managementIp;
this.dataIp = dataIp;
this.vlanIntf = vlanIntf;
this.uplinkPort = uplinkPort;
this.state = state;
this.phyIntfs = phyIntfs;
this.controllers = controllers;
this.auth = auth;
this.endpoint = endpoint;
this.sshAuth = sshAuth;
this.datapathType = datapathType;
this.socketDir = socketDir;
}
@Override
public String hostname() {
return hostname;
}
@Override
public NodeType type() {
return type;
}
@Override
public DeviceId ovsdb() {
return DeviceId.deviceId(OVSDB + managementIp().toString());
}
@Override
public DeviceId intgBridge() {
return intgBridge;
}
@Override
public IpAddress managementIp() {
return managementIp;
}
@Override
public IpAddress dataIp() {
return dataIp;
}
@Override
public String vlanIntf() {
return vlanIntf;
}
@Override
public String uplinkPort() {
return uplinkPort;
}
@Override
public DatapathType datapathType() {
return datapathType;
}
@Override
public String socketDir() {
return socketDir;
}
@Override
public NodeState state() {
return state;
}
@Override
public PortNumber uplinkPortNum() {
if (uplinkPort == null) {
return null;
}
DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
Port port = deviceService.getPorts(intgBridge).stream()
.filter(p -> p.isEnabled() &&
Objects.equals(p.annotations().value(PORT_NAME), uplinkPort))
.findAny().orElse(null);
return port != null ? port.number() : null;
}
@Override
public PortNumber tunnelPortNum() {
if (dataIp == null) {
return null;
}
DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
Port port = deviceService.getPorts(intgBridge).stream()
.filter(p -> p.isEnabled() &&
Objects.equals(p.annotations().value(PORT_NAME), DEFAULT_TUNNEL))
.findAny().orElse(null);
return port != null ? port.number() : null;
}
@Override
public PortNumber vlanPortNum() {
if (vlanIntf == null) {
return null;
}
DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
Port port = deviceService.getPorts(intgBridge).stream()
.filter(p -> p.isEnabled() &&
Objects.equals(p.annotations().value(PORT_NAME), vlanIntf))
.findAny().orElse(null);
return port != null ? port.number() : null;
}
@Override
public PortNumber patchPortNum() {
if (type == NodeType.COMPUTE) {
return null;
}
DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
Port port = deviceService.getPorts(intgBridge).stream()
.filter(p -> p.isEnabled() &&
Objects.equals(p.annotations().value(PORT_NAME), PATCH_INTG_BRIDGE))
.findAny().orElse(null);
return port != null ? port.number() : null;
}
@Override
public MacAddress vlanPortMac() {
if (vlanIntf == null) {
return null;
}
DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
Port port = deviceService.getPorts(intgBridge).stream()
.filter(p -> p.annotations().value(PORT_NAME).equals(vlanIntf))
.findAny().orElse(null);
return port != null ? MacAddress.valueOf(port.annotations().value(PORT_MAC)) : null;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DefaultOpenstackNode) {
DefaultOpenstackNode that = (DefaultOpenstackNode) obj;
return Objects.equals(hostname, that.hostname) &&
Objects.equals(type, that.type) &&
Objects.equals(intgBridge, that.intgBridge) &&
Objects.equals(managementIp, that.managementIp) &&
Objects.equals(dataIp, that.dataIp) &&
Objects.equals(uplinkPort, that.uplinkPort) &&
Objects.equals(vlanIntf, that.vlanIntf) &&
Objects.equals(phyIntfs, that.phyIntfs) &&
Objects.equals(controllers, that.controllers) &&
Objects.equals(auth, that.auth) &&
Objects.equals(endpoint, that.endpoint) &&
Objects.equals(sshAuth, that.sshAuth) &&
Objects.equals(datapathType, that.datapathType) &&
Objects.equals(socketDir, that.socketDir);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(hostname,
type,
intgBridge,
managementIp,
dataIp,
vlanIntf,
uplinkPort,
phyIntfs,
controllers,
auth,
endpoint,
sshAuth,
datapathType,
socketDir);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("hostname", hostname)
.add("type", type)
.add("integrationBridge", intgBridge)
.add("managementIp", managementIp)
.add("dataIp", dataIp)
.add("vlanIntf", vlanIntf)
.add("uplinkPort", uplinkPort)
.add("state", state)
.add("phyIntfs", phyIntfs)
.add("controllers", controllers)
.add("auth", auth)
.add("endpoint", endpoint)
.add("sshAuth", sshAuth)
.add("datapathType", datapathType)
.add("socketDir", socketDir)
.toString();
}
@Override
public OpenstackNode updateState(NodeState newState) {
return new Builder()
.type(type)
.hostname(hostname)
.intgBridge(intgBridge)
.managementIp(managementIp)
.dataIp(dataIp)
.vlanIntf(vlanIntf)
.uplinkPort(uplinkPort)
.state(newState)
.phyIntfs(phyIntfs)
.controllers(controllers)
.authentication(auth)
.endpoint(endpoint)
.sshAuthInfo(sshAuth)
.datapathType(datapathType)
.build();
}
@Override
public OpenstackNode updateIntbridge(DeviceId newIntgBridge) {
return new Builder()
.type(type)
.hostname(hostname)
.intgBridge(newIntgBridge)
.managementIp(managementIp)
.dataIp(dataIp)
.vlanIntf(vlanIntf)
.uplinkPort(uplinkPort)
.state(state)
.phyIntfs(phyIntfs)
.controllers(controllers)
.authentication(auth)
.endpoint(endpoint)
.sshAuthInfo(sshAuth)
.datapathType(datapathType)
.socketDir(socketDir)
.build();
}
@Override
public Collection<OpenstackPhyInterface> phyIntfs() {
if (phyIntfs == null) {
return new ArrayList<>();
}
return phyIntfs;
}
@Override
public Collection<ControllerInfo> controllers() {
if (controllers == null) {
return new ArrayList<>();
}
return controllers;
}
@Override
public OpenstackSshAuth sshAuthInfo() {
return sshAuth;
}
@Override
public PortNumber phyIntfPortNum(String providerPhysnet) {
Optional<OpenstackPhyInterface> openstackPhyInterface =
phyIntfs.stream().filter(p -> p.network().equals(providerPhysnet)).findAny();
if (openstackPhyInterface.isPresent()) {
DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
Port port = deviceService.getPorts(intgBridge).stream()
.filter(p -> p.isEnabled() &&
Objects.equals(p.annotations().value(PORT_NAME), openstackPhyInterface.get().intf()))
.findAny().orElse(null);
return port != null ? port.number() : null;
} else {
return null;
}
}
@Override
public OpenstackAuth authentication() {
return auth;
}
@Override
public String endpoint() {
return endpoint;
}
/**
* Returns new builder instance.
*
* @return openstack node builder
*/
public static Builder builder() {
return new Builder();
}
/**
* Returns new builder instance with the given node as a default value.
*
* @param osNode openstack node
* @return openstack node builder
*/
public static Builder from(OpenstackNode osNode) {
return new Builder()
.hostname(osNode.hostname())
.type(osNode.type())
.intgBridge(osNode.intgBridge())
.managementIp(osNode.managementIp())
.dataIp(osNode.dataIp())
.vlanIntf(osNode.vlanIntf())
.uplinkPort(osNode.uplinkPort())
.state(osNode.state())
.phyIntfs(osNode.phyIntfs())
.controllers(osNode.controllers())
.authentication(osNode.authentication())
.endpoint(osNode.endpoint())
.sshAuthInfo(osNode.sshAuthInfo())
.datapathType(osNode.datapathType())
.socketDir(osNode.socketDir());
}
/**
* A builder class for openstack Node.
*/
public static final class Builder implements OpenstackNode.Builder {
private String hostname;
private NodeType type;
private DeviceId intgBridge;
private IpAddress managementIp;
private IpAddress dataIp;
private String vlanIntf;
private String uplinkPort;
private NodeState state;
private Collection<OpenstackPhyInterface> phyIntfs;
private Collection<ControllerInfo> controllers;
private OpenstackAuth auth;
private String endpoint;
private OpenstackSshAuth sshAuth;
private DatapathType datapathType = DatapathType.NORMAL;
private String socketDir;
// private constructor not intended to use from external
private Builder() {
}
@Override
public DefaultOpenstackNode 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 (type != NodeType.CONTROLLER) {
if (dataIp == null && Strings.isNullOrEmpty(vlanIntf)) {
throw new IllegalArgumentException("Either data IP or VLAN interface is required");
}
} else {
checkArgument(endpoint != null, NOT_NULL_MSG, "endpoint URL");
}
if (type == NodeType.GATEWAY && uplinkPort == null) {
throw new IllegalArgumentException("Uplink port is required for gateway node");
}
return new DefaultOpenstackNode(hostname,
type,
intgBridge,
managementIp,
dataIp,
vlanIntf,
uplinkPort,
state,
phyIntfs,
controllers,
auth,
endpoint,
sshAuth,
datapathType,
socketDir);
}
@Override
public Builder hostname(String hostname) {
if (!Strings.isNullOrEmpty(hostname)) {
this.hostname = hostname;
}
return this;
}
@Override
public Builder type(NodeType type) {
this.type = type;
return this;
}
@Override
public Builder intgBridge(DeviceId intgBridge) {
this.intgBridge = intgBridge;
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 vlanIntf(String vlanIntf) {
this.vlanIntf = vlanIntf;
return this;
}
@Override
public Builder uplinkPort(String uplinkPort) {
this.uplinkPort = uplinkPort;
return this;
}
@Override
public Builder state(NodeState state) {
this.state = state;
return this;
}
@Override
public Builder phyIntfs(Collection<OpenstackPhyInterface> phyIntfs) {
this.phyIntfs = phyIntfs;
return this;
}
@Override
public Builder controllers(Collection<ControllerInfo> controllers) {
this.controllers = controllers;
return this;
}
@Override
public Builder authentication(OpenstackAuth auth) {
this.auth = auth;
return this;
}
@Override
public Builder endpoint(String endpoint) {
this.endpoint = endpoint;
return this;
}
@Override
public Builder sshAuthInfo(OpenstackSshAuth sshAuth) {
this.sshAuth = sshAuth;
return this;
}
@Override
public Builder datapathType(DatapathType datapathType) {
this.datapathType = datapathType;
return this;
}
@Override
public Builder socketDir(String socketDir) {
this.socketDir = socketDir;
return this;
}
}
}