blob: f8b87ccc1bfd14fbc00012929385a5f83f6f3834 [file] [log] [blame]
jiangrui330b0c92015-11-28 14:09:50 +08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
jiangrui330b0c92015-11-28 14:09:50 +08003 *
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 */
16package org.onosproject.vtnweb.resources;
17
Jian Lic2a542b2016-05-10 11:48:19 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.collect.Maps;
22import com.google.common.collect.Sets;
jiangrui330b0c92015-11-28 14:09:50 +080023import org.onlab.packet.IpAddress;
24import org.onlab.util.ItemNotFoundException;
25import org.onosproject.rest.AbstractWebResource;
26import org.onosproject.vtnrsc.DefaultRouter;
27import org.onosproject.vtnrsc.FixedIp;
28import org.onosproject.vtnrsc.Router;
29import org.onosproject.vtnrsc.Router.Status;
30import org.onosproject.vtnrsc.RouterGateway;
31import org.onosproject.vtnrsc.RouterId;
32import org.onosproject.vtnrsc.RouterInterface;
33import org.onosproject.vtnrsc.SubnetId;
34import org.onosproject.vtnrsc.TenantId;
35import org.onosproject.vtnrsc.TenantNetworkId;
36import org.onosproject.vtnrsc.VirtualPortId;
37import org.onosproject.vtnrsc.router.RouterService;
38import org.onosproject.vtnrsc.routerinterface.RouterInterfaceService;
39import org.onosproject.vtnweb.web.RouterCodec;
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
Jian Lic2a542b2016-05-10 11:48:19 -070043import javax.ws.rs.Consumes;
44import javax.ws.rs.DELETE;
45import javax.ws.rs.GET;
46import javax.ws.rs.POST;
47import javax.ws.rs.PUT;
48import javax.ws.rs.Path;
49import javax.ws.rs.PathParam;
50import javax.ws.rs.Produces;
51import javax.ws.rs.QueryParam;
52import javax.ws.rs.core.MediaType;
53import javax.ws.rs.core.Response;
54import java.io.IOException;
55import java.io.InputStream;
56import java.util.ArrayList;
57import java.util.Collection;
58import java.util.Collections;
59import java.util.HashMap;
60import java.util.List;
61import java.util.Map;
62import java.util.Set;
63import java.util.concurrent.ConcurrentMap;
64
65import static com.google.common.base.Preconditions.checkArgument;
66import static com.google.common.base.Preconditions.checkNotNull;
67import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
68import static javax.ws.rs.core.Response.Status.CONFLICT;
69import static javax.ws.rs.core.Response.Status.CREATED;
70import static javax.ws.rs.core.Response.Status.NOT_FOUND;
jiangrui330b0c92015-11-28 14:09:50 +080071
72@Path("routers")
73public class RouterWebResource extends AbstractWebResource {
74 private final Logger log = LoggerFactory.getLogger(RouterWebResource.class);
75 public static final String CREATE_FAIL = "Router is failed to create!";
76 public static final String UPDATE_FAIL = "Router is failed to update!";
77 public static final String GET_FAIL = "Router is failed to get!";
78 public static final String NOT_EXIST = "Router does not exist!";
79 public static final String DELETE_SUCCESS = "Router delete success!";
80 public static final String JSON_NOT_NULL = "JsonNode can not be null";
81 public static final String INTFACR_ADD_SUCCESS = "Interface add success";
82 public static final String INTFACR_DEL_SUCCESS = "Interface delete success";
83
84 @GET
85 @Produces(MediaType.APPLICATION_JSON)
86 public Response listRouters() {
87 Collection<Router> routers = get(RouterService.class).getRouters();
88 ObjectNode result = new ObjectMapper().createObjectNode();
89 result.set("routers", new RouterCodec().encode(routers, this));
90 return ok(result.toString()).build();
91 }
92
93 @GET
94 @Path("{routerUUID}")
95 @Produces(MediaType.APPLICATION_JSON)
96 public Response getRouter(@PathParam("routerUUID") String id,
97 @QueryParam("fields") List<String> fields) {
98
99 if (!get(RouterService.class).exists(RouterId.valueOf(id))) {
100 return Response.status(NOT_FOUND)
101 .entity("The Router does not exists").build();
102 }
103 Router sub = nullIsNotFound(get(RouterService.class)
lishuaid6f0c9e2015-12-16 11:40:01 +0800104 .getRouter(RouterId.valueOf(id)), NOT_EXIST);
jiangrui330b0c92015-11-28 14:09:50 +0800105
106 ObjectNode result = new ObjectMapper().createObjectNode();
107 if (fields.size() > 0) {
108 result.set("router",
109 new RouterCodec().extracFields(sub, this, fields));
110 } else {
111 result.set("router", new RouterCodec().encode(sub, this));
112 }
113 return ok(result.toString()).build();
114 }
115
116 @POST
117 @Produces(MediaType.APPLICATION_JSON)
118 @Consumes(MediaType.APPLICATION_JSON)
119 public Response createRouter(final InputStream input) {
120 try {
121 ObjectMapper mapper = new ObjectMapper();
122 JsonNode subnode = mapper.readTree(input);
123 Collection<Router> routers = createOrUpdateByInputStream(subnode);
124
125 Boolean result = nullIsNotFound((get(RouterService.class)
lishuaid6f0c9e2015-12-16 11:40:01 +0800126 .createRouters(routers)), CREATE_FAIL);
jiangrui330b0c92015-11-28 14:09:50 +0800127 if (!result) {
128 return Response.status(CONFLICT).entity(CREATE_FAIL).build();
129 }
130 return Response.status(CREATED).entity(result.toString()).build();
131
132 } catch (Exception e) {
133 return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
134 }
135 }
136
137 @PUT
138 @Path("{routerUUID}")
139 @Produces(MediaType.APPLICATION_JSON)
140 @Consumes(MediaType.APPLICATION_JSON)
141 public Response updateRouter(@PathParam("routerUUID") String id,
142 final InputStream input) {
143 try {
144 ObjectMapper mapper = new ObjectMapper();
145 JsonNode subnode = mapper.readTree(input);
lishuaid6f0c9e2015-12-16 11:40:01 +0800146 Collection<Router> routers = changeUpdateJsonToSub(subnode, id);
jiangrui330b0c92015-11-28 14:09:50 +0800147 Boolean result = nullIsNotFound(get(RouterService.class)
148 .updateRouters(routers), UPDATE_FAIL);
149 if (!result) {
150 return Response.status(CONFLICT).entity(UPDATE_FAIL).build();
151 }
152 return ok(result.toString()).build();
153 } catch (Exception e) {
154 return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
155 }
156 }
157
jiangrui330b0c92015-11-28 14:09:50 +0800158 @DELETE
Wu wenbinb0bd6132016-05-10 19:20:23 +0800159 @Path("{routerUUID}")
160 @Consumes(MediaType.APPLICATION_JSON)
161 @Produces(MediaType.APPLICATION_JSON)
jiangrui330b0c92015-11-28 14:09:50 +0800162 public Response deleteSingleRouter(@PathParam("routerUUID") String id)
163 throws IOException {
164 try {
165 RouterId routerId = RouterId.valueOf(id);
166 Set<RouterId> routerIds = Sets.newHashSet(routerId);
167 get(RouterService.class).removeRouters(routerIds);
Jian Lic2a542b2016-05-10 11:48:19 -0700168 return Response.noContent().entity(DELETE_SUCCESS).build();
jiangrui330b0c92015-11-28 14:09:50 +0800169 } catch (Exception e) {
170 return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
171 }
172 }
173
174 @PUT
175 @Path("{routerUUID}/add_router_interface")
176 @Produces(MediaType.APPLICATION_JSON)
177 @Consumes(MediaType.APPLICATION_JSON)
178 public Response addRouterInterface(@PathParam("routerUUID") String id,
179 final InputStream input) {
180 if (!get(RouterService.class).exists(RouterId.valueOf(id))) {
181 return Response.status(NOT_FOUND).entity(NOT_EXIST).build();
182 }
183 try {
184 ObjectMapper mapper = new ObjectMapper();
185 JsonNode subnode = mapper.readTree(input);
186 if (!subnode.hasNonNull("id")) {
187 throw new IllegalArgumentException("id should not be null");
188 } else if (subnode.get("id").asText().isEmpty()) {
189 throw new IllegalArgumentException("id should not be empty");
190 }
191 RouterId routerId = RouterId.valueOf(id);
192 if (!subnode.hasNonNull("subnet_id")) {
193 throw new IllegalArgumentException("subnet_id should not be null");
194 } else if (subnode.get("subnet_id").asText().isEmpty()) {
195 throw new IllegalArgumentException("subnet_id should not be empty");
196 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800197 SubnetId subnetId = SubnetId
198 .subnetId(subnode.get("subnet_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800199 if (!subnode.hasNonNull("tenant_id")) {
200 throw new IllegalArgumentException("tenant_id should not be null");
201 } else if (subnode.get("tenant_id").asText().isEmpty()) {
202 throw new IllegalArgumentException("tenant_id should not be empty");
203 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800204 TenantId tenentId = TenantId
205 .tenantId(subnode.get("tenant_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800206 if (!subnode.hasNonNull("port_id")) {
207 throw new IllegalArgumentException("port_id should not be null");
208 } else if (subnode.get("port_id").asText().isEmpty()) {
209 throw new IllegalArgumentException("port_id should not be empty");
210 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800211 VirtualPortId portId = VirtualPortId
212 .portId(subnode.get("port_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800213 RouterInterface routerInterface = RouterInterface
214 .routerInterface(subnetId, portId, routerId, tenentId);
215 get(RouterInterfaceService.class)
216 .addRouterInterface(routerInterface);
217 return ok(INTFACR_ADD_SUCCESS).build();
218 } catch (Exception e) {
219 return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
220 }
221 }
222
223 @PUT
224 @Path("{routerUUID}/remove_router_interface")
225 @Produces(MediaType.APPLICATION_JSON)
226 @Consumes(MediaType.APPLICATION_JSON)
227 public Response removeRouterInterface(@PathParam("routerUUID") String id,
228 final InputStream input) {
229 if (!get(RouterService.class).exists(RouterId.valueOf(id))) {
230 return Response.status(NOT_FOUND).entity(NOT_EXIST).build();
231 }
232 try {
233 ObjectMapper mapper = new ObjectMapper();
234 JsonNode subnode = mapper.readTree(input);
235 if (!subnode.hasNonNull("id")) {
236 throw new IllegalArgumentException("id should not be null");
237 } else if (subnode.get("id").asText().isEmpty()) {
238 throw new IllegalArgumentException("id should not be empty");
239 }
240 RouterId routerId = RouterId.valueOf(id);
241 if (!subnode.hasNonNull("subnet_id")) {
242 throw new IllegalArgumentException("subnet_id should not be null");
243 } else if (subnode.get("subnet_id").asText().isEmpty()) {
244 throw new IllegalArgumentException("subnet_id should not be empty");
245 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800246 SubnetId subnetId = SubnetId
247 .subnetId(subnode.get("subnet_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800248 if (!subnode.hasNonNull("port_id")) {
249 throw new IllegalArgumentException("port_id should not be null");
250 } else if (subnode.get("port_id").asText().isEmpty()) {
251 throw new IllegalArgumentException("port_id should not be empty");
252 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800253 VirtualPortId portId = VirtualPortId
254 .portId(subnode.get("port_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800255 if (!subnode.hasNonNull("tenant_id")) {
256 throw new IllegalArgumentException("tenant_id should not be null");
257 } else if (subnode.get("tenant_id").asText().isEmpty()) {
258 throw new IllegalArgumentException("tenant_id should not be empty");
259 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800260 TenantId tenentId = TenantId
261 .tenantId(subnode.get("tenant_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800262 RouterInterface routerInterface = RouterInterface
263 .routerInterface(subnetId, portId, routerId, tenentId);
264 get(RouterInterfaceService.class)
265 .removeRouterInterface(routerInterface);
266 return ok(INTFACR_DEL_SUCCESS).build();
267 } catch (Exception e) {
268 return Response.status(BAD_REQUEST).entity(e.getMessage()).build();
269 }
270 }
271
272 private Collection<Router> createOrUpdateByInputStream(JsonNode subnode)
273 throws Exception {
274 checkNotNull(subnode, JSON_NOT_NULL);
275 JsonNode routerNode = subnode.get("routers");
276 if (routerNode == null) {
277 routerNode = subnode.get("router");
278 }
279 log.debug("routerNode is {}", routerNode.toString());
280
281 if (routerNode.isArray()) {
282 throw new Exception("only singleton requests allowed");
283 } else {
284 return changeJsonToSub(routerNode);
285 }
286 }
287
288 /**
289 * Returns a collection of floatingIps from floatingIpNodes.
290 *
291 * @param routerNode the router json node
292 * @return routers a collection of router
Bharat saraswald270b182015-12-01 01:53:06 +0530293 * @throws Exception when any argument is illegal
jiangrui330b0c92015-11-28 14:09:50 +0800294 */
295 public Collection<Router> changeJsonToSub(JsonNode routerNode)
296 throws Exception {
297 checkNotNull(routerNode, JSON_NOT_NULL);
298 Map<RouterId, Router> subMap = new HashMap<RouterId, Router>();
299 if (!routerNode.hasNonNull("id")) {
300 new IllegalArgumentException("id should not be null");
301 } else if (routerNode.get("id").asText().isEmpty()) {
302 throw new IllegalArgumentException("id should not be empty");
303 }
304 RouterId id = RouterId.valueOf(routerNode.get("id").asText());
305
306 if (!routerNode.hasNonNull("tenant_id")) {
307 throw new IllegalArgumentException("tenant_id should not be null");
308 } else if (routerNode.get("tenant_id").asText().isEmpty()) {
309 throw new IllegalArgumentException("tenant_id should not be empty");
310 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800311 TenantId tenantId = TenantId
312 .tenantId(routerNode.get("tenant_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800313
314 VirtualPortId gwPortId = null;
315 if (routerNode.hasNonNull("gw_port_id")) {
lishuaid6f0c9e2015-12-16 11:40:01 +0800316 gwPortId = VirtualPortId
317 .portId(routerNode.get("gw_port_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800318 }
319
320 if (!routerNode.hasNonNull("status")) {
321 throw new IllegalArgumentException("status should not be null");
322 } else if (routerNode.get("status").asText().isEmpty()) {
323 throw new IllegalArgumentException("status should not be empty");
324 }
325 Status status = Status.valueOf(routerNode.get("status").asText());
326
327 String routerName = null;
328 if (routerNode.hasNonNull("name")) {
329 routerName = routerNode.get("name").asText();
330 }
331
332 boolean adminStateUp = true;
333 checkArgument(routerNode.get("admin_state_up").isBoolean(),
334 "admin_state_up should be boolean");
335 if (routerNode.hasNonNull("admin_state_up")) {
336 adminStateUp = routerNode.get("admin_state_up").asBoolean();
337 }
338 boolean distributed = false;
339 if (routerNode.hasNonNull("distributed")) {
340 distributed = routerNode.get("distributed").asBoolean();
341 }
342 RouterGateway gateway = null;
343 if (routerNode.hasNonNull("external_gateway_info")) {
lishuaid6f0c9e2015-12-16 11:40:01 +0800344 gateway = jsonNodeToGateway(routerNode
345 .get("external_gateway_info"));
346 }
347 List<String> routes = new ArrayList<String>();
348 DefaultRouter routerObj = new DefaultRouter(id, routerName,
349 adminStateUp, status,
350 distributed, gateway,
351 gwPortId, tenantId, routes);
352 subMap.put(id, routerObj);
353 return Collections.unmodifiableCollection(subMap.values());
354 }
355
356 /**
357 * Returns a collection of floatingIps from floatingIpNodes.
358 *
359 * @param subnode the router json node
360 * @param routerId the router identify
361 * @return routers a collection of router
362 * @throws Exception when any argument is illegal
363 */
364 public Collection<Router> changeUpdateJsonToSub(JsonNode subnode,
365 String routerId)
366 throws Exception {
367 checkNotNull(subnode, JSON_NOT_NULL);
368 checkNotNull(routerId, "routerId should not be null");
369 Map<RouterId, Router> subMap = new HashMap<RouterId, Router>();
370 JsonNode routerNode = subnode.get("router");
371 RouterId id = RouterId.valueOf(routerId);
372 Router sub = nullIsNotFound(get(RouterService.class).getRouter(id),
373 NOT_EXIST);
374 TenantId tenantId = sub.tenantId();
375
376 VirtualPortId gwPortId = null;
377 if (routerNode.hasNonNull("gw_port_id")) {
378 gwPortId = VirtualPortId
379 .portId(routerNode.get("gw_port_id").asText());
380 }
381 Status status = sub.status();
382
383 String routerName = routerNode.get("name").asText();
384
385 checkArgument(routerNode.get("admin_state_up").isBoolean(),
386 "admin_state_up should be boolean");
387 boolean adminStateUp = routerNode.get("admin_state_up").asBoolean();
388
389 boolean distributed = sub.distributed();
390 if (routerNode.hasNonNull("distributed")) {
391 distributed = routerNode.get("distributed").asBoolean();
392 }
393 RouterGateway gateway = sub.externalGatewayInfo();
394 if (routerNode.hasNonNull("external_gateway_info")) {
395 gateway = jsonNodeToGateway(routerNode
396 .get("external_gateway_info"));
jiangrui330b0c92015-11-28 14:09:50 +0800397 }
398 List<String> routes = new ArrayList<String>();
399 DefaultRouter routerObj = new DefaultRouter(id, routerName,
400 adminStateUp, status,
401 distributed, gateway,
402 gwPortId, tenantId, routes);
403 subMap.put(id, routerObj);
404 return Collections.unmodifiableCollection(subMap.values());
405 }
406
407 /**
408 * Changes JsonNode Gateway to the Gateway.
409 *
410 * @param gateway the gateway JsonNode
411 * @return gateway
412 */
413 private RouterGateway jsonNodeToGateway(JsonNode gateway) {
414 checkNotNull(gateway, JSON_NOT_NULL);
415 if (!gateway.hasNonNull("network_id")) {
416 throw new IllegalArgumentException("network_id should not be null");
417 } else if (gateway.get("network_id").asText().isEmpty()) {
418 throw new IllegalArgumentException("network_id should not be empty");
419 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800420 TenantNetworkId networkId = TenantNetworkId
421 .networkId(gateway.get("network_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800422
423 if (!gateway.hasNonNull("enable_snat")) {
424 throw new IllegalArgumentException("enable_snat should not be null");
425 } else if (gateway.get("enable_snat").asText().isEmpty()) {
426 throw new IllegalArgumentException("enable_snat should not be empty");
427 }
428 checkArgument(gateway.get("enable_snat").isBoolean(),
429 "enable_snat should be boolean");
430 boolean enableSnat = gateway.get("enable_snat").asBoolean();
431
432 if (!gateway.hasNonNull("external_fixed_ips")) {
lishuaid6f0c9e2015-12-16 11:40:01 +0800433 throw new IllegalArgumentException("external_fixed_ips should not be null");
jiangrui330b0c92015-11-28 14:09:50 +0800434 } else if (gateway.get("external_fixed_ips").isNull()) {
lishuaid6f0c9e2015-12-16 11:40:01 +0800435 throw new IllegalArgumentException("external_fixed_ips should not be empty");
jiangrui330b0c92015-11-28 14:09:50 +0800436 }
yuanyoue2ed3862016-05-06 13:18:08 +0800437 Iterable<FixedIp> fixedIpList = jsonNodeToFixedIp(gateway
jiangrui330b0c92015-11-28 14:09:50 +0800438 .get("external_fixed_ips"));
lishuaid6f0c9e2015-12-16 11:40:01 +0800439 RouterGateway gatewayObj = RouterGateway
yuanyoue2ed3862016-05-06 13:18:08 +0800440 .routerGateway(networkId, enableSnat, Sets.newHashSet(fixedIpList));
jiangrui330b0c92015-11-28 14:09:50 +0800441 return gatewayObj;
442 }
443
444 /**
445 * Changes JsonNode fixedIp to a collection of the fixedIp.
446 *
447 * @param fixedIp the allocationPools JsonNode
448 * @return a collection of fixedIp
449 */
yuanyoue2ed3862016-05-06 13:18:08 +0800450 private Iterable<FixedIp> jsonNodeToFixedIp(JsonNode fixedIp) {
jiangrui330b0c92015-11-28 14:09:50 +0800451 checkNotNull(fixedIp, JSON_NOT_NULL);
452 ConcurrentMap<Integer, FixedIp> fixedIpMaps = Maps.newConcurrentMap();
453 Integer i = 0;
454 for (JsonNode node : fixedIp) {
455 if (!node.hasNonNull("subnet_id")) {
456 throw new IllegalArgumentException("subnet_id should not be null");
457 } else if (node.get("subnet_id").asText().isEmpty()) {
458 throw new IllegalArgumentException("subnet_id should not be empty");
459 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800460 SubnetId subnetId = SubnetId
461 .subnetId(node.get("subnet_id").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800462 if (!node.hasNonNull("ip_address")) {
463 throw new IllegalArgumentException("ip_address should not be null");
464 } else if (node.get("ip_address").asText().isEmpty()) {
465 throw new IllegalArgumentException("ip_address should not be empty");
466 }
lishuaid6f0c9e2015-12-16 11:40:01 +0800467 IpAddress ipAddress = IpAddress
468 .valueOf(node.get("ip_address").asText());
jiangrui330b0c92015-11-28 14:09:50 +0800469 FixedIp fixedIpObj = FixedIp.fixedIp(subnetId, ipAddress);
470
471 fixedIpMaps.putIfAbsent(i, fixedIpObj);
472 i++;
473 }
474 return Collections.unmodifiableCollection(fixedIpMaps.values());
475 }
476
477 /**
478 * Returns the specified item if that items is null; otherwise throws not
479 * found exception.
480 *
481 * @param item item to check
482 * @param <T> item type
483 * @param message not found message
484 * @return item if not null
485 * @throws org.onlab.util.ItemNotFoundException if item is null
486 */
487 protected <T> T nullIsNotFound(T item, String message) {
488 if (item == null) {
489 throw new ItemNotFoundException(message);
490 }
491 return item;
492 }
493}