blob: 0e3504c8dd30f9694c58ed9ed3d35207a23d26bb [file] [log] [blame]
/*
* Copyright 2016-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.rest.resources;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.incubator.net.virtual.VirtualHost;
import org.onosproject.incubator.net.virtual.VirtualLink;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.incubator.net.virtual.VirtualPort;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
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;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.onlab.util.Tools.readTreeFromStream;
/**
* Query and Manage Virtual Network elements.
*/
@Path("vnets")
public class VirtualNetworkWebResource extends AbstractWebResource {
private static final String MISSING_FIELD = "Missing ";
private static final String INVALID_FIELD = "Invalid ";
private final VirtualNetworkAdminService vnetAdminService = get(VirtualNetworkAdminService.class);
private final VirtualNetworkService vnetService = get(VirtualNetworkService.class);
@Context
private UriInfo uriInfo;
// VirtualNetwork
/**
* Returns all virtual networks.
*
* @return 200 OK with set of virtual networks
* @onos.rsModel VirtualNetworks
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getVirtualNetworks() {
Set<TenantId> tenantIds = vnetAdminService.getTenantIds();
List<VirtualNetwork> allVnets = tenantIds.stream()
.map(tenantId -> vnetService.getVirtualNetworks(tenantId))
.flatMap(Collection::stream)
.collect(Collectors.toList());
return ok(encodeArray(VirtualNetwork.class, "vnets", allVnets)).build();
}
/**
* Returns the virtual networks with the specified tenant identifier.
*
* @param tenantId tenant identifier
* @return 200 OK with a virtual network, 404 not found
* @onos.rsModel VirtualNetworks
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{tenantId}")
public Response getVirtualNetworkById(@PathParam("tenantId") String tenantId) {
final TenantId existingTid = TenantWebResource.getExistingTenantId(vnetAdminService,
TenantId.tenantId(tenantId));
Set<VirtualNetwork> vnets = vnetService.getVirtualNetworks(existingTid);
return ok(encodeArray(VirtualNetwork.class, "vnets", vnets)).build();
}
/**
* Creates a virtual network from the JSON input stream.
*
* @param stream tenant identifier 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 createVirtualNetwork(InputStream stream) {
try {
final TenantId tid = TenantId.tenantId(getFromJsonStream(stream, "id").asText());
VirtualNetwork newVnet = vnetAdminService.createVirtualNetwork(tid);
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path("vnets")
.path(newVnet.id().toString());
return Response
.created(locationBuilder.build())
.build();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Removes the virtual network with the specified network identifier.
*
* @param networkId network identifier
* @return 204 NO CONTENT
*/
@DELETE
@Path("{networkId}")
public Response removeVirtualNetwork(@PathParam("networkId") long networkId) {
NetworkId nid = NetworkId.networkId(networkId);
vnetAdminService.removeVirtualNetwork(nid);
return Response.noContent().build();
}
// VirtualDevice
/**
* Returns all virtual network devices in a virtual network.
*
* @param networkId network identifier
* @return 200 OK with set of virtual devices, 404 not found
* @onos.rsModel VirtualDevices
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{networkId}/devices")
public Response getVirtualDevices(@PathParam("networkId") long networkId) {
NetworkId nid = NetworkId.networkId(networkId);
Set<VirtualDevice> vdevs = vnetService.getVirtualDevices(nid);
return ok(encodeArray(VirtualDevice.class, "devices", vdevs)).build();
}
/**
* Creates a virtual device from the JSON input stream.
*
* @param networkId network identifier
* @param stream virtual device JSON stream
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel VirtualDevice
*/
@POST
@Path("{networkId}/devices")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createVirtualDevice(@PathParam("networkId") long networkId,
InputStream stream) {
try {
ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
final VirtualDevice vdevReq = codec(VirtualDevice.class).decode(jsonTree, this);
JsonNode specifiedNetworkId = jsonTree.get("networkId");
if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
final VirtualDevice vdevRes = vnetAdminService.createVirtualDevice(vdevReq.networkId(),
vdevReq.id());
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path("vnets").path(specifiedNetworkId.asText())
.path("devices").path(vdevRes.id().toString());
return Response
.created(locationBuilder.build())
.build();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Removes the virtual network device from the virtual network.
*
* @param networkId network identifier
* @param deviceId device identifier
* @return 204 NO CONTENT
*/
@DELETE
@Path("{networkId}/devices/{deviceId}")
public Response removeVirtualDevice(@PathParam("networkId") long networkId,
@PathParam("deviceId") String deviceId) {
NetworkId nid = NetworkId.networkId(networkId);
DeviceId did = DeviceId.deviceId(deviceId);
vnetAdminService.removeVirtualDevice(nid, did);
return Response.noContent().build();
}
// VirtualPort
/**
* Returns all virtual network ports in a virtual device in a virtual network.
*
* @param networkId network identifier
* @param deviceId virtual device identifier
* @return 200 OK with set of virtual ports, 404 not found
* @onos.rsModel VirtualPorts
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{networkId}/devices/{deviceId}/ports")
public Response getVirtualPorts(@PathParam("networkId") long networkId,
@PathParam("deviceId") String deviceId) {
NetworkId nid = NetworkId.networkId(networkId);
Iterable<VirtualPort> vports = vnetService.getVirtualPorts(nid, DeviceId.deviceId(deviceId));
return ok(encodeArray(VirtualPort.class, "ports", vports)).build();
}
/**
* Creates a virtual network port in a virtual device in a virtual network.
*
* @param networkId network identifier
* @param virtDeviceId virtual device identifier
* @param stream virtual port JSON stream
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel VirtualPort
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("{networkId}/devices/{deviceId}/ports")
public Response createVirtualPort(@PathParam("networkId") long networkId,
@PathParam("deviceId") String virtDeviceId,
InputStream stream) {
try {
ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
// final VirtualPort vportReq = codec(VirtualPort.class).decode(jsonTree, this);
JsonNode specifiedNetworkId = jsonTree.get("networkId");
JsonNode specifiedDeviceId = jsonTree.get("deviceId");
if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
if (specifiedDeviceId == null || !specifiedDeviceId.asText().equals(virtDeviceId)) {
throw new IllegalArgumentException(INVALID_FIELD + "deviceId");
}
JsonNode specifiedPortNum = jsonTree.get("portNum");
JsonNode specifiedPhysDeviceId = jsonTree.get("physDeviceId");
JsonNode specifiedPhysPortNum = jsonTree.get("physPortNum");
final NetworkId nid = NetworkId.networkId(networkId);
DeviceId vdevId = DeviceId.deviceId(virtDeviceId);
ConnectPoint realizedBy = new ConnectPoint(DeviceId.deviceId(specifiedPhysDeviceId.asText()),
PortNumber.portNumber(specifiedPhysPortNum.asText()));
VirtualPort vport = vnetAdminService.createVirtualPort(nid, vdevId,
PortNumber.portNumber(specifiedPortNum.asText()), realizedBy);
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path("vnets").path(specifiedNetworkId.asText())
.path("devices").path(specifiedDeviceId.asText())
.path("ports").path(vport.number().toString());
return Response
.created(locationBuilder.build())
.build();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Removes the virtual network port from the virtual device in a virtual network.
*
* @param networkId network identifier
* @param deviceId virtual device identifier
* @param portNum virtual port number
* @return 204 NO CONTENT
*/
@DELETE
@Path("{networkId}/devices/{deviceId}/ports/{portNum}")
public Response removeVirtualPort(@PathParam("networkId") long networkId,
@PathParam("deviceId") String deviceId,
@PathParam("portNum") long portNum) {
NetworkId nid = NetworkId.networkId(networkId);
vnetAdminService.removeVirtualPort(nid, DeviceId.deviceId(deviceId),
PortNumber.portNumber(portNum));
return Response.noContent().build();
}
// VirtualLink
/**
* Returns all virtual network links in a virtual network.
*
* @param networkId network identifier
* @return 200 OK with set of virtual network links
* @onos.rsModel VirtualLinks
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{networkId}/links")
public Response getVirtualLinks(@PathParam("networkId") long networkId) {
NetworkId nid = NetworkId.networkId(networkId);
Set<VirtualLink> vlinks = vnetService.getVirtualLinks(nid);
return ok(encodeArray(VirtualLink.class, "links", vlinks)).build();
}
/**
* Creates a virtual network link from the JSON input stream.
*
* @param networkId network identifier
* @param stream virtual link JSON stream
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel VirtualLink
*/
@POST
@Path("{networkId}/links")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createVirtualLink(@PathParam("networkId") long networkId,
InputStream stream) {
try {
ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
JsonNode specifiedNetworkId = jsonTree.get("networkId");
if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
final VirtualLink vlinkReq = codec(VirtualLink.class).decode(jsonTree, this);
vnetAdminService.createVirtualLink(vlinkReq.networkId(),
vlinkReq.src(), vlinkReq.dst());
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path("vnets").path(specifiedNetworkId.asText())
.path("links");
return Response
.created(locationBuilder.build())
.build();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Removes the virtual network link from the JSON input stream.
*
* @param networkId network identifier
* @param stream virtual link JSON stream
* @return 204 NO CONTENT
* @onos.rsModel VirtualLink
*/
@DELETE
@Path("{networkId}/links")
@Consumes(MediaType.APPLICATION_JSON)
public Response removeVirtualLink(@PathParam("networkId") long networkId,
InputStream stream) {
try {
ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
JsonNode specifiedNetworkId = jsonTree.get("networkId");
if (specifiedNetworkId != null &&
specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
final VirtualLink vlinkReq = codec(VirtualLink.class).decode(jsonTree, this);
vnetAdminService.removeVirtualLink(vlinkReq.networkId(),
vlinkReq.src(), vlinkReq.dst());
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return Response.noContent().build();
}
/**
* Returns all virtual network hosts in a virtual network.
*
* @param networkId network identifier
* @return 200 OK with set of virtual network hosts
* @onos.rsModel VirtualHosts
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{networkId}/hosts")
public Response getVirtualHosts(@PathParam("networkId") long networkId) {
NetworkId nid = NetworkId.networkId(networkId);
Set<VirtualHost> vhosts = vnetService.getVirtualHosts(nid);
return ok(encodeArray(VirtualHost.class, "hosts", vhosts)).build();
}
/**
* Creates a virtual network host from the JSON input stream.
*
* @param networkId network identifier
* @param stream virtual host JSON stream
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel VirtualHostPut
*/
@POST
@Path("{networkId}/hosts")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createVirtualHost(@PathParam("networkId") long networkId,
InputStream stream) {
try {
ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
JsonNode specifiedNetworkId = jsonTree.get("networkId");
if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
final VirtualHost vhostReq = codec(VirtualHost.class).decode(jsonTree, this);
vnetAdminService.createVirtualHost(vhostReq.networkId(), vhostReq.id(),
vhostReq.mac(), vhostReq.vlan(),
vhostReq.location(), vhostReq.ipAddresses());
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path("vnets").path(specifiedNetworkId.asText())
.path("hosts");
return Response
.created(locationBuilder.build())
.build();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Removes the virtual network host from the JSON input stream.
*
* @param networkId network identifier
* @param stream virtual host JSON stream
* @return 204 NO CONTENT
* @onos.rsModel VirtualHost
*/
@DELETE
@Path("{networkId}/hosts")
@Consumes(MediaType.APPLICATION_JSON)
public Response removeVirtualHost(@PathParam("networkId") long networkId,
InputStream stream) {
try {
ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
JsonNode specifiedNetworkId = jsonTree.get("networkId");
if (specifiedNetworkId != null &&
specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
final VirtualHost vhostReq = codec(VirtualHost.class).decode(jsonTree, this);
vnetAdminService.removeVirtualHost(vhostReq.networkId(), vhostReq.id());
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return Response.noContent().build();
}
/**
* Get the tenant identifier from the JSON stream.
*
* @param stream TenantId JSON stream
* @param jsonFieldName field name
* @return JsonNode
* @throws IOException if unable to parse the request
*/
private JsonNode getFromJsonStream(InputStream stream, String jsonFieldName) throws IOException {
ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
JsonNode jsonNode = jsonTree.get(jsonFieldName);
if (jsonNode == null) {
throw new IllegalArgumentException(MISSING_FIELD + jsonFieldName);
}
return jsonNode;
}
}