| /* |
| * 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.vtnweb.resources; |
| |
| import static com.google.common.base.Preconditions.checkArgument; |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static javax.ws.rs.core.Response.Status.BAD_REQUEST; |
| import static javax.ws.rs.core.Response.Status.CONFLICT; |
| import static javax.ws.rs.core.Response.Status.CREATED; |
| import static javax.ws.rs.core.Response.Status.NOT_FOUND; |
| import static javax.ws.rs.core.Response.Status.NO_CONTENT; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentMap; |
| |
| import javax.ws.rs.Consumes; |
| import javax.ws.rs.DELETE; |
| import javax.ws.rs.GET; |
| import javax.ws.rs.POST; |
| import javax.ws.rs.PUT; |
| import javax.ws.rs.Path; |
| import javax.ws.rs.PathParam; |
| import javax.ws.rs.Produces; |
| import javax.ws.rs.QueryParam; |
| import javax.ws.rs.core.MediaType; |
| import javax.ws.rs.core.Response; |
| |
| import org.onlab.packet.IpAddress; |
| import org.onlab.util.ItemNotFoundException; |
| import org.onosproject.rest.AbstractWebResource; |
| import org.onosproject.vtnrsc.DefaultRouter; |
| import org.onosproject.vtnrsc.FixedIp; |
| import org.onosproject.vtnrsc.Router; |
| import org.onosproject.vtnrsc.Router.Status; |
| import org.onosproject.vtnrsc.RouterGateway; |
| import org.onosproject.vtnrsc.RouterId; |
| import org.onosproject.vtnrsc.RouterInterface; |
| import org.onosproject.vtnrsc.SubnetId; |
| import org.onosproject.vtnrsc.TenantId; |
| import org.onosproject.vtnrsc.TenantNetworkId; |
| import org.onosproject.vtnrsc.VirtualPortId; |
| import org.onosproject.vtnrsc.router.RouterService; |
| import org.onosproject.vtnrsc.routerinterface.RouterInterfaceService; |
| import org.onosproject.vtnweb.web.RouterCodec; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.fasterxml.jackson.databind.JsonNode; |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import com.fasterxml.jackson.databind.node.ObjectNode; |
| import com.google.common.collect.Maps; |
| import com.google.common.collect.Sets; |
| |
| @Path("routers") |
| public class RouterWebResource extends AbstractWebResource { |
| private final Logger log = LoggerFactory.getLogger(RouterWebResource.class); |
| public static final String CREATE_FAIL = "Router is failed to create!"; |
| public static final String UPDATE_FAIL = "Router is failed to update!"; |
| public static final String GET_FAIL = "Router is failed to get!"; |
| public static final String NOT_EXIST = "Router does not exist!"; |
| public static final String DELETE_SUCCESS = "Router delete success!"; |
| public static final String JSON_NOT_NULL = "JsonNode can not be null"; |
| public static final String INTFACR_ADD_SUCCESS = "Interface add success"; |
| public static final String INTFACR_DEL_SUCCESS = "Interface delete success"; |
| |
| @GET |
| @Produces(MediaType.APPLICATION_JSON) |
| public Response listRouters() { |
| Collection<Router> routers = get(RouterService.class).getRouters(); |
| ObjectNode result = new ObjectMapper().createObjectNode(); |
| result.set("routers", new RouterCodec().encode(routers, this)); |
| return ok(result.toString()).build(); |
| } |
| |
| @GET |
| @Path("{routerUUID}") |
| @Produces(MediaType.APPLICATION_JSON) |
| public Response getRouter(@PathParam("routerUUID") String id, |
| @QueryParam("fields") List<String> fields) { |
| |
| if (!get(RouterService.class).exists(RouterId.valueOf(id))) { |
| return Response.status(NOT_FOUND) |
| .entity("The Router does not exists").build(); |
| } |
| Router sub = nullIsNotFound(get(RouterService.class) |
| .getRouter(RouterId.valueOf(id)), NOT_EXIST); |
| |
| ObjectNode result = new ObjectMapper().createObjectNode(); |
| if (fields.size() > 0) { |
| result.set("router", |
| new RouterCodec().extracFields(sub, this, fields)); |
| } else { |
| result.set("router", new RouterCodec().encode(sub, this)); |
| } |
| return ok(result.toString()).build(); |
| } |
| |
| @POST |
| @Produces(MediaType.APPLICATION_JSON) |
| @Consumes(MediaType.APPLICATION_JSON) |
| public Response createRouter(final InputStream input) { |
| try { |
| ObjectMapper mapper = new ObjectMapper(); |
| JsonNode subnode = mapper.readTree(input); |
| Collection<Router> routers = createOrUpdateByInputStream(subnode); |
| |
| Boolean result = nullIsNotFound((get(RouterService.class) |
| .createRouters(routers)), CREATE_FAIL); |
| if (!result) { |
| return Response.status(CONFLICT).entity(CREATE_FAIL).build(); |
| } |
| return Response.status(CREATED).entity(result.toString()).build(); |
| |
| } catch (Exception e) { |
| return Response.status(BAD_REQUEST).entity(e.getMessage()).build(); |
| } |
| } |
| |
| @PUT |
| @Path("{routerUUID}") |
| @Produces(MediaType.APPLICATION_JSON) |
| @Consumes(MediaType.APPLICATION_JSON) |
| public Response updateRouter(@PathParam("routerUUID") String id, |
| final InputStream input) { |
| try { |
| ObjectMapper mapper = new ObjectMapper(); |
| JsonNode subnode = mapper.readTree(input); |
| Collection<Router> routers = changeUpdateJsonToSub(subnode, id); |
| Boolean result = nullIsNotFound(get(RouterService.class) |
| .updateRouters(routers), UPDATE_FAIL); |
| if (!result) { |
| return Response.status(CONFLICT).entity(UPDATE_FAIL).build(); |
| } |
| return ok(result.toString()).build(); |
| } catch (Exception e) { |
| return Response.status(BAD_REQUEST).entity(e.getMessage()).build(); |
| } |
| } |
| |
| @DELETE |
| @Path("{routerUUID}") |
| @Consumes(MediaType.APPLICATION_JSON) |
| @Produces(MediaType.APPLICATION_JSON) |
| public Response deleteSingleRouter(@PathParam("routerUUID") String id) |
| throws IOException { |
| try { |
| RouterId routerId = RouterId.valueOf(id); |
| Set<RouterId> routerIds = Sets.newHashSet(routerId); |
| get(RouterService.class).removeRouters(routerIds); |
| return Response.status(NO_CONTENT).entity(DELETE_SUCCESS).build(); |
| } catch (Exception e) { |
| return Response.status(BAD_REQUEST).entity(e.getMessage()).build(); |
| } |
| } |
| |
| @PUT |
| @Path("{routerUUID}/add_router_interface") |
| @Produces(MediaType.APPLICATION_JSON) |
| @Consumes(MediaType.APPLICATION_JSON) |
| public Response addRouterInterface(@PathParam("routerUUID") String id, |
| final InputStream input) { |
| if (!get(RouterService.class).exists(RouterId.valueOf(id))) { |
| return Response.status(NOT_FOUND).entity(NOT_EXIST).build(); |
| } |
| try { |
| ObjectMapper mapper = new ObjectMapper(); |
| JsonNode subnode = mapper.readTree(input); |
| if (!subnode.hasNonNull("id")) { |
| throw new IllegalArgumentException("id should not be null"); |
| } else if (subnode.get("id").asText().isEmpty()) { |
| throw new IllegalArgumentException("id should not be empty"); |
| } |
| RouterId routerId = RouterId.valueOf(id); |
| if (!subnode.hasNonNull("subnet_id")) { |
| throw new IllegalArgumentException("subnet_id should not be null"); |
| } else if (subnode.get("subnet_id").asText().isEmpty()) { |
| throw new IllegalArgumentException("subnet_id should not be empty"); |
| } |
| SubnetId subnetId = SubnetId |
| .subnetId(subnode.get("subnet_id").asText()); |
| if (!subnode.hasNonNull("tenant_id")) { |
| throw new IllegalArgumentException("tenant_id should not be null"); |
| } else if (subnode.get("tenant_id").asText().isEmpty()) { |
| throw new IllegalArgumentException("tenant_id should not be empty"); |
| } |
| TenantId tenentId = TenantId |
| .tenantId(subnode.get("tenant_id").asText()); |
| if (!subnode.hasNonNull("port_id")) { |
| throw new IllegalArgumentException("port_id should not be null"); |
| } else if (subnode.get("port_id").asText().isEmpty()) { |
| throw new IllegalArgumentException("port_id should not be empty"); |
| } |
| VirtualPortId portId = VirtualPortId |
| .portId(subnode.get("port_id").asText()); |
| RouterInterface routerInterface = RouterInterface |
| .routerInterface(subnetId, portId, routerId, tenentId); |
| get(RouterInterfaceService.class) |
| .addRouterInterface(routerInterface); |
| return ok(INTFACR_ADD_SUCCESS).build(); |
| } catch (Exception e) { |
| return Response.status(BAD_REQUEST).entity(e.getMessage()).build(); |
| } |
| } |
| |
| @PUT |
| @Path("{routerUUID}/remove_router_interface") |
| @Produces(MediaType.APPLICATION_JSON) |
| @Consumes(MediaType.APPLICATION_JSON) |
| public Response removeRouterInterface(@PathParam("routerUUID") String id, |
| final InputStream input) { |
| if (!get(RouterService.class).exists(RouterId.valueOf(id))) { |
| return Response.status(NOT_FOUND).entity(NOT_EXIST).build(); |
| } |
| try { |
| ObjectMapper mapper = new ObjectMapper(); |
| JsonNode subnode = mapper.readTree(input); |
| if (!subnode.hasNonNull("id")) { |
| throw new IllegalArgumentException("id should not be null"); |
| } else if (subnode.get("id").asText().isEmpty()) { |
| throw new IllegalArgumentException("id should not be empty"); |
| } |
| RouterId routerId = RouterId.valueOf(id); |
| if (!subnode.hasNonNull("subnet_id")) { |
| throw new IllegalArgumentException("subnet_id should not be null"); |
| } else if (subnode.get("subnet_id").asText().isEmpty()) { |
| throw new IllegalArgumentException("subnet_id should not be empty"); |
| } |
| SubnetId subnetId = SubnetId |
| .subnetId(subnode.get("subnet_id").asText()); |
| if (!subnode.hasNonNull("port_id")) { |
| throw new IllegalArgumentException("port_id should not be null"); |
| } else if (subnode.get("port_id").asText().isEmpty()) { |
| throw new IllegalArgumentException("port_id should not be empty"); |
| } |
| VirtualPortId portId = VirtualPortId |
| .portId(subnode.get("port_id").asText()); |
| if (!subnode.hasNonNull("tenant_id")) { |
| throw new IllegalArgumentException("tenant_id should not be null"); |
| } else if (subnode.get("tenant_id").asText().isEmpty()) { |
| throw new IllegalArgumentException("tenant_id should not be empty"); |
| } |
| TenantId tenentId = TenantId |
| .tenantId(subnode.get("tenant_id").asText()); |
| RouterInterface routerInterface = RouterInterface |
| .routerInterface(subnetId, portId, routerId, tenentId); |
| get(RouterInterfaceService.class) |
| .removeRouterInterface(routerInterface); |
| return ok(INTFACR_DEL_SUCCESS).build(); |
| } catch (Exception e) { |
| return Response.status(BAD_REQUEST).entity(e.getMessage()).build(); |
| } |
| } |
| |
| private Collection<Router> createOrUpdateByInputStream(JsonNode subnode) |
| throws Exception { |
| checkNotNull(subnode, JSON_NOT_NULL); |
| JsonNode routerNode = subnode.get("routers"); |
| if (routerNode == null) { |
| routerNode = subnode.get("router"); |
| } |
| log.debug("routerNode is {}", routerNode.toString()); |
| |
| if (routerNode.isArray()) { |
| throw new Exception("only singleton requests allowed"); |
| } else { |
| return changeJsonToSub(routerNode); |
| } |
| } |
| |
| /** |
| * Returns a collection of floatingIps from floatingIpNodes. |
| * |
| * @param routerNode the router json node |
| * @return routers a collection of router |
| * @throws Exception when any argument is illegal |
| */ |
| public Collection<Router> changeJsonToSub(JsonNode routerNode) |
| throws Exception { |
| checkNotNull(routerNode, JSON_NOT_NULL); |
| Map<RouterId, Router> subMap = new HashMap<RouterId, Router>(); |
| if (!routerNode.hasNonNull("id")) { |
| new IllegalArgumentException("id should not be null"); |
| } else if (routerNode.get("id").asText().isEmpty()) { |
| throw new IllegalArgumentException("id should not be empty"); |
| } |
| RouterId id = RouterId.valueOf(routerNode.get("id").asText()); |
| |
| if (!routerNode.hasNonNull("tenant_id")) { |
| throw new IllegalArgumentException("tenant_id should not be null"); |
| } else if (routerNode.get("tenant_id").asText().isEmpty()) { |
| throw new IllegalArgumentException("tenant_id should not be empty"); |
| } |
| TenantId tenantId = TenantId |
| .tenantId(routerNode.get("tenant_id").asText()); |
| |
| VirtualPortId gwPortId = null; |
| if (routerNode.hasNonNull("gw_port_id")) { |
| gwPortId = VirtualPortId |
| .portId(routerNode.get("gw_port_id").asText()); |
| } |
| |
| if (!routerNode.hasNonNull("status")) { |
| throw new IllegalArgumentException("status should not be null"); |
| } else if (routerNode.get("status").asText().isEmpty()) { |
| throw new IllegalArgumentException("status should not be empty"); |
| } |
| Status status = Status.valueOf(routerNode.get("status").asText()); |
| |
| String routerName = null; |
| if (routerNode.hasNonNull("name")) { |
| routerName = routerNode.get("name").asText(); |
| } |
| |
| boolean adminStateUp = true; |
| checkArgument(routerNode.get("admin_state_up").isBoolean(), |
| "admin_state_up should be boolean"); |
| if (routerNode.hasNonNull("admin_state_up")) { |
| adminStateUp = routerNode.get("admin_state_up").asBoolean(); |
| } |
| boolean distributed = false; |
| if (routerNode.hasNonNull("distributed")) { |
| distributed = routerNode.get("distributed").asBoolean(); |
| } |
| RouterGateway gateway = null; |
| if (routerNode.hasNonNull("external_gateway_info")) { |
| gateway = jsonNodeToGateway(routerNode |
| .get("external_gateway_info")); |
| } |
| List<String> routes = new ArrayList<String>(); |
| DefaultRouter routerObj = new DefaultRouter(id, routerName, |
| adminStateUp, status, |
| distributed, gateway, |
| gwPortId, tenantId, routes); |
| subMap.put(id, routerObj); |
| return Collections.unmodifiableCollection(subMap.values()); |
| } |
| |
| /** |
| * Returns a collection of floatingIps from floatingIpNodes. |
| * |
| * @param subnode the router json node |
| * @param routerId the router identify |
| * @return routers a collection of router |
| * @throws Exception when any argument is illegal |
| */ |
| public Collection<Router> changeUpdateJsonToSub(JsonNode subnode, |
| String routerId) |
| throws Exception { |
| checkNotNull(subnode, JSON_NOT_NULL); |
| checkNotNull(routerId, "routerId should not be null"); |
| Map<RouterId, Router> subMap = new HashMap<RouterId, Router>(); |
| JsonNode routerNode = subnode.get("router"); |
| RouterId id = RouterId.valueOf(routerId); |
| Router sub = nullIsNotFound(get(RouterService.class).getRouter(id), |
| NOT_EXIST); |
| TenantId tenantId = sub.tenantId(); |
| |
| VirtualPortId gwPortId = null; |
| if (routerNode.hasNonNull("gw_port_id")) { |
| gwPortId = VirtualPortId |
| .portId(routerNode.get("gw_port_id").asText()); |
| } |
| Status status = sub.status(); |
| |
| String routerName = routerNode.get("name").asText(); |
| |
| checkArgument(routerNode.get("admin_state_up").isBoolean(), |
| "admin_state_up should be boolean"); |
| boolean adminStateUp = routerNode.get("admin_state_up").asBoolean(); |
| |
| boolean distributed = sub.distributed(); |
| if (routerNode.hasNonNull("distributed")) { |
| distributed = routerNode.get("distributed").asBoolean(); |
| } |
| RouterGateway gateway = sub.externalGatewayInfo(); |
| if (routerNode.hasNonNull("external_gateway_info")) { |
| gateway = jsonNodeToGateway(routerNode |
| .get("external_gateway_info")); |
| } |
| List<String> routes = new ArrayList<String>(); |
| DefaultRouter routerObj = new DefaultRouter(id, routerName, |
| adminStateUp, status, |
| distributed, gateway, |
| gwPortId, tenantId, routes); |
| subMap.put(id, routerObj); |
| return Collections.unmodifiableCollection(subMap.values()); |
| } |
| |
| /** |
| * Changes JsonNode Gateway to the Gateway. |
| * |
| * @param gateway the gateway JsonNode |
| * @return gateway |
| */ |
| private RouterGateway jsonNodeToGateway(JsonNode gateway) { |
| checkNotNull(gateway, JSON_NOT_NULL); |
| if (!gateway.hasNonNull("network_id")) { |
| throw new IllegalArgumentException("network_id should not be null"); |
| } else if (gateway.get("network_id").asText().isEmpty()) { |
| throw new IllegalArgumentException("network_id should not be empty"); |
| } |
| TenantNetworkId networkId = TenantNetworkId |
| .networkId(gateway.get("network_id").asText()); |
| |
| if (!gateway.hasNonNull("enable_snat")) { |
| throw new IllegalArgumentException("enable_snat should not be null"); |
| } else if (gateway.get("enable_snat").asText().isEmpty()) { |
| throw new IllegalArgumentException("enable_snat should not be empty"); |
| } |
| checkArgument(gateway.get("enable_snat").isBoolean(), |
| "enable_snat should be boolean"); |
| boolean enableSnat = gateway.get("enable_snat").asBoolean(); |
| |
| if (!gateway.hasNonNull("external_fixed_ips")) { |
| throw new IllegalArgumentException("external_fixed_ips should not be null"); |
| } else if (gateway.get("external_fixed_ips").isNull()) { |
| throw new IllegalArgumentException("external_fixed_ips should not be empty"); |
| } |
| Iterable<FixedIp> fixedIpList = jsonNodeToFixedIp(gateway |
| .get("external_fixed_ips")); |
| RouterGateway gatewayObj = RouterGateway |
| .routerGateway(networkId, enableSnat, Sets.newHashSet(fixedIpList)); |
| return gatewayObj; |
| } |
| |
| /** |
| * Changes JsonNode fixedIp to a collection of the fixedIp. |
| * |
| * @param fixedIp the allocationPools JsonNode |
| * @return a collection of fixedIp |
| */ |
| private Iterable<FixedIp> jsonNodeToFixedIp(JsonNode fixedIp) { |
| checkNotNull(fixedIp, JSON_NOT_NULL); |
| ConcurrentMap<Integer, FixedIp> fixedIpMaps = Maps.newConcurrentMap(); |
| Integer i = 0; |
| for (JsonNode node : fixedIp) { |
| if (!node.hasNonNull("subnet_id")) { |
| throw new IllegalArgumentException("subnet_id should not be null"); |
| } else if (node.get("subnet_id").asText().isEmpty()) { |
| throw new IllegalArgumentException("subnet_id should not be empty"); |
| } |
| SubnetId subnetId = SubnetId |
| .subnetId(node.get("subnet_id").asText()); |
| if (!node.hasNonNull("ip_address")) { |
| throw new IllegalArgumentException("ip_address should not be null"); |
| } else if (node.get("ip_address").asText().isEmpty()) { |
| throw new IllegalArgumentException("ip_address should not be empty"); |
| } |
| IpAddress ipAddress = IpAddress |
| .valueOf(node.get("ip_address").asText()); |
| FixedIp fixedIpObj = FixedIp.fixedIp(subnetId, ipAddress); |
| |
| fixedIpMaps.putIfAbsent(i, fixedIpObj); |
| i++; |
| } |
| return Collections.unmodifiableCollection(fixedIpMaps.values()); |
| } |
| |
| /** |
| * Returns the specified item if that items is null; otherwise throws not |
| * found exception. |
| * |
| * @param item item to check |
| * @param <T> item type |
| * @param message not found message |
| * @return item if not null |
| * @throws org.onlab.util.ItemNotFoundException if item is null |
| */ |
| protected <T> T nullIsNotFound(T item, String message) { |
| if (item == null) { |
| throw new ItemNotFoundException(message); |
| } |
| return item; |
| } |
| } |