Hyunsun Moon

Changed to use XOS client to get service and port information

XOS client still gets these information from OpenStack temporarily
until XOS provides these APIs

Change-Id: I1ef9302f719a18a7377221f63b84431c2cdface8
......@@ -6,13 +6,9 @@ COMPILE_DEPS = [
'//lib:org.apache.karaf.shell.console',
'//lib:javax.ws.rs-api',
'//lib:jsch',
'//lib:openstack4j-core',
'//lib:openstack4j-http-connector',
'//lib:openstack4j-httpclient',
'//utils/rest:onlab-rest',
'//cli:onos-cli',
'//core/store/serializers:onos-core-serializers',
'//apps/openstackinterface/api:onos-apps-openstackinterface-api',
'//apps/dhcp/api:onos-apps-dhcp-api',
'//apps/xosclient:onos-apps-xosclient',
'//protocols/ovsdb/api:onos-protocols-ovsdb-api',
......@@ -20,11 +16,7 @@ COMPILE_DEPS = [
]
BUNDLES = [
'//apps/openstackinterface/api:onos-apps-openstackinterface-api',
'//apps/cordvtn:onos-apps-cordvtn',
'//lib:openstack4j-core',
'//lib:openstack4j-http-connector',
'//lib:openstack4j-httpclient',
]
EXCLUDED_BUNDLES = [
......@@ -43,5 +35,5 @@ onos_app (
included_bundles = BUNDLES,
excluded_bundles = EXCLUDED_BUNDLES,
description = 'APIs for interacting with the CORD VTN application.',
required_apps = [ 'org.onosproject.xosclient', 'org.onosproject.dhcp', 'org.onosproject.ovsdb', 'org.onosproject.openstackinterface' ],
required_apps = [ 'org.onosproject.xosclient', 'org.onosproject.dhcp', 'org.onosproject.ovsdb' ],
)
......
......@@ -112,21 +112,6 @@
<artifactId>jsch</artifactId>
<version>0.1.53</version>
</dependency>
<dependency>
<groupId>org.pacesys</groupId>
<artifactId>openstack4j-core</artifactId>
<version>2.11</version>
</dependency>
<dependency>
<groupId>org.pacesys.openstack4j.connectors</groupId>
<artifactId>openstack4j-http-connector</artifactId>
<version>2.11</version>
</dependency>
<dependency>
<groupId>org.pacesys.openstack4j.connectors</groupId>
<artifactId>openstack4j-httpclient</artifactId>
<version>2.11</version>
</dependency>
</dependencies>
<build>
......@@ -146,15 +131,8 @@
${project.groupId}.${project.artifactId}
</Bundle-SymbolicName>
<Import-Package>
!org.apache.http.*,
!com.fasterxml.jackson.dataformat.*,
*,org.glassfish.jersey.servlet
</Import-Package>
<Embed-Dependency>
openstack4j-core,
openstack4j-http-connector,
openstack4j-httpclient
</Embed-Dependency>
<Web-ContextPath>${web.context}</Web-ContextPath>
</instructions>
</configuration>
......
/*
* Copyright 2015-present Open Networking Laboratory
*
* 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.cordvtn.api;
import com.google.common.base.MoreObjects;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onosproject.net.Host;
import org.openstack4j.model.network.Network;
import org.openstack4j.model.network.Subnet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
public final class CordService {
public enum ServiceType {
PRIVATE,
PUBLIC,
MANAGEMENT
}
private final CordServiceId id;
private final long segmentationId;
private final ServiceType serviceType;
private final IpPrefix serviceIpRange;
private final IpAddress serviceIp;
private final Map<Host, IpAddress> hosts;
private final Set<CordServiceId> tenantServices;
private final Set<CordServiceId> providerServices;
/**
* Default constructor.
*
* @param osNet OpenStack network
* @param osSubnet OpenStack subnet
* @param hosts host and tunnel ip map
* @param tenantServices list of tenant service ids
* @param providerServices list of provider service ids
*/
public CordService(Network osNet, Subnet osSubnet,
Map<Host, IpAddress> hosts, Set<CordServiceId> tenantServices,
Set<CordServiceId> providerServices) {
this.id = CordServiceId.of(osNet.getId());
this.segmentationId = Long.parseLong(osNet.getProviderSegID());
this.serviceType = getServiceType(osNet.getName());
this.serviceIpRange = IpPrefix.valueOf(osSubnet.getCidr());
this.serviceIp = IpAddress.valueOf(osSubnet.getGateway());
this.hosts = hosts;
this.tenantServices = tenantServices;
this.providerServices = providerServices;
}
/**
* Returns service ID.
*
* @return service id
*/
public CordServiceId id() {
return id;
}
/**
* Returns segmentation ID of this service.
*
* @return segmentation id
*/
public long segmentationId() {
return segmentationId;
}
/**
* Returns service type.
*
* @return service type
*/
public ServiceType serviceType() {
return serviceType;
}
/**
* Returns service IP range.
*
* @return CIDR
*/
public IpPrefix serviceIpRange() {
return serviceIpRange;
}
/**
* Returns service IP address.
*
* @return ip address
*/
public IpAddress serviceIp() {
return serviceIp;
}
/**
* Returns hosts associated with this service.
*
* @return list of hosts
*/
public Map<Host, IpAddress> hosts() {
return hosts;
}
/**
* Returns tenant service IDs.
*
* @return list of tenant service id
*/
public Set<CordServiceId> tenantServices() {
return tenantServices;
}
/**
* Returns provider service IDs.
*
* @return list of provider service id
*/
public Set<CordServiceId> providerServices() {
return providerServices;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof CordService)) {
return false;
}
final CordService other = (CordService) obj;
return Objects.equals(this.id, other.id);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("id", id)
.add("segmentationId", segmentationId)
.add("serviceType", serviceType)
.add("serviceIpRange", serviceIpRange)
.add("serviceIp", serviceIp)
.add("tenantServices", tenantServices)
.add("providerServices", providerServices)
.toString();
}
/**
* Returns network type from network name.
* It assumes that network name contains network type.
*
* @param netName network name
* @return network type, or PRIVATE if it doesn't match any type
*/
private ServiceType getServiceType(String netName) {
checkNotNull(netName);
String name = netName.toUpperCase();
if (name.contains(ServiceType.PUBLIC.toString())) {
return ServiceType.PUBLIC;
} else if (name.contains(ServiceType.MANAGEMENT.toString())) {
return ServiceType.MANAGEMENT;
} else {
return ServiceType.PRIVATE;
}
}
}
/*
* Copyright 2015-present Open Networking Laboratory
*
* 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.cordvtn.api;
import org.onlab.util.Identifier;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Representation of service identifier.
*/
public final class CordServiceId extends Identifier<String> {
/**
* Default constructor.
*
* @param id service identifier
*/
private CordServiceId(String id) {
super(id);
}
/**
* Returns the CordServiceId with value.
*
* @param id service id
* @return CordServiceId
*/
public static CordServiceId of(String id) {
checkNotNull(id);
return new CordServiceId(id);
}
}
......@@ -25,6 +25,7 @@ import org.onlab.packet.TpPort;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.config.Config;
import org.onosproject.xosclient.api.OpenStackAccess;
import org.onosproject.xosclient.api.XosAccess;
import org.slf4j.Logger;
......@@ -209,9 +210,9 @@ public class CordVtnConfig extends Config<ApplicationId> {
/**
* Returns OpenStack API access information.
*
* @return openstack config
* @return openstack access
*/
public OpenStackConfig openstackConfig() {
public OpenStackAccess openstackAccess() {
JsonNode jsonNode = object.get(OPENSTACK);
if (jsonNode == null) {
log.error("Failed to get OpenStack configurations");
......@@ -219,7 +220,7 @@ public class CordVtnConfig extends Config<ApplicationId> {
}
try {
return new OpenStackConfig(
return new OpenStackAccess(
jsonNode.path(ENDPOINT).asText(),
jsonNode.path(TENANT).asText(),
jsonNode.path(USER).asText(),
......@@ -229,66 +230,4 @@ public class CordVtnConfig extends Config<ApplicationId> {
return null;
}
}
/**
* Configuration for OpenStack API access.
*/
public static class OpenStackConfig {
private final String endpoint;
private final String tenant;
private final String user;
private final String password;
/**
* Default constructor.
*
* @param endpoint Keystone endpoint
* @param tenant tenant name
* @param user user name
* @param password passwowrd
*/
public OpenStackConfig(String endpoint, String tenant, String user, String password) {
this.endpoint = endpoint;
this.tenant = tenant;
this.user = user;
this.password = password;
}
/**
* Returns OpenStack API endpoint.
*
* @return endpoint
*/
public String endpoint() {
return this.endpoint;
}
/**
* Returns OpenStack tenant name.
*
* @return tenant name
*/
public String tenant() {
return this.tenant;
}
/**
* Returns OpenStack user.
*
* @return user name
*/
public String user() {
return this.user;
}
/**
* Returns OpenStack password for the user.
*
* @return password
*/
public String password() {
return this.password;
}
}
}
......
......@@ -19,6 +19,7 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.HostId;
import org.onosproject.xosclient.api.VtnServiceId;
import java.util.Map;
......@@ -51,8 +52,7 @@ public interface CordVtnService {
* @param pServiceId id of the service which provide dependency
* @param isBidirectional true to enable bidirectional connectivity between two services
*/
void createServiceDependency(CordServiceId tServiceId,
CordServiceId pServiceId,
void createServiceDependency(VtnServiceId tServiceId, VtnServiceId pServiceId,
boolean isBidirectional);
/**
......@@ -61,7 +61,7 @@ public interface CordVtnService {
* @param tServiceId id of the service which has a dependency
* @param pServiceId id of the service which provide dependency
*/
void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId);
void removeServiceDependency(VtnServiceId tServiceId, VtnServiceId pServiceId);
/**
* Updates virtual service gateways.
......
......@@ -237,6 +237,7 @@ public class CordVtnNodeManager {
ruleInstaller = new CordVtnRuleInstaller(appId, flowRuleService,
deviceService,
groupService,
hostService,
configRegistry,
DEFAULT_TUNNEL);
......
......@@ -28,8 +28,6 @@ import org.onlab.packet.MacAddress;
import org.onlab.packet.TpPort;
import org.onlab.packet.VlanId;
import org.onlab.util.ItemNotFoundException;
import org.onosproject.cordvtn.api.CordService;
import org.onosproject.cordvtn.api.CordServiceId;
import org.onosproject.cordvtn.api.CordVtnConfig;
import org.onosproject.cordvtn.api.CordVtnNode;
import org.onosproject.core.ApplicationId;
......@@ -68,6 +66,9 @@ import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupService;
import org.onosproject.net.host.HostService;
import org.onosproject.xosclient.api.VtnService;
import org.onosproject.xosclient.api.VtnServiceId;
import org.slf4j.Logger;
import java.util.ArrayList;
......@@ -76,6 +77,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
......@@ -112,11 +114,13 @@ public class CordVtnRuleInstaller {
private static final String DATA_PLANE_INTF = "dataPlaneIntf";
private static final String DATA_PLANE_IP = "dataPlaneIp";
private static final String S_TAG = "stag";
private static final String SERVICE_ID = "serviceId";
private final ApplicationId appId;
private final FlowRuleService flowRuleService;
private final DeviceService deviceService;
private final GroupService groupService;
private final HostService hostService;
private final NetworkConfigRegistry configRegistry;
private final String tunnelType;
......@@ -134,12 +138,14 @@ public class CordVtnRuleInstaller {
FlowRuleService flowRuleService,
DeviceService deviceService,
GroupService groupService,
HostService hostService,
NetworkConfigRegistry configRegistry,
String tunnelType) {
this.appId = appId;
this.flowRuleService = flowRuleService;
this.deviceService = deviceService;
this.groupService = groupService;
this.hostService = hostService;
this.configRegistry = configRegistry;
this.tunnelType = checkNotNull(tunnelType);
}
......@@ -177,7 +183,7 @@ public class CordVtnRuleInstaller {
* @param service cord service
* @param install true to install or false to remove
*/
public void populateBasicConnectionRules(Host host, CordService service, boolean install) {
public void populateBasicConnectionRules(Host host, VtnService service, boolean install) {
checkNotNull(host);
checkNotNull(service);
......@@ -186,8 +192,8 @@ public class CordVtnRuleInstaller {
MacAddress dstMac = host.mac();
IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
long tunnelId = service.segmentationId();
Ip4Prefix serviceIpRange = service.serviceIpRange().getIp4Prefix();
long tunnelId = service.vni();
Ip4Prefix serviceIpRange = service.subnet().getIp4Prefix();
populateLocalInPortRule(deviceId, inPort, hostIp, install);
populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, getTunnelIp(host), install);
......@@ -196,7 +202,7 @@ public class CordVtnRuleInstaller {
if (install) {
populateDirectAccessRule(serviceIpRange, serviceIpRange, true);
populateServiceIsolationRule(serviceIpRange, true);
} else if (service.hosts().isEmpty()) {
} else if (getInstances(service.id()).isEmpty()) {
// removes network related rules only if there's no hosts left in this network
populateDirectAccessRule(serviceIpRange, serviceIpRange, false);
populateServiceIsolationRule(serviceIpRange, false);
......@@ -211,13 +217,13 @@ public class CordVtnRuleInstaller {
* @param isBidirectional true to enable bidirectional connection between two services
* @param install true to install or false to remove
*/
public void populateServiceDependencyRules(CordService tService, CordService pService,
public void populateServiceDependencyRules(VtnService tService, VtnService pService,
boolean isBidirectional, boolean install) {
checkNotNull(tService);
checkNotNull(pService);
Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
Ip4Prefix srcRange = tService.subnet().getIp4Prefix();
Ip4Prefix dstRange = pService.subnet().getIp4Prefix();
Ip4Address serviceIp = pService.serviceIp().getIp4Address();
Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
......@@ -227,7 +233,7 @@ public class CordVtnRuleInstaller {
GroupId groupId = createServiceGroup(deviceId, pService);
outGroups.put(deviceId, groupId);
Set<PortNumber> tServiceVms = tService.hosts().keySet()
Set<PortNumber> tServiceVms = getInstances(tService.id())
.stream()
.filter(host -> host.location().deviceId().equals(deviceId))
.map(host -> host.location().port())
......@@ -248,7 +254,7 @@ public class CordVtnRuleInstaller {
*
* @param service cord service
*/
public void updateProviderServiceGroup(CordService service) {
public void updateProviderServiceGroup(VtnService service) {
checkNotNull(service);
GroupKey groupKey = getGroupKey(service.id());
......@@ -262,7 +268,7 @@ public class CordVtnRuleInstaller {
List<GroupBucket> oldBuckets = group.buckets().buckets();
List<GroupBucket> newBuckets = getServiceGroupBuckets(
deviceId, service.segmentationId(), service.hosts()).buckets();
deviceId, service.vni(), getInstances(service.id())).buckets();
if (oldBuckets.equals(newBuckets)) {
continue;
......@@ -296,7 +302,7 @@ public class CordVtnRuleInstaller {
* @param host removed vm
* @param service tenant service
*/
public void updateTenantServiceVm(Host host, CordService service) {
public void updateTenantServiceVm(Host host, VtnService service) {
checkNotNull(host);
checkNotNull(service);
......@@ -320,7 +326,7 @@ public class CordVtnRuleInstaller {
* @param host host which has management network interface
* @param mService management network service
*/
public void populateManagementNetworkRules(Host host, CordService mService) {
public void populateManagementNetworkRules(Host host, VtnService mService) {
checkNotNull(mService);
DeviceId deviceId = host.location().deviceId();
......@@ -372,7 +378,7 @@ public class CordVtnRuleInstaller {
selector = DefaultTrafficSelector.builder()
.matchInPort(PortNumber.LOCAL)
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(mService.serviceIpRange())
.matchIPDst(mService.subnet())
.build();
treatment = DefaultTrafficTreatment.builder()
......@@ -1237,7 +1243,7 @@ public class CordVtnRuleInstaller {
* @param service cord service
* @return group id, or null if it fails to create
*/
private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
private GroupId createServiceGroup(DeviceId deviceId, VtnService service) {
checkNotNull(service);
GroupKey groupKey = getGroupKey(service.id());
......@@ -1250,7 +1256,7 @@ public class CordVtnRuleInstaller {
}
GroupBuckets buckets = getServiceGroupBuckets(
deviceId, service.segmentationId(), service.hosts());
deviceId, service.vni(), getInstances(service.id()));
GroupDescription groupDescription = new DefaultGroupDescription(
deviceId,
GroupDescription.Type.SELECT,
......@@ -1273,33 +1279,26 @@ public class CordVtnRuleInstaller {
* @return group buckets
*/
private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId,
Map<Host, IpAddress> hosts) {
Set<Host> hosts) {
List<GroupBucket> buckets = Lists.newArrayList();
for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
Host host = entry.getKey();
Ip4Address remoteIp = entry.getValue().getIp4Address();
hosts.stream().forEach(host -> {
Ip4Address tunnelIp = getTunnelIp(host).getIp4Address();
DeviceId hostDevice = host.location().deviceId();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
.builder()
.setEthDst(host.mac());
if (deviceId.equals(hostDevice)) {
tBuilder.setOutput(host.location().port());
} else {
ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
if (tunnelDst == null) {
continue;
}
ExtensionTreatment tunnelDst = getTunnelDst(deviceId, tunnelIp);
tBuilder.extension(tunnelDst, deviceId)
.setTunnelId(tunnelId)
.setOutput(getTunnelPort(hostDevice));
}
buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
}
});
return new GroupBuckets(buckets);
}
......@@ -1311,7 +1310,7 @@ public class CordVtnRuleInstaller {
* @param deviceId device id
* @return group id
*/
private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
private GroupId getGroupId(VtnServiceId serviceId, DeviceId deviceId) {
return new DefaultGroupId(Objects.hash(serviceId, deviceId));
}
......@@ -1321,7 +1320,7 @@ public class CordVtnRuleInstaller {
* @param serviceId service id
* @return group key
*/
private GroupKey getGroupKey(CordServiceId serviceId) {
private GroupKey getGroupKey(VtnServiceId serviceId) {
return new DefaultGroupKey(serviceId.id().getBytes());
}
......@@ -1370,5 +1369,19 @@ public class CordVtnRuleInstaller {
return config.cordVtnNodes().stream()
.map(CordVtnNode::intBrId).collect(Collectors.toSet());
}
/**
* Returns instances with a given network service.
*
* @param serviceId service id
* @return set of hosts
*/
private Set<Host> getInstances(VtnServiceId serviceId) {
return StreamSupport.stream(hostService.getHosts().spliterator(), false)
.filter(host -> Objects.equals(
serviceId.id(),
host.annotations().value(SERVICE_ID)))
.collect(Collectors.toSet());
}
}
......
......@@ -16,8 +16,8 @@
package org.onosproject.cordvtn.rest;
import org.onosproject.cordvtn.api.CordVtnService;
import org.onosproject.cordvtn.api.CordServiceId;
import org.onosproject.rest.AbstractWebResource;
import org.onosproject.xosclient.api.VtnServiceId;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
......@@ -48,8 +48,8 @@ public class ServiceDependencyWebResource extends AbstractWebResource {
@Produces(MediaType.APPLICATION_JSON)
public Response createServiceDependency(@PathParam("tenantServiceId") String tServiceId,
@PathParam("providerServiceId") String pServiceId) {
service.createServiceDependency(CordServiceId.of(tServiceId),
CordServiceId.of(pServiceId),
service.createServiceDependency(VtnServiceId.of(tServiceId),
VtnServiceId.of(pServiceId),
false);
return Response.status(Response.Status.OK).build();
}
......@@ -68,8 +68,8 @@ public class ServiceDependencyWebResource extends AbstractWebResource {
public Response createServiceDependency(@PathParam("tenantServiceId") String tServiceId,
@PathParam("providerServiceId") String pServiceId,
@PathParam("direction") String direction) {
service.createServiceDependency(CordServiceId.of(tServiceId),
CordServiceId.of(pServiceId),
service.createServiceDependency(VtnServiceId.of(tServiceId),
VtnServiceId.of(pServiceId),
direction.equals(BIDIRECTION));
return Response.status(Response.Status.OK).build();
}
......@@ -85,7 +85,7 @@ public class ServiceDependencyWebResource extends AbstractWebResource {
@Path("{tenantServiceId}/{providerServiceId}")
public Response removeServiceDependency(@PathParam("tenantServiceId") String tServiceId,
@PathParam("providerServiceId") String pServiceId) {
service.removeServiceDependency(CordServiceId.of(tServiceId), CordServiceId.of(pServiceId));
service.removeServiceDependency(VtnServiceId.of(tServiceId), VtnServiceId.of(pServiceId));
return Response.noContent().build();
}
}
......
COMPILE_DEPS = [
'//lib:CORE_DEPS',
'//lib:javax.ws.rs-api',
'//lib:openstack4j-core',
'//lib:openstack4j-http-connector',
'//lib:openstack4j-httpclient',
]
osgi_jar_with_tests (
......
......@@ -49,6 +49,45 @@
<artifactId>onlab-misc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.pacesys</groupId>
<artifactId>openstack4j-core</artifactId>
<version>2.11</version>
</dependency>
<dependency>
<groupId>org.pacesys.openstack4j.connectors</groupId>
<artifactId>openstack4j-http-connector</artifactId>
<version>2.11</version>
</dependency>
<dependency>
<groupId>org.pacesys.openstack4j.connectors</groupId>
<artifactId>openstack4j-httpclient</artifactId>
<version>2.11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
!org.apache.http.*,
!com.fasterxml.jackson.dataformat.*,
!javax.annotation,*
</Import-Package>
<Embed-Dependency>
openstack4j-core,
openstack4j-http-connector,
openstack4j-httpclient
</Embed-Dependency>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
......
/*
* Copyright 2016-present Open Networking Laboratory
*
* 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.xosclient.api;
import com.google.common.base.MoreObjects;
import java.util.Objects;
/**
* Object holding OpenStack API access information.
*/
// TODO remove this when XOS provides this information
public class OpenStackAccess {
private final String endpoint;
private final String tenant;
private final String user;
private final String password;
/**
* Default constructor.
*
* @param endpoint Keystone endpoint
* @param tenant tenant name
* @param user user name
* @param password password
*/
public OpenStackAccess(String endpoint, String tenant, String user, String password) {
this.endpoint = endpoint;
this.tenant = tenant;
this.user = user;
this.password = password;
}
/**
* Returns OpenStack API endpoint.
*
* @return endpoint
*/
public String endpoint() {
return this.endpoint;
}
/**
* Returns OpenStack tenant name.
*
* @return tenant name
*/
public String tenant() {
return this.tenant;
}
/**
* Returns OpenStack user.
*
* @return user name
*/
public String user() {
return this.user;
}
/**
* Returns OpenStack password for the user.
*
* @return password
*/
public String password() {
return this.password;
}
@Override
public int hashCode() {
return Objects.hash(endpoint, tenant, user, password);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if ((obj instanceof OpenStackAccess)) {
OpenStackAccess that = (OpenStackAccess) obj;
if (Objects.equals(endpoint, that.endpoint) &&
Objects.equals(tenant, that.tenant) &&
Objects.equals(user, that.user) &&
Objects.equals(password, that.password)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("endpoint", endpoint)
.add("tenant", tenant)
.add("user", user)
.add("password", password)
.toString();
}
}
......@@ -44,4 +44,22 @@ public interface VtnPortApi {
* @return vtn port; null if it fails to get port information
*/
VtnPort vtnPort(VtnPortId portId);
/**
* Returns port information from OpenStack with port id.
*
* @param portId port id
* @return vtn port; null if it fails to get port information
*/
// TODO remove this when XOS provides port information
VtnPort vtnPort(VtnPortId portId, OpenStackAccess osAccess);
/**
* Returns port information from OpenStack with port name.
*
* @param portName port name
* @return vtn port; null if it fails to get port information
*/
// TODO remove this when XOS provides port information
VtnPort vtnPort(String portName, OpenStackAccess osAccess);
}
......
......@@ -52,4 +52,14 @@ public interface VtnServiceApi {
* @return set of service ids
*/
Set<VtnServiceId> providerServices(VtnServiceId tServiceId);
/**
* Returns VTN service from OpenStack.
*
* @param serviceId service id
* @param osAccess openstack access
* @return vtn service
*/
// TODO remove this when XOS provides service information
VtnService service(VtnServiceId serviceId, OpenStackAccess osAccess);
}
......
......@@ -15,18 +15,33 @@
*/
package org.onosproject.xosclient.impl;
import com.google.common.collect.Maps;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.xosclient.api.OpenStackAccess;
import org.onosproject.xosclient.api.VtnPort;
import org.onosproject.xosclient.api.VtnPortApi;
import org.onosproject.xosclient.api.VtnPortId;
import org.onosproject.xosclient.api.VtnServiceId;
import org.onosproject.xosclient.api.XosAccess;
import org.openstack4j.api.OSClient;
import org.openstack4j.model.network.IP;
import org.openstack4j.model.network.Port;
import org.openstack4j.openstack.OSFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Provides CORD VTN port APIs.
*/
public class DefaultVtnPortApi extends XosApi implements VtnPortApi {
public final class DefaultVtnPortApi extends XosApi implements VtnPortApi {
private final Logger log = LoggerFactory.getLogger(getClass());
/**
* Default constructor.
......@@ -55,4 +70,72 @@ public class DefaultVtnPortApi extends XosApi implements VtnPortApi {
// TODO implement this when XOS provides this information
return null;
}
@Override
// TODO remove this when XOS provides this information
public VtnPort vtnPort(String portName, OpenStackAccess osAccess) {
checkNotNull(osAccess);
OSClient osClient = getOpenStackClient(osAccess);
Port osPort = osClient.networking().port().list()
.stream()
.filter(p -> p.getId().contains(portName.substring(3)))
.findFirst().orElse(null);
if (osPort == null) {
log.warn("Failed to get OpenStack port for {}", portName);
return null;
}
return getVtnPort(osPort);
}
@Override
// TODO remove this when XOS provides this information
public VtnPort vtnPort(VtnPortId portId, OpenStackAccess osAccess) {
checkNotNull(osAccess);
OSClient osClient = getOpenStackClient(osAccess);
Port osPort = osClient.networking().port().get(portId.id());
if (osPort == null) {
log.warn("Failed to get OpenStack port {}", portId);
return null;
}
return getVtnPort(osPort);
}
// TODO remove this when XOS provides this information
private VtnPort getVtnPort(Port osPort) {
checkNotNull(osPort);
// assumes all vtn port has single IP address
IP ipAddr = osPort.getFixedIps().stream().findFirst().orElse(null);
if (ipAddr == null) {
log.warn("Failed to get IP address for {}", osPort);
return null;
}
Map<IpAddress, MacAddress> addressPairs = Maps.newHashMap();
osPort.getAllowedAddressPairs().stream().forEach(
pair -> addressPairs.put(IpAddress.valueOf(pair.getIpAddress()),
MacAddress.valueOf(pair.getMacAddress())));
return new VtnPort(VtnPortId.of(osPort.getId()),
osPort.getName(),
VtnServiceId.of(osPort.getNetworkId()),
MacAddress.valueOf(osPort.getMacAddress()),
IpAddress.valueOf(ipAddr.getIpAddress()),
addressPairs);
}
// TODO remove this when XOS provides this information
private OSClient getOpenStackClient(OpenStackAccess osAccess) {
checkNotNull(osAccess);
// creating a client every time must be inefficient, but this method
// will be removed once XOS provides equivalent APIs
return OSFactory.builder()
.endpoint(osAccess.endpoint())
.credentials(osAccess.user(), osAccess.password())
.tenantName(osAccess.tenant())
.authenticate();
}
}
......
......@@ -17,12 +17,22 @@ package org.onosproject.xosclient.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onosproject.xosclient.api.OpenStackAccess;
import org.onosproject.xosclient.api.VtnService.NetworkType;
import org.onosproject.xosclient.api.VtnService.ServiceType;
import org.onosproject.xosclient.api.VtnServiceApi;
import org.onosproject.xosclient.api.XosAccess;
import org.onosproject.xosclient.api.VtnService;
import org.onosproject.xosclient.api.VtnServiceId;
import org.openstack4j.api.OSClient;
import org.openstack4j.model.network.Network;
import org.openstack4j.model.network.Subnet;
import org.openstack4j.openstack.OSFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -30,6 +40,9 @@ import java.io.IOException;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkArgument;
import static org.onosproject.xosclient.api.VtnService.NetworkType.*;
import static org.onosproject.xosclient.api.VtnService.ServiceType.*;
/**
* Provides CORD VTN service and service dependency APIs.
......@@ -113,4 +126,76 @@ public final class DefaultVtnServiceApi extends XosApi implements VtnServiceApi
}
return tServices;
}
@Override
// TODO remove this when XOS provides this information
public VtnService service(VtnServiceId serviceId, OpenStackAccess osAccess) {
checkNotNull(osAccess);
OSClient osClient = getOpenStackClient(osAccess);
Network osNet = osClient.networking().network().get(serviceId.id());
if (osNet == null) {
log.warn("Failed to get OpenStack network {}", serviceId);
return null;
}
// assumes all cord service networks has single subnet
Subnet osSubnet = osNet.getNeutronSubnets().stream()
.findFirst().orElse(null);
if (osSubnet == null) {
log.warn("Failed to get OpenStack subnet of network {}", serviceId);
return null;
}
return new VtnService(serviceId,
osNet.getName(),
serviceType(osNet.getName()),
networkType(osNet.getName()),
Long.parseLong(osNet.getProviderSegID()),
IpPrefix.valueOf(osSubnet.getCidr()),
IpAddress.valueOf(osSubnet.getGateway()),
providerServices(serviceId),
tenantServices(serviceId));
}
// TODO remove this when XOS provides this information
private OSClient getOpenStackClient(OpenStackAccess osAccess) {
checkNotNull(osAccess);
// creating a client every time must be inefficient, but this method
// will be removed once XOS provides equivalent APIs
return OSFactory.builder()
.endpoint(osAccess.endpoint())
.credentials(osAccess.user(), osAccess.password())
.tenantName(osAccess.tenant())
.authenticate();
}
// TODO remove this when XOS provides this information
private NetworkType networkType(String netName) {
checkArgument(!Strings.isNullOrEmpty(netName));
String name = netName.toUpperCase();
if (name.contains(PUBLIC.toString())) {
return PUBLIC;
} else if (name.contains(MANAGEMENT.toString())) {
return MANAGEMENT;
} else {
return PRIVATE;
}
}
// TODO remove this when XOS provides this information
private ServiceType serviceType(String netName) {
checkArgument(!Strings.isNullOrEmpty(netName));
String name = netName.toUpperCase();
if (name.contains(VSG.toString())) {
return VSG;
} else if (name.contains(OLT_AGENT.toString())) {
return OLT_AGENT;
} else {
return DUMMY;
}
}
}
......
......@@ -81,13 +81,15 @@ public class XosApi {
public String restGet(String path) {
WebTarget wt = client.target(access.endpoint() + baseUrl).path(path);
Invocation.Builder builder = wt.request(JSON_UTF_8.toString());
Response response = builder.get();
if (response.getStatus() != HTTP_OK) {
log.warn("Failed to get resource {}", access.endpoint() + baseUrl + path);
try {
Response response = builder.get();
if (response.getStatus() != HTTP_OK) {
log.warn("Failed to get resource {}", access.endpoint() + baseUrl + path);
return EMPTY_JSON_STRING;
}
} catch (javax.ws.rs.ProcessingException e) {
return EMPTY_JSON_STRING;
}
return builder.get(String.class);
}
}
......