2 * Copyright 2015 Open Networking Laboratory
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org.onosproject.vtnweb.resources;
18 import static com.google.common.base.Preconditions.checkArgument;
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
21 import static javax.ws.rs.core.Response.Status.NOT_FOUND;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.HashSet;
30 import java.util.concurrent.ConcurrentMap;
32 import javax.ws.rs.Consumes;
33 import javax.ws.rs.DELETE;
34 import javax.ws.rs.GET;
35 import javax.ws.rs.POST;
36 import javax.ws.rs.PUT;
37 import javax.ws.rs.Path;
38 import javax.ws.rs.PathParam;
39 import javax.ws.rs.Produces;
40 import javax.ws.rs.core.MediaType;
41 import javax.ws.rs.core.Response;
43 import org.onlab.packet.IpAddress;
44 import org.onlab.packet.IpAddress.Version;
45 import org.onlab.packet.IpPrefix;
46 import org.onlab.util.ItemNotFoundException;
47 import org.onosproject.rest.AbstractWebResource;
48 import org.onosproject.vtnrsc.AllocationPool;
49 import org.onosproject.vtnrsc.DefaultAllocationPool;
50 import org.onosproject.vtnrsc.DefaultHostRoute;
51 import org.onosproject.vtnrsc.DefaultSubnet;
52 import org.onosproject.vtnrsc.HostRoute;
53 import org.onosproject.vtnrsc.Subnet;
54 import org.onosproject.vtnrsc.SubnetId;
55 import org.onosproject.vtnrsc.TenantId;
56 import org.onosproject.vtnrsc.TenantNetworkId;
57 import org.onosproject.vtnrsc.Subnet.Mode;
58 import org.onosproject.vtnrsc.subnet.SubnetService;
59 import org.onosproject.vtnrsc.web.SubnetCodec;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
63 import com.fasterxml.jackson.databind.JsonNode;
64 import com.fasterxml.jackson.databind.ObjectMapper;
65 import com.fasterxml.jackson.databind.node.ObjectNode;
66 import com.google.common.collect.Maps;
67 import com.google.common.collect.Sets;
70 public class SubnetWebResource extends AbstractWebResource {
71 private final Logger log = LoggerFactory.getLogger(SubnetWebResource.class);
72 public static final String SUBNET_NOT_CREATED = "Subnet failed to create!";
73 public static final String SUBNET_NOT_FOUND = "Subnet is not found";
74 public static final String JSON_NOT_NULL = "JsonNode can not be null";
77 @Produces(MediaType.APPLICATION_JSON)
78 public Response listSubnets() {
79 Iterable<Subnet> subnets = get(SubnetService.class).getSubnets();
80 ObjectNode result = new ObjectMapper().createObjectNode();
81 result.set("subnets", new SubnetCodec().encode(subnets, this));
82 return ok(result.toString()).build();
87 @Produces(MediaType.APPLICATION_JSON)
88 public Response getSubnet(@PathParam("subnetUUID") String id) {
90 if (!get(SubnetService.class).exists(SubnetId.subnetId(id))) {
91 return Response.status(NOT_FOUND)
92 .entity(SUBNET_NOT_FOUND).build();
94 Subnet sub = nullIsNotFound(get(SubnetService.class)
95 .getSubnet(SubnetId.subnetId(id)),
98 ObjectNode result = new ObjectMapper().createObjectNode();
99 result.set("subnet", new SubnetCodec().encode(sub, this));
100 return ok(result.toString()).build();
104 @Produces(MediaType.APPLICATION_JSON)
105 @Consumes(MediaType.APPLICATION_JSON)
106 public Response createSubnet(final InputStream input) {
109 ObjectMapper mapper = new ObjectMapper();
110 JsonNode subnode = mapper.readTree(input);
111 Iterable<Subnet> subnets = createOrUpdateByInputStream(subnode);
112 Boolean result = nullIsNotFound((get(SubnetService.class)
113 .createSubnets(subnets)),
117 return Response.status(INTERNAL_SERVER_ERROR)
118 .entity(SUBNET_NOT_CREATED).build();
120 return Response.status(202).entity(result.toString()).build();
121 } catch (Exception e) {
122 return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
128 @Path("{subnetUUID}")
129 @Produces(MediaType.APPLICATION_JSON)
130 @Consumes(MediaType.APPLICATION_JSON)
131 public Response updateSubnet(@PathParam("id") String id,
132 final InputStream input) {
134 ObjectMapper mapper = new ObjectMapper();
135 JsonNode subnode = mapper.readTree(input);
136 Iterable<Subnet> subnets = createOrUpdateByInputStream(subnode);
137 Boolean result = nullIsNotFound(get(SubnetService.class)
138 .updateSubnets(subnets), SUBNET_NOT_FOUND);
140 return Response.status(INTERNAL_SERVER_ERROR)
141 .entity(SUBNET_NOT_FOUND).build();
143 return Response.status(203).entity(result.toString()).build();
144 } catch (Exception e) {
145 return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
150 @Path("{subnetUUID}")
152 public Response deleteSingleSubnet(@PathParam("subnetUUID") String id)
155 SubnetId subId = SubnetId.subnetId(id);
156 Set<SubnetId> subIds = new HashSet<>();
158 get(SubnetService.class).removeSubnets(subIds);
159 return Response.status(201).entity("SUCCESS").build();
160 } catch (Exception e) {
161 return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
166 private Iterable<Subnet> createOrUpdateByInputStream(JsonNode subnode) {
167 checkNotNull(subnode, JSON_NOT_NULL);
168 Iterable<Subnet> subnets = null;
169 JsonNode subnetNodes = subnode.get("subnets");
170 if (subnetNodes == null) {
171 subnetNodes = subnode.get("subnet");
173 log.debug("subnetNodes is {}", subnetNodes.toString());
174 if (subnetNodes.isArray()) {
175 subnets = changeJsonToSubs(subnetNodes);
177 subnets = changeJsonToSub(subnetNodes);
183 * Returns a collection of subnets from subnetNodes.
185 * @param subnetNodes the subnet json node
186 * @return subnets a collection of subnets
188 public Iterable<Subnet> changeJsonToSubs(JsonNode subnetNodes) {
189 checkNotNull(subnetNodes, JSON_NOT_NULL);
190 Map<SubnetId, Subnet> subMap = new HashMap<>();
191 for (JsonNode subnetNode : subnetNodes) {
192 if (!subnetNode.hasNonNull("id")) {
195 SubnetId id = SubnetId.subnetId(subnetNode.get("id").asText());
196 String subnetName = subnetNode.get("name").asText();
197 TenantId tenantId = TenantId
198 .tenantId(subnetNode.get("tenant_id").asText());
199 TenantNetworkId networkId = TenantNetworkId
200 .networkId(subnetNode.get("network_id").asText());
201 String version = subnetNode.get("ip_version").asText();
205 ipVersion = Version.INET;
208 ipVersion = Version.INET;
211 throw new IllegalArgumentException("ipVersion should be 4 or 6.");
213 IpPrefix cidr = IpPrefix.valueOf(subnetNode.get("cidr").asText());
214 IpAddress gatewayIp = IpAddress
215 .valueOf(subnetNode.get("gateway_ip").asText());
216 Boolean dhcpEnabled = subnetNode.get("enable_dhcp").asBoolean();
217 Boolean shared = subnetNode.get("shared").asBoolean();
218 JsonNode hostRoutes = subnetNode.get("host_routes");
219 Iterable<HostRoute> hostRoutesIt = jsonNodeToHostRoutes(hostRoutes);
220 JsonNode allocationPools = subnetNode.get("allocation_pools");
221 Iterable<AllocationPool> allocationPoolsIt = jsonNodeToAllocationPools(allocationPools);
222 Mode ipV6AddressMode = Mode
223 .valueOf(subnetNode.get("ipv6_address_mode").asText());
224 Mode ipV6RaMode = Mode
225 .valueOf(subnetNode.get("ipv6_ra_mode").asText());
226 Subnet subnet = new DefaultSubnet(id, subnetName, networkId,
227 tenantId, ipVersion, cidr,
228 gatewayIp, dhcpEnabled, shared,
229 Sets.newHashSet(hostRoutesIt), ipV6AddressMode,
230 ipV6RaMode, Sets.newHashSet(allocationPoolsIt));
231 subMap.put(id, subnet);
233 return Collections.unmodifiableCollection(subMap.values());
237 * Returns a collection of subnets from subnetNodes.
239 * @param subnetNodes the subnet json node
240 * @return subnets a collection of subnets
242 public Iterable<Subnet> changeJsonToSub(JsonNode subnetNodes) {
243 checkNotNull(subnetNodes, JSON_NOT_NULL);
244 checkArgument(subnetNodes.get("enable_dhcp").isBoolean(), "enable_dhcp should be boolean");
245 checkArgument(subnetNodes.get("shared").isBoolean(), "shared should be boolean");
246 Map<SubnetId, Subnet> subMap = new HashMap<>();
247 if (!subnetNodes.hasNonNull("id")) {
250 SubnetId id = SubnetId.subnetId(subnetNodes.get("id").asText());
251 String subnetName = subnetNodes.get("name").asText();
252 TenantId tenantId = TenantId
253 .tenantId(subnetNodes.get("tenant_id").asText());
254 TenantNetworkId networkId = TenantNetworkId
255 .networkId(subnetNodes.get("network_id").asText());
256 String version = subnetNodes.get("ip_version").asText();
260 ipVersion = Version.INET;
263 ipVersion = Version.INET;
266 throw new IllegalArgumentException("ipVersion should be 4 or 6.");
269 IpPrefix cidr = IpPrefix.valueOf(subnetNodes.get("cidr").asText());
270 IpAddress gatewayIp = IpAddress
271 .valueOf(subnetNodes.get("gateway_ip").asText());
272 Boolean dhcpEnabled = subnetNodes.get("enable_dhcp").asBoolean();
273 Boolean shared = subnetNodes.get("shared").asBoolean();
274 JsonNode hostRoutes = subnetNodes.get("host_routes");
275 Iterable<HostRoute> hostRoutesIt = jsonNodeToHostRoutes(hostRoutes);
276 JsonNode allocationPools = subnetNodes.get("allocation_pools");
277 Iterable<AllocationPool> allocationPoolsIt = jsonNodeToAllocationPools(allocationPools);
279 Mode ipV6AddressMode = getMode(subnetNodes.get("ipv6_address_mode")
281 Mode ipV6RaMode = getMode(subnetNodes.get("ipv6_ra_mode").asText());
283 Subnet subnet = new DefaultSubnet(id, subnetName, networkId, tenantId,
284 ipVersion, cidr, gatewayIp,
285 dhcpEnabled, shared, Sets.newHashSet(hostRoutesIt),
286 ipV6AddressMode, ipV6RaMode,
287 Sets.newHashSet(allocationPoolsIt));
288 subMap.put(id, subnet);
289 return Collections.unmodifiableCollection(subMap.values());
293 * Gets ipv6_address_mode or ipv6_ra_mode type.
295 * @param mode the String value in JsonNode
296 * @return ipV6Mode Mode of the ipV6Mode
298 private Mode getMode(String mode) {
304 case "dhcpv6-stateful":
305 ipV6Mode = Mode.DHCPV6_STATEFUL;
307 case "dhcpv6-stateless":
308 ipV6Mode = Mode.DHCPV6_STATELESS;
311 ipV6Mode = Mode.SLAAC;
320 * Changes JsonNode alocPools to a collection of the alocPools.
322 * @param allocationPools the allocationPools JsonNode
323 * @return a collection of allocationPools
325 public Iterable<AllocationPool> jsonNodeToAllocationPools(JsonNode allocationPools) {
326 checkNotNull(allocationPools, JSON_NOT_NULL);
327 ConcurrentMap<Integer, AllocationPool> alocplMaps = Maps
330 for (JsonNode node : allocationPools) {
331 IpAddress startIp = IpAddress.valueOf(node.get("start").asText());
332 IpAddress endIp = IpAddress.valueOf(node.get("end").asText());
333 AllocationPool alocPls = new DefaultAllocationPool(startIp, endIp);
334 alocplMaps.putIfAbsent(i, alocPls);
337 return Collections.unmodifiableCollection(alocplMaps.values());
341 * Changes hostRoutes JsonNode to a collection of the hostRoutes.
343 * @param hostRoutes the hostRoutes json node
344 * @return a collection of hostRoutes
346 public Iterable<HostRoute> jsonNodeToHostRoutes(JsonNode hostRoutes) {
347 checkNotNull(hostRoutes, JSON_NOT_NULL);
348 ConcurrentMap<Integer, HostRoute> hostRouteMaps = Maps
351 for (JsonNode node : hostRoutes) {
352 IpAddress nexthop = IpAddress.valueOf(node.get("nexthop").asText());
353 IpPrefix destination = IpPrefix.valueOf(node.get("destination")
355 HostRoute hostRoute = new DefaultHostRoute(nexthop, destination);
356 hostRouteMaps.putIfAbsent(i, hostRoute);
359 return Collections.unmodifiableCollection(hostRouteMaps.values());
363 * Returns the specified item if that items is null; otherwise throws not
366 * @param item item to check
367 * @param <T> item type
368 * @param message not found message
369 * @return item if not null
370 * @throws org.onlab.util.ItemNotFoundException if item is null
372 protected <T> T nullIsNotFound(T item, String message) {
374 throw new ItemNotFoundException(message);