blob: 81a699b5615c2b78c20d2316395121879dbf9416 [file] [log] [blame]
Claudine Chiufb8b8162016-04-01 23:50:51 +00001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Claudine Chiufb8b8162016-04-01 23:50:51 +00003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.rest.resources;
18
19import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import org.onosproject.incubator.net.virtual.NetworkId;
22import org.onosproject.incubator.net.virtual.TenantId;
23import org.onosproject.incubator.net.virtual.VirtualDevice;
Claudine Chiuf6bf8d52016-04-08 01:31:54 +000024import org.onosproject.incubator.net.virtual.VirtualLink;
Claudine Chiufb8b8162016-04-01 23:50:51 +000025import org.onosproject.incubator.net.virtual.VirtualNetwork;
26import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
27import org.onosproject.incubator.net.virtual.VirtualNetworkService;
28import org.onosproject.incubator.net.virtual.VirtualPort;
29import org.onosproject.net.DefaultAnnotations;
30import org.onosproject.net.DefaultDevice;
31import org.onosproject.net.DefaultPort;
32import org.onosproject.net.Device;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.Port;
35import org.onosproject.net.PortNumber;
36import org.onosproject.rest.AbstractWebResource;
37
38import javax.ws.rs.Consumes;
39import javax.ws.rs.DELETE;
40import javax.ws.rs.GET;
41import javax.ws.rs.POST;
42import javax.ws.rs.Path;
43import javax.ws.rs.PathParam;
44import javax.ws.rs.Produces;
45import javax.ws.rs.core.Context;
46import javax.ws.rs.core.MediaType;
47import javax.ws.rs.core.Response;
48import javax.ws.rs.core.UriBuilder;
49import javax.ws.rs.core.UriInfo;
50import java.io.IOException;
51import java.io.InputStream;
52import java.util.Collection;
53import java.util.List;
54import java.util.Set;
55import java.util.stream.Collectors;
56
57/**
58 * Query and Manage Virtual Network elements.
59 */
60@Path("vnets")
61public class VirtualNetworkWebResource extends AbstractWebResource {
62
63 private static final String MISSING_FIELD = "Missing ";
64 private static final String INVALID_FIELD = "Invalid ";
65
66 private final VirtualNetworkAdminService vnetAdminService = get(VirtualNetworkAdminService.class);
67 private final VirtualNetworkService vnetService = get(VirtualNetworkService.class);
68
69 @Context
70 UriInfo uriInfo;
71
72 // VirtualNetwork
Claudine Chiufb8b8162016-04-01 23:50:51 +000073
74 /**
75 * Returns all virtual networks.
76 *
77 * @return 200 OK
78 */
79 @GET
80 @Produces(MediaType.APPLICATION_JSON)
81 public Response getVirtualNetworks() {
82 Set<TenantId> tenantIds = vnetAdminService.getTenantIds();
83 List<VirtualNetwork> allVnets = tenantIds.stream()
84 .map(tenantId -> vnetService.getVirtualNetworks(tenantId))
85 .flatMap(Collection::stream)
86 .collect(Collectors.toList());
87 return ok(encodeArray(VirtualNetwork.class, "vnets", allVnets)).build();
88 }
89
90 /**
Claudine Chiuf6bf8d52016-04-08 01:31:54 +000091 * Returns the virtual networks with the specified tenant identifier.
92 *
93 * @param tenantId tenant identifier
94 * @return 200 OK, 404 not found
95 */
96 @GET
97 @Produces(MediaType.APPLICATION_JSON)
98 @Path("{tenantId}")
99 public Response getVirtualNetworkById(@PathParam("tenantId") String tenantId) {
100 final TenantId existingTid = TenantWebResource.getExistingTenantId(vnetAdminService,
Brian Stanke9a108972016-04-11 15:25:17 -0400101 TenantId.tenantId(tenantId));
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000102 Set<VirtualNetwork> vnets = vnetService.getVirtualNetworks(existingTid);
103 return ok(encodeArray(VirtualNetwork.class, "vnets", vnets)).build();
104 }
105
106 /**
Claudine Chiufb8b8162016-04-01 23:50:51 +0000107 * Creates a virtual network from the JSON input stream.
108 *
109 * @param stream TenantId JSON stream
110 * @return status of the request - CREATED if the JSON is correct,
111 * BAD_REQUEST if the JSON is invalid
112 * @onos.rsModel TenantId
113 */
114 @POST
115 @Consumes(MediaType.APPLICATION_JSON)
116 @Produces(MediaType.APPLICATION_JSON)
117 public Response createVirtualNetwork(InputStream stream) {
118 try {
119 final TenantId tid = TenantId.tenantId(getFromJsonStream(stream, "id").asText());
120 VirtualNetwork newVnet = vnetAdminService.createVirtualNetwork(tid);
121 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
122 .path("vnets")
123 .path(newVnet.id().toString());
124 return Response
125 .created(locationBuilder.build())
126 .build();
127 } catch (IOException e) {
128 throw new IllegalArgumentException(e);
129 }
130 }
131
132 /**
133 * Removes the virtual network with the specified network identifier.
134 *
135 * @param networkId network identifier
136 * @return 200 OK, 404 not found
137 */
138 @DELETE
139 @Path("{networkId}")
140 public Response removeVirtualNetwork(@PathParam("networkId") long networkId) {
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000141 NetworkId nid = NetworkId.networkId(networkId);
Claudine Chiufb8b8162016-04-01 23:50:51 +0000142 vnetAdminService.removeVirtualNetwork(nid);
143 return Response.ok().build();
144 }
145
146 // VirtualDevice
147
148 /**
149 * Returns all virtual network devices in a virtual network.
150 *
151 * @param networkId network identifier
152 * @return 200 OK
153 */
154 @GET
155 @Produces(MediaType.APPLICATION_JSON)
156 @Path("{networkId}/devices")
157 public Response getVirtualDevices(@PathParam("networkId") long networkId) {
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000158 NetworkId nid = NetworkId.networkId(networkId);
Brian Stanke9a108972016-04-11 15:25:17 -0400159 Set<VirtualDevice> vdevs = vnetService.getVirtualDevices(nid);
Claudine Chiufb8b8162016-04-01 23:50:51 +0000160 return ok(encodeArray(VirtualDevice.class, "devices", vdevs)).build();
161 }
162
163 /**
164 * Creates a virtual device from the JSON input stream.
165 *
166 * @param networkId network identifier
Brian Stanke9a108972016-04-11 15:25:17 -0400167 * @param stream Virtual device JSON stream
Claudine Chiufb8b8162016-04-01 23:50:51 +0000168 * @return status of the request - CREATED if the JSON is correct,
169 * BAD_REQUEST if the JSON is invalid
170 * @onos.rsModel VirtualDevice
171 */
172 @POST
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000173 @Path("{networkId}/devices")
Claudine Chiufb8b8162016-04-01 23:50:51 +0000174 @Consumes(MediaType.APPLICATION_JSON)
175 @Produces(MediaType.APPLICATION_JSON)
176 public Response createVirtualDevice(@PathParam("networkId") long networkId,
177 InputStream stream) {
178 try {
179 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
180 final VirtualDevice vdevReq = codec(VirtualDevice.class).decode(jsonTree, this);
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000181 JsonNode specifiedNetworkId = jsonTree.get("networkId");
182 if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
Claudine Chiufb8b8162016-04-01 23:50:51 +0000183 throw new IllegalArgumentException(INVALID_FIELD + "networkId");
184 }
185 final VirtualDevice vdevRes = vnetAdminService.createVirtualDevice(vdevReq.networkId(),
186 vdevReq.id());
187 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000188 .path("vnets").path(specifiedNetworkId.asText())
Claudine Chiufb8b8162016-04-01 23:50:51 +0000189 .path("devices").path(vdevRes.id().toString());
190 return Response
191 .created(locationBuilder.build())
192 .build();
193 } catch (IOException e) {
194 throw new IllegalArgumentException(e);
195 }
196 }
197
198 /**
199 * Removes the virtual network device from the virtual network.
200 *
201 * @param networkId network identifier
Brian Stanke9a108972016-04-11 15:25:17 -0400202 * @param deviceId device identifier
Claudine Chiufb8b8162016-04-01 23:50:51 +0000203 * @return 200 OK, 404 not found
204 */
205 @DELETE
206 @Path("{networkId}/devices/{deviceId}")
207 public Response removeVirtualDevice(@PathParam("networkId") long networkId,
Brian Stanke9a108972016-04-11 15:25:17 -0400208 @PathParam("deviceId") String deviceId) {
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000209 NetworkId nid = NetworkId.networkId(networkId);
210 DeviceId did = DeviceId.deviceId(deviceId);
Claudine Chiufb8b8162016-04-01 23:50:51 +0000211 vnetAdminService.removeVirtualDevice(nid, did);
212 return Response.ok().build();
213 }
214
215 // VirtualPort
216
217 /**
218 * Returns all virtual network ports in a virtual device in a virtual network.
219 *
220 * @param networkId network identifier
Brian Stanke9a108972016-04-11 15:25:17 -0400221 * @param deviceId virtual device identifier
Claudine Chiufb8b8162016-04-01 23:50:51 +0000222 * @return 200 OK
223 */
224 @GET
225 @Produces(MediaType.APPLICATION_JSON)
226 @Path("{networkId}/devices/{deviceId}/ports")
227 public Response getVirtualPorts(@PathParam("networkId") long networkId,
Brian Stanke9a108972016-04-11 15:25:17 -0400228 @PathParam("deviceId") String deviceId) {
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000229 NetworkId nid = NetworkId.networkId(networkId);
Brian Stanke9a108972016-04-11 15:25:17 -0400230 Iterable<VirtualPort> vports = vnetService.getVirtualPorts(nid, DeviceId.deviceId(deviceId));
Claudine Chiufb8b8162016-04-01 23:50:51 +0000231 return ok(encodeArray(VirtualPort.class, "ports", vports)).build();
232 }
233
234 /**
235 * Creates a virtual network port in a virtual device in a virtual network.
236 *
Brian Stanke9a108972016-04-11 15:25:17 -0400237 * @param networkId network identifier
Claudine Chiufb8b8162016-04-01 23:50:51 +0000238 * @param virtDeviceId virtual device identifier
Brian Stanke9a108972016-04-11 15:25:17 -0400239 * @param stream Virtual device JSON stream
Claudine Chiufb8b8162016-04-01 23:50:51 +0000240 * @return status of the request - CREATED if the JSON is correct,
241 * BAD_REQUEST if the JSON is invalid
242 * @onos.rsModel VirtualPort
243 */
244 @POST
245 @Consumes(MediaType.APPLICATION_JSON)
246 @Produces(MediaType.APPLICATION_JSON)
247 @Path("{networkId}/devices/{deviceId}/ports")
248 public Response createVirtualPort(@PathParam("networkId") long networkId,
Brian Stanke9a108972016-04-11 15:25:17 -0400249 @PathParam("deviceId") String virtDeviceId,
250 InputStream stream) {
Claudine Chiufb8b8162016-04-01 23:50:51 +0000251 try {
252 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
253// final VirtualPort vportReq = codec(VirtualPort.class).decode(jsonTree, this);
254 JsonNode specifiedNetworkId = jsonTree.get("networkId");
255 JsonNode specifiedDeviceId = jsonTree.get("deviceId");
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000256 if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
Claudine Chiufb8b8162016-04-01 23:50:51 +0000257 throw new IllegalArgumentException(INVALID_FIELD + "networkId");
258 }
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000259 if (specifiedDeviceId == null || !specifiedDeviceId.asText().equals(virtDeviceId)) {
Claudine Chiufb8b8162016-04-01 23:50:51 +0000260 throw new IllegalArgumentException(INVALID_FIELD + "deviceId");
261 }
262 JsonNode specifiedPortNum = jsonTree.get("portNum");
263 JsonNode specifiedPhysDeviceId = jsonTree.get("physDeviceId");
264 JsonNode specifiedPhysPortNum = jsonTree.get("physPortNum");
265 final NetworkId nid = NetworkId.networkId(networkId);
266 DeviceId vdevId = DeviceId.deviceId(virtDeviceId);
267 DefaultAnnotations annotations = DefaultAnnotations.builder().build();
268 Device physDevice = new DefaultDevice(null, DeviceId.deviceId(specifiedPhysDeviceId.asText()),
Brian Stanke9a108972016-04-11 15:25:17 -0400269 null, null, null, null, null, null, annotations);
Claudine Chiufb8b8162016-04-01 23:50:51 +0000270 Port realizedBy = new DefaultPort(physDevice,
Brian Stanke9a108972016-04-11 15:25:17 -0400271 PortNumber.portNumber(specifiedPhysPortNum.asText()), true);
Claudine Chiufb8b8162016-04-01 23:50:51 +0000272 VirtualPort vport = vnetAdminService.createVirtualPort(nid, vdevId,
Brian Stanke9a108972016-04-11 15:25:17 -0400273 PortNumber.portNumber(specifiedPortNum.asText()), realizedBy);
Claudine Chiufb8b8162016-04-01 23:50:51 +0000274 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
275 .path("vnets").path(specifiedNetworkId.asText())
276 .path("devices").path(specifiedDeviceId.asText())
277 .path("ports").path(vport.number().toString());
278 return Response
279 .created(locationBuilder.build())
280 .build();
281 } catch (IOException e) {
282 throw new IllegalArgumentException(e);
283 }
284 }
285
286 /**
287 * Removes the virtual network port from the virtual device in a virtual network.
288 *
289 * @param networkId network identifier
Brian Stanke9a108972016-04-11 15:25:17 -0400290 * @param deviceId virtual device identifier
291 * @param portNum virtual port number
Claudine Chiufb8b8162016-04-01 23:50:51 +0000292 * @return 200 OK, 404 not found
293 */
294 @DELETE
295 @Path("{networkId}/devices/{deviceId}/ports/{portNum}")
296 public Response removeVirtualPort(@PathParam("networkId") long networkId,
Brian Stanke9a108972016-04-11 15:25:17 -0400297 @PathParam("deviceId") String deviceId,
298 @PathParam("portNum") long portNum) {
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000299 NetworkId nid = NetworkId.networkId(networkId);
Claudine Chiufb8b8162016-04-01 23:50:51 +0000300 vnetAdminService.removeVirtualPort(nid, DeviceId.deviceId(deviceId),
Brian Stanke9a108972016-04-11 15:25:17 -0400301 PortNumber.portNumber(portNum));
Claudine Chiufb8b8162016-04-01 23:50:51 +0000302 return Response.ok().build();
303 }
304
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000305 // VirtualLink
306
307 /**
308 * Returns all virtual network links in a virtual network.
309 *
310 * @param networkId network identifier
311 * @return 200 OK
312 */
313 @GET
314 @Produces(MediaType.APPLICATION_JSON)
315 @Path("{networkId}/links")
316 public Response getVirtualLinks(@PathParam("networkId") long networkId) {
317 NetworkId nid = NetworkId.networkId(networkId);
Brian Stanke9a108972016-04-11 15:25:17 -0400318 Set<VirtualLink> vlinks = vnetService.getVirtualLinks(nid);
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000319 return ok(encodeArray(VirtualLink.class, "links", vlinks)).build();
320 }
321
Brian Stanke9a108972016-04-11 15:25:17 -0400322 /**
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000323 * Creates a virtual network link from the JSON input stream.
324 *
325 * @param networkId network identifier
Brian Stanke9a108972016-04-11 15:25:17 -0400326 * @param stream Virtual device JSON stream
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000327 * @return status of the request - CREATED if the JSON is correct,
328 * BAD_REQUEST if the JSON is invalid
329 * @onos.rsModel VirtualLink
330 */
331 @POST
332 @Path("{networkId}/links")
333 @Consumes(MediaType.APPLICATION_JSON)
334 @Produces(MediaType.APPLICATION_JSON)
335 public Response createVirtualLink(@PathParam("networkId") long networkId,
336 InputStream stream) {
337 try {
338 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
339 JsonNode specifiedNetworkId = jsonTree.get("networkId");
340 if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
341 throw new IllegalArgumentException(INVALID_FIELD + "networkId");
342 }
343 final VirtualLink vlinkReq = codec(VirtualLink.class).decode(jsonTree, this);
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000344 vnetAdminService.createVirtualLink(vlinkReq.networkId(),
Brian Stanke9a108972016-04-11 15:25:17 -0400345 vlinkReq.src(), vlinkReq.dst());
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000346 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
347 .path("vnets").path(specifiedNetworkId.asText())
348 .path("links");
349 return Response
350 .created(locationBuilder.build())
351 .build();
352 } catch (IOException e) {
353 throw new IllegalArgumentException(e);
354 }
355 }
356
357 /**
358 * Removes the virtual network link from the JSON input stream.
359 *
360 * @param networkId network identifier
Brian Stanke9a108972016-04-11 15:25:17 -0400361 * @param stream deviceIds JSON stream
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000362 * @return 200 OK, 404 not found
363 * @onos.rsModel VirtualLink
364 */
365 @DELETE
366 @Path("{networkId}/links")
367 @Consumes(MediaType.APPLICATION_JSON)
368 public Response removeVirtualLink(@PathParam("networkId") long networkId,
Brian Stanke9a108972016-04-11 15:25:17 -0400369 InputStream stream) {
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000370 try {
371 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
372 JsonNode specifiedNetworkId = jsonTree.get("networkId");
373 if (specifiedNetworkId != null &&
374 specifiedNetworkId.asLong() != (networkId)) {
375 throw new IllegalArgumentException(INVALID_FIELD + "networkId");
376 }
377 final VirtualLink vlinkReq = codec(VirtualLink.class).decode(jsonTree, this);
378 vnetAdminService.removeVirtualLink(vlinkReq.networkId(),
Brian Stanke9a108972016-04-11 15:25:17 -0400379 vlinkReq.src(), vlinkReq.dst());
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000380 } catch (IOException e) {
381 throw new IllegalArgumentException(e);
382 }
383
384 return Response.ok().build();
385 }
386
387 /**
Claudine Chiufb8b8162016-04-01 23:50:51 +0000388 * Get the tenant identifier from the JSON stream.
389 *
Brian Stanke9a108972016-04-11 15:25:17 -0400390 * @param stream TenantId JSON stream
Claudine Chiufb8b8162016-04-01 23:50:51 +0000391 * @param jsonFieldName field name
392 * @return JsonNode
Claudine Chiuf6bf8d52016-04-08 01:31:54 +0000393 * @throws IOException if unable to parse the request
Claudine Chiufb8b8162016-04-01 23:50:51 +0000394 */
395 private JsonNode getFromJsonStream(InputStream stream, String jsonFieldName) throws IOException {
396 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
397 JsonNode jsonNode = jsonTree.get(jsonFieldName);
398
399 if (jsonNode == null) {
400 throw new IllegalArgumentException(MISSING_FIELD + jsonFieldName);
401 }
402 return jsonNode;
403 }
404}