blob: 2d122d71530049868dbd5b910fabde3647e1f29e [file] [log] [blame]
Madan Jampani38a88212015-09-15 11:21:27 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Madan Jampani38a88212015-09-15 11:21:27 -07003 *
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
18import static com.google.common.base.Preconditions.checkArgument;
19import static com.google.common.base.Preconditions.checkNotNull;
20import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
lishuai0f47f342015-09-16 11:38:48 +080021import static javax.ws.rs.core.Response.Status.NOT_FOUND;
Madan Jampani38a88212015-09-15 11:21:27 -070022
23import java.io.IOException;
24import java.io.InputStream;
25import java.util.Collections;
26import java.util.HashMap;
27import java.util.HashSet;
28import java.util.Map;
29import java.util.Set;
30import java.util.concurrent.ConcurrentMap;
31
32import javax.ws.rs.Consumes;
33import javax.ws.rs.DELETE;
34import javax.ws.rs.GET;
35import javax.ws.rs.POST;
36import javax.ws.rs.PUT;
37import javax.ws.rs.Path;
38import javax.ws.rs.PathParam;
39import javax.ws.rs.Produces;
40import javax.ws.rs.core.MediaType;
41import javax.ws.rs.core.Response;
42
43import org.onlab.packet.IpAddress;
44import org.onlab.packet.IpAddress.Version;
45import org.onlab.packet.IpPrefix;
46import org.onlab.util.ItemNotFoundException;
47import org.onosproject.rest.AbstractWebResource;
48import org.onosproject.vtnrsc.AllocationPool;
49import org.onosproject.vtnrsc.DefaultAllocationPool;
50import org.onosproject.vtnrsc.DefaultHostRoute;
51import org.onosproject.vtnrsc.DefaultSubnet;
52import org.onosproject.vtnrsc.HostRoute;
53import org.onosproject.vtnrsc.Subnet;
54import org.onosproject.vtnrsc.SubnetId;
55import org.onosproject.vtnrsc.TenantId;
56import org.onosproject.vtnrsc.TenantNetworkId;
57import org.onosproject.vtnrsc.Subnet.Mode;
58import org.onosproject.vtnrsc.subnet.SubnetService;
onosjcc36e04a82015-10-27 16:46:37 +080059import org.onosproject.vtnweb.web.SubnetCodec;
Madan Jampani38a88212015-09-15 11:21:27 -070060import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62
63import com.fasterxml.jackson.databind.JsonNode;
64import com.fasterxml.jackson.databind.ObjectMapper;
65import com.fasterxml.jackson.databind.node.ObjectNode;
66import com.google.common.collect.Maps;
67import com.google.common.collect.Sets;
68
69@Path("subnets")
70public class SubnetWebResource extends AbstractWebResource {
71 private final Logger log = LoggerFactory.getLogger(SubnetWebResource.class);
bobzhouf8da9652015-10-14 11:23:18 +080072 public static final String SUBNET_NOT_CREATED = "Subnet failed to create!";
73 public static final String SUBNET_NOT_FOUND = "Subnet is not found";
Madan Jampani38a88212015-09-15 11:21:27 -070074 public static final String JSON_NOT_NULL = "JsonNode can not be null";
75
76 @GET
77 @Produces(MediaType.APPLICATION_JSON)
Wu wenbind0b119f2016-05-11 18:03:41 +080078 @Consumes(MediaType.APPLICATION_JSON)
Madan Jampani38a88212015-09-15 11:21:27 -070079 public Response listSubnets() {
80 Iterable<Subnet> subnets = get(SubnetService.class).getSubnets();
81 ObjectNode result = new ObjectMapper().createObjectNode();
82 result.set("subnets", new SubnetCodec().encode(subnets, this));
83 return ok(result.toString()).build();
84 }
85
86 @GET
87 @Path("{subnetUUID}")
88 @Produces(MediaType.APPLICATION_JSON)
Wu wenbind0b119f2016-05-11 18:03:41 +080089 @Consumes(MediaType.APPLICATION_JSON)
Madan Jampani38a88212015-09-15 11:21:27 -070090 public Response getSubnet(@PathParam("subnetUUID") String id) {
91
92 if (!get(SubnetService.class).exists(SubnetId.subnetId(id))) {
lishuai0f47f342015-09-16 11:38:48 +080093 return Response.status(NOT_FOUND)
94 .entity(SUBNET_NOT_FOUND).build();
Madan Jampani38a88212015-09-15 11:21:27 -070095 }
96 Subnet sub = nullIsNotFound(get(SubnetService.class)
97 .getSubnet(SubnetId.subnetId(id)),
98 SUBNET_NOT_FOUND);
99
100 ObjectNode result = new ObjectMapper().createObjectNode();
101 result.set("subnet", new SubnetCodec().encode(sub, this));
102 return ok(result.toString()).build();
103 }
104
105 @POST
106 @Produces(MediaType.APPLICATION_JSON)
107 @Consumes(MediaType.APPLICATION_JSON)
108 public Response createSubnet(final InputStream input) {
109
110 try {
111 ObjectMapper mapper = new ObjectMapper();
112 JsonNode subnode = mapper.readTree(input);
113 Iterable<Subnet> subnets = createOrUpdateByInputStream(subnode);
114 Boolean result = nullIsNotFound((get(SubnetService.class)
115 .createSubnets(subnets)),
bobzhouf8da9652015-10-14 11:23:18 +0800116 SUBNET_NOT_CREATED);
Madan Jampani38a88212015-09-15 11:21:27 -0700117
118 if (!result) {
lishuai0f47f342015-09-16 11:38:48 +0800119 return Response.status(INTERNAL_SERVER_ERROR)
bobzhouf8da9652015-10-14 11:23:18 +0800120 .entity(SUBNET_NOT_CREATED).build();
Madan Jampani38a88212015-09-15 11:21:27 -0700121 }
122 return Response.status(202).entity(result.toString()).build();
123 } catch (Exception e) {
124 return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
125 .build();
126 }
127 }
128
129 @PUT
130 @Path("{subnetUUID}")
131 @Produces(MediaType.APPLICATION_JSON)
132 @Consumes(MediaType.APPLICATION_JSON)
133 public Response updateSubnet(@PathParam("id") String id,
134 final InputStream input) {
135 try {
136 ObjectMapper mapper = new ObjectMapper();
137 JsonNode subnode = mapper.readTree(input);
138 Iterable<Subnet> subnets = createOrUpdateByInputStream(subnode);
139 Boolean result = nullIsNotFound(get(SubnetService.class)
140 .updateSubnets(subnets), SUBNET_NOT_FOUND);
141 if (!result) {
lishuai0f47f342015-09-16 11:38:48 +0800142 return Response.status(INTERNAL_SERVER_ERROR)
143 .entity(SUBNET_NOT_FOUND).build();
Madan Jampani38a88212015-09-15 11:21:27 -0700144 }
145 return Response.status(203).entity(result.toString()).build();
146 } catch (Exception e) {
147 return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
148 .build();
149 }
150 }
151
Madan Jampani38a88212015-09-15 11:21:27 -0700152 @DELETE
Wu wenbinb0bd6132016-05-10 19:20:23 +0800153 @Path("{subnetUUID}")
154 @Consumes(MediaType.APPLICATION_JSON)
155 @Produces(MediaType.APPLICATION_JSON)
Madan Jampani38a88212015-09-15 11:21:27 -0700156 public Response deleteSingleSubnet(@PathParam("subnetUUID") String id)
157 throws IOException {
158 try {
159 SubnetId subId = SubnetId.subnetId(id);
160 Set<SubnetId> subIds = new HashSet<>();
161 subIds.add(subId);
162 get(SubnetService.class).removeSubnets(subIds);
Jian Lic2a542b2016-05-10 11:48:19 -0700163 return Response.noContent().entity("SUCCESS").build();
Madan Jampani38a88212015-09-15 11:21:27 -0700164 } catch (Exception e) {
165 return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
166 .build();
167 }
168 }
169
170 private Iterable<Subnet> createOrUpdateByInputStream(JsonNode subnode) {
171 checkNotNull(subnode, JSON_NOT_NULL);
172 Iterable<Subnet> subnets = null;
173 JsonNode subnetNodes = subnode.get("subnets");
174 if (subnetNodes == null) {
175 subnetNodes = subnode.get("subnet");
176 }
177 log.debug("subnetNodes is {}", subnetNodes.toString());
178 if (subnetNodes.isArray()) {
179 subnets = changeJsonToSubs(subnetNodes);
180 } else {
181 subnets = changeJsonToSub(subnetNodes);
182 }
183 return subnets;
184 }
185
186 /**
187 * Returns a collection of subnets from subnetNodes.
188 *
189 * @param subnetNodes the subnet json node
190 * @return subnets a collection of subnets
191 */
192 public Iterable<Subnet> changeJsonToSubs(JsonNode subnetNodes) {
193 checkNotNull(subnetNodes, JSON_NOT_NULL);
194 Map<SubnetId, Subnet> subMap = new HashMap<>();
195 for (JsonNode subnetNode : subnetNodes) {
196 if (!subnetNode.hasNonNull("id")) {
197 return null;
198 }
199 SubnetId id = SubnetId.subnetId(subnetNode.get("id").asText());
200 String subnetName = subnetNode.get("name").asText();
201 TenantId tenantId = TenantId
202 .tenantId(subnetNode.get("tenant_id").asText());
203 TenantNetworkId networkId = TenantNetworkId
204 .networkId(subnetNode.get("network_id").asText());
lishuai0f47f342015-09-16 11:38:48 +0800205 String version = subnetNode.get("ip_version").asText();
206 Version ipVersion;
207 switch (version) {
208 case "4":
209 ipVersion = Version.INET;
210 break;
211 case "6":
212 ipVersion = Version.INET;
213 break;
214 default:
215 throw new IllegalArgumentException("ipVersion should be 4 or 6.");
216 }
Madan Jampani38a88212015-09-15 11:21:27 -0700217 IpPrefix cidr = IpPrefix.valueOf(subnetNode.get("cidr").asText());
218 IpAddress gatewayIp = IpAddress
219 .valueOf(subnetNode.get("gateway_ip").asText());
220 Boolean dhcpEnabled = subnetNode.get("enable_dhcp").asBoolean();
221 Boolean shared = subnetNode.get("shared").asBoolean();
222 JsonNode hostRoutes = subnetNode.get("host_routes");
223 Iterable<HostRoute> hostRoutesIt = jsonNodeToHostRoutes(hostRoutes);
224 JsonNode allocationPools = subnetNode.get("allocation_pools");
225 Iterable<AllocationPool> allocationPoolsIt = jsonNodeToAllocationPools(allocationPools);
226 Mode ipV6AddressMode = Mode
227 .valueOf(subnetNode.get("ipv6_address_mode").asText());
228 Mode ipV6RaMode = Mode
229 .valueOf(subnetNode.get("ipv6_ra_mode").asText());
230 Subnet subnet = new DefaultSubnet(id, subnetName, networkId,
231 tenantId, ipVersion, cidr,
232 gatewayIp, dhcpEnabled, shared,
233 Sets.newHashSet(hostRoutesIt), ipV6AddressMode,
234 ipV6RaMode, Sets.newHashSet(allocationPoolsIt));
235 subMap.put(id, subnet);
236 }
237 return Collections.unmodifiableCollection(subMap.values());
238 }
239
240 /**
241 * Returns a collection of subnets from subnetNodes.
242 *
243 * @param subnetNodes the subnet json node
244 * @return subnets a collection of subnets
245 */
246 public Iterable<Subnet> changeJsonToSub(JsonNode subnetNodes) {
247 checkNotNull(subnetNodes, JSON_NOT_NULL);
248 checkArgument(subnetNodes.get("enable_dhcp").isBoolean(), "enable_dhcp should be boolean");
249 checkArgument(subnetNodes.get("shared").isBoolean(), "shared should be boolean");
250 Map<SubnetId, Subnet> subMap = new HashMap<>();
251 if (!subnetNodes.hasNonNull("id")) {
252 return null;
253 }
254 SubnetId id = SubnetId.subnetId(subnetNodes.get("id").asText());
255 String subnetName = subnetNodes.get("name").asText();
256 TenantId tenantId = TenantId
257 .tenantId(subnetNodes.get("tenant_id").asText());
258 TenantNetworkId networkId = TenantNetworkId
259 .networkId(subnetNodes.get("network_id").asText());
260 String version = subnetNodes.get("ip_version").asText();
261 Version ipVersion;
262 switch (version) {
263 case "4":
264 ipVersion = Version.INET;
265 break;
266 case "6":
267 ipVersion = Version.INET;
268 break;
269 default:
270 throw new IllegalArgumentException("ipVersion should be 4 or 6.");
271 }
272
273 IpPrefix cidr = IpPrefix.valueOf(subnetNodes.get("cidr").asText());
274 IpAddress gatewayIp = IpAddress
275 .valueOf(subnetNodes.get("gateway_ip").asText());
276 Boolean dhcpEnabled = subnetNodes.get("enable_dhcp").asBoolean();
277 Boolean shared = subnetNodes.get("shared").asBoolean();
278 JsonNode hostRoutes = subnetNodes.get("host_routes");
279 Iterable<HostRoute> hostRoutesIt = jsonNodeToHostRoutes(hostRoutes);
280 JsonNode allocationPools = subnetNodes.get("allocation_pools");
281 Iterable<AllocationPool> allocationPoolsIt = jsonNodeToAllocationPools(allocationPools);
282
283 Mode ipV6AddressMode = getMode(subnetNodes.get("ipv6_address_mode")
284 .asText());
285 Mode ipV6RaMode = getMode(subnetNodes.get("ipv6_ra_mode").asText());
286
287 Subnet subnet = new DefaultSubnet(id, subnetName, networkId, tenantId,
288 ipVersion, cidr, gatewayIp,
289 dhcpEnabled, shared, Sets.newHashSet(hostRoutesIt),
290 ipV6AddressMode, ipV6RaMode,
291 Sets.newHashSet(allocationPoolsIt));
292 subMap.put(id, subnet);
293 return Collections.unmodifiableCollection(subMap.values());
294 }
295
296 /**
297 * Gets ipv6_address_mode or ipv6_ra_mode type.
298 *
299 * @param mode the String value in JsonNode
300 * @return ipV6Mode Mode of the ipV6Mode
301 */
302 private Mode getMode(String mode) {
303 Mode ipV6Mode;
304 if (mode == null) {
305 return null;
306 }
307 switch (mode) {
308 case "dhcpv6-stateful":
309 ipV6Mode = Mode.DHCPV6_STATEFUL;
310 break;
311 case "dhcpv6-stateless":
312 ipV6Mode = Mode.DHCPV6_STATELESS;
313 break;
314 case "slaac":
315 ipV6Mode = Mode.SLAAC;
316 break;
317 default:
318 ipV6Mode = null;
319 }
320 return ipV6Mode;
321 }
322
323 /**
324 * Changes JsonNode alocPools to a collection of the alocPools.
325 *
326 * @param allocationPools the allocationPools JsonNode
327 * @return a collection of allocationPools
328 */
329 public Iterable<AllocationPool> jsonNodeToAllocationPools(JsonNode allocationPools) {
330 checkNotNull(allocationPools, JSON_NOT_NULL);
331 ConcurrentMap<Integer, AllocationPool> alocplMaps = Maps
332 .newConcurrentMap();
333 Integer i = 0;
334 for (JsonNode node : allocationPools) {
335 IpAddress startIp = IpAddress.valueOf(node.get("start").asText());
336 IpAddress endIp = IpAddress.valueOf(node.get("end").asText());
337 AllocationPool alocPls = new DefaultAllocationPool(startIp, endIp);
338 alocplMaps.putIfAbsent(i, alocPls);
339 i++;
340 }
341 return Collections.unmodifiableCollection(alocplMaps.values());
342 }
343
344 /**
345 * Changes hostRoutes JsonNode to a collection of the hostRoutes.
346 *
347 * @param hostRoutes the hostRoutes json node
348 * @return a collection of hostRoutes
349 */
350 public Iterable<HostRoute> jsonNodeToHostRoutes(JsonNode hostRoutes) {
351 checkNotNull(hostRoutes, JSON_NOT_NULL);
352 ConcurrentMap<Integer, HostRoute> hostRouteMaps = Maps
353 .newConcurrentMap();
354 Integer i = 0;
355 for (JsonNode node : hostRoutes) {
356 IpAddress nexthop = IpAddress.valueOf(node.get("nexthop").asText());
357 IpPrefix destination = IpPrefix.valueOf(node.get("destination")
358 .asText());
359 HostRoute hostRoute = new DefaultHostRoute(nexthop, destination);
360 hostRouteMaps.putIfAbsent(i, hostRoute);
361 i++;
362 }
363 return Collections.unmodifiableCollection(hostRouteMaps.values());
364 }
365
366 /**
367 * Returns the specified item if that items is null; otherwise throws not
368 * found exception.
369 *
370 * @param item item to check
371 * @param <T> item type
372 * @param message not found message
373 * @return item if not null
374 * @throws org.onlab.util.ItemNotFoundException if item is null
375 */
376 protected <T> T nullIsNotFound(T item, String message) {
377 if (item == null) {
378 throw new ItemNotFoundException(message);
379 }
380 return item;
381 }
382
383}