Claudine Chiu
Committed by Gerrit Code Review

REST API's for tenants, virtual networks, virtual devices ad virtual ports.

Change-Id: I80abe14a083fce3dc6246118af8874028109388f

REST API's for tenants, virtual networks, virtual devices ad virtual ports.

Change-Id: Ib6c3d69d396e57822bae23f5bf3101c8b9c0b95c
......@@ -26,6 +26,10 @@ import org.onosproject.cluster.ControllerNode;
import org.onosproject.codec.CodecService;
import org.onosproject.codec.JsonCodec;
import org.onosproject.core.Application;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualPort;
import org.onosproject.net.Annotations;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
......@@ -126,6 +130,10 @@ public class CodecManager implements CodecService {
registerCodec(McastRoute.class, new McastRouteCodec());
registerCodec(DeviceKey.class, new DeviceKeyCodec());
registerCodec(Region.class, new RegionCodec());
registerCodec(TenantId.class, new TenantIdCodec());
registerCodec(VirtualNetwork.class, new VirtualNetworkCodec());
registerCodec(VirtualDevice.class, new VirtualDeviceCodec());
registerCodec(VirtualPort.class, new VirtualPortCodec());
log.info("Started");
}
......
/*
* Copyright 2016 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.codec.impl;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.incubator.net.virtual.TenantId;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.nullIsIllegal;
/**
* Codec for the TenantId class.
*/
public class TenantIdCodec extends JsonCodec<TenantId> {
// JSON field names
private static final String TENANT_ID = "id";
private static final String NULL_TENANT_MSG = "TenantId cannot be null";
private static final String MISSING_MEMBER_MSG = " member is required in TenantId";
@Override
public ObjectNode encode(TenantId tenantId, CodecContext context) {
checkNotNull(tenantId, NULL_TENANT_MSG);
ObjectNode result = context.mapper().createObjectNode()
.put(TENANT_ID, tenantId.id().toString());
return result;
}
@Override
public TenantId decode(ObjectNode json, CodecContext context) {
if (json == null || !json.isObject()) {
return null;
}
TenantId tenantId = TenantId.tenantId(extractMember(TENANT_ID, json));
return tenantId;
}
private String extractMember(String key, ObjectNode json) {
return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
}
}
/*
* Copyright 2016 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.codec.impl;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.incubator.net.virtual.DefaultVirtualDevice;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.net.DeviceId;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.nullIsIllegal;
/**
* Codec for the VirtualDevice class.
*/
public class VirtualDeviceCodec extends JsonCodec<VirtualDevice> {
// JSON field names
private static final String ID = "deviceId";
private static final String NETWORK_ID = "networkId";
private static final String NULL_OBJECT_MSG = "VirtualDevice cannot be null";
private static final String MISSING_MEMBER_MSG = " member is required in VirtualDevice";
@Override
public ObjectNode encode(VirtualDevice vDev, CodecContext context) {
checkNotNull(vDev, NULL_OBJECT_MSG);
ObjectNode result = context.mapper().createObjectNode()
.put(ID, vDev.id().toString())
.put(NETWORK_ID, vDev.networkId().toString());
return result;
}
@Override
public VirtualDevice decode(ObjectNode json, CodecContext context) {
if (json == null || !json.isObject()) {
return null;
}
DeviceId dId = DeviceId.deviceId(extractMember(ID, json));
NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
return new DefaultVirtualDevice(nId, dId);
}
private String extractMember(String key, ObjectNode json) {
return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
}
}
/*
* Copyright 2016 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.codec.impl;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.nullIsIllegal;
/**
* Codec for the VirtualNetwork class.
*/
public class VirtualNetworkCodec extends JsonCodec<VirtualNetwork> {
// JSON field names
private static final String NETWORK_ID = "networkId";
private static final String TENANT_ID = "tenantId";
private static final String NULL_OBJECT_MSG = "VirtualNetwork cannot be null";
private static final String MISSING_MEMBER_MSG = " member is required in VirtualNetwork";
@Override
public ObjectNode encode(VirtualNetwork vnet, CodecContext context) {
checkNotNull(vnet, NULL_OBJECT_MSG);
ObjectNode result = context.mapper().createObjectNode()
.put(NETWORK_ID, vnet.id().toString())
.put(TENANT_ID, vnet.tenantId().toString());
return result;
}
@Override
public VirtualNetwork decode(ObjectNode json, CodecContext context) {
if (json == null || !json.isObject()) {
return null;
}
NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
TenantId tId = TenantId.tenantId(extractMember(TENANT_ID, json));
return new DefaultVirtualNetwork(nId, tId);
}
private String extractMember(String key, ObjectNode json) {
return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
}
}
/*
* Copyright 2016 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.codec.impl;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.incubator.net.virtual.DefaultVirtualPort;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.incubator.net.virtual.VirtualPort;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.DefaultPort;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.nullIsIllegal;
/**
* Codec for the VirtualPort class.
*/
public class VirtualPortCodec extends JsonCodec<VirtualPort> {
// JSON field names
private static final String NETWORK_ID = "networkId";
private static final String DEVICE_ID = "deviceId";
private static final String PORT_NUM = "portNum";
private static final String PHYS_DEVICE_ID = "physDeviceId";
private static final String PHYS_PORT_NUM = "physPortNum";
private static final String NULL_OBJECT_MSG = "VirtualPort cannot be null";
private static final String MISSING_MEMBER_MSG = " member is required in VirtualPort";
private static final String INVALID_VIRTUAL_DEVICE = " is not a valid VirtualDevice";
@Override
public ObjectNode encode(VirtualPort vPort, CodecContext context) {
checkNotNull(vPort, NULL_OBJECT_MSG);
ObjectNode result = context.mapper().createObjectNode()
.put(NETWORK_ID, vPort.networkId().toString())
.put(DEVICE_ID, vPort.element().id().toString())
.put(PORT_NUM, vPort.number().toString())
.put(PHYS_DEVICE_ID, vPort.realizedBy().element().id().toString())
.put(PHYS_PORT_NUM, vPort.realizedBy().number().toString());
return result;
}
@Override
public VirtualPort decode(ObjectNode json, CodecContext context) {
if (json == null || !json.isObject()) {
return null;
}
NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
DeviceId dId = DeviceId.deviceId(extractMember(DEVICE_ID, json));
VirtualNetworkService vnetService = context.getService(VirtualNetworkService.class);
Set<VirtualDevice> vDevs = vnetService.getVirtualDevices(nId);
VirtualDevice vDev = vDevs.stream()
.filter(virtualDevice -> virtualDevice.id().equals(dId))
.findFirst().orElse(null);
nullIsIllegal(vDev, dId.toString() + INVALID_VIRTUAL_DEVICE);
PortNumber portNum = PortNumber.portNumber(extractMember(PORT_NUM, json));
DeviceId physDId = DeviceId.deviceId(extractMember(PHYS_DEVICE_ID, json));
PortNumber physPortNum = PortNumber.portNumber(extractMember(PHYS_PORT_NUM, json));
DefaultAnnotations annotations = DefaultAnnotations.builder().build();
Device physDevice = new DefaultDevice(null, physDId,
null, null, null, null, null, null, annotations);
Port realizedBy = new DefaultPort(physDevice, physPortNum, true);
return new DefaultVirtualPort(nId, vDev, portNum, realizedBy);
}
private String extractMember(String key, ObjectNode json) {
return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
}
}
......@@ -22,7 +22,7 @@ import org.onosproject.net.Port;
* Representation of a virtual port.
*/
@Beta
public interface VirtualPort extends Port {
public interface VirtualPort extends VirtualElement, Port {
/**
* Returns the underlying port using which this port is realized.
......
......@@ -47,7 +47,9 @@ public class CoreWebApplication extends AbstractWebApplication {
FlowObjectiveWebResource.class,
MulticastRouteWebResource.class,
DeviceKeyWebResource.class,
RegionsWebResource.class
RegionsWebResource.class,
TenantWebResource.class,
VirtualNetworkWebResource.class
);
}
}
......
/*
* Copyright 2016 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.rest.resources;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.util.ItemNotFoundException;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
import org.onosproject.rest.AbstractWebResource;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.io.InputStream;
/**
* Query and manage tenants of virtual networks.
*/
@Path("tenants")
public class TenantWebResource extends AbstractWebResource {
private static final String MISSING_TENANTID = "Missing tenant identifier";
private static final String TENANTID_NOT_FOUND = "Tenant identifier not found";
private static final String INVALID_TENANTID = "Invalid tenant identifier ";
@Context
UriInfo uriInfo;
private final VirtualNetworkAdminService vnetAdminService = get(VirtualNetworkAdminService.class);
/**
* Returns all tenants.
*
* @return 200 OK
* @onos.rsModel TenantIds
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getVirtualNetworkTenants() {
Iterable<TenantId> tenantIds = vnetAdminService.getTenantIds();
return ok(encodeArray(TenantId.class, "tenants", tenantIds)).build();
}
/**
* Creates a tenant with the given tenant identifier.
*
* @param stream TenantId JSON stream
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel TenantId
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response addTenantId(InputStream stream) {
try {
final TenantId tid = getTenantIdFromJsonStream(stream);
vnetAdminService.registerTenantId(tid);
final TenantId resultTid = getExistingTenantId(vnetAdminService, tid);
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path("tenants")
.path(resultTid.id());
return Response
.created(locationBuilder.build())
.build();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Removes the specified tenant with the specified tenant identifier.
*
* @param tenantId tenant identifier
* @return 200 OK, 404 not found
*/
@DELETE
@Path("{tenantId}")
public Response removeTenantId(@PathParam("tenantId") String tenantId) {
final TenantId tid = TenantId.tenantId(tenantId);
final TenantId existingTid = getExistingTenantId(vnetAdminService, tid);
vnetAdminService.unregisterTenantId(existingTid);
return Response.ok().build();
}
/**
* Removes the specified tenant with the specified tenant identifier.
*
* @param stream deviceIds JSON stream
* @return 200 OK, 404 not found
* @onos.rsModel TenantId
*/
@DELETE
public Response removeTenantId(InputStream stream) {
try {
final TenantId tid = getTenantIdFromJsonStream(stream);
vnetAdminService.unregisterTenantId(tid);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return Response.ok().build();
}
/**
* Get the tenant identifier from the JSON stream.
*
* @param stream TenantId JSON stream
* @return TenantId
* @throws IOException
*/
private TenantId getTenantIdFromJsonStream(InputStream stream) throws IOException {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
JsonNode specifiedTenantId = jsonTree.get("id");
if (specifiedTenantId == null) {
throw new IllegalArgumentException(MISSING_TENANTID);
}
return TenantId.tenantId(specifiedTenantId.asText());
}
/**
* Get the matching tenant identifier from existing tenant identifiers in system.
*
* @param vnetAdminSvc
* @param tidIn tenant identifier
* @return TenantId
*/
private static TenantId getExistingTenantId(VirtualNetworkAdminService vnetAdminSvc,
TenantId tidIn) {
final TenantId resultTid = vnetAdminSvc
.getTenantIds()
.stream()
.filter(tenantId -> tenantId.equals(tidIn))
.findFirst()
.orElseThrow(() -> new ItemNotFoundException(TENANTID_NOT_FOUND));
return resultTid;
}
}
{
"type": "object",
"title": "TenantId",
"required": [
"id"
],
"properties": {
"id": {
"type": "String",
"example": "Tenant unique identifier"
}
}
}
{
"type": "object",
"title": "tenants",
"required": [
"tenants"
],
"properties": {
"tenants": {
"type": "array",
"xml": {
"name": "tenants",
"wrapped": true
},
"items": {
"type": "object",
"title": "tenant",
"required": [
"id"
],
"properties": {
"id": {
"type": "String",
"example": "Tenant unique identifier"
}
}
}
}
}
}
{
"type": "object",
"title": "vdev",
"required": [
"networkId",
"deviceId"
],
"properties": {
"networkId": {
"type": "String",
"example": "Network identifier"
},
"deviceId": {
"type": "String",
"example": "Device identifier"
}
}
}
{
"type": "object",
"title": "vport",
"required": [
"networkId",
"deviceId",
"portNum",
"physDeviceId",
"physPortNum"
],
"properties": {
"networkId": {
"type": "String",
"example": "Network identifier"
},
"deviceId": {
"type": "String",
"example": "Virtual device identifier"
},
"portNum": {
"type": "String",
"example": "Virtual device port number"
},
"physDeviceId": {
"type": "String",
"example": "Physical device identifier"
},
"physPortNum": {
"type": "String",
"example": "Physical device port number"
}
}
}
{
"networkId": "3",
"deviceId": "dev22",
"portNum": "22",
"physDeviceId": "dev1",
"physPortNum": "1"
}