blob: deb9ca3736f3fadf7fae22d924f211699ad6a41a [file] [log] [blame]
Madan Jampani38a88212015-09-15 11:21:27 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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;
59import org.onosproject.vtnrsc.web.SubnetCodec;
60import 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);
72 public static final String SUBNET_NOT_CREATE = "Subnets is failed to create!";
bobzhoue528c112015-09-30 13:56:14 +080073 public static final String SUBNET_NOT_FOUND = "Subnets 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)
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();
83 }
84
85 @GET
86 @Path("{subnetUUID}")
87 @Produces(MediaType.APPLICATION_JSON)
88 public Response getSubnet(@PathParam("subnetUUID") String id) {
89
90 if (!get(SubnetService.class).exists(SubnetId.subnetId(id))) {
lishuai0f47f342015-09-16 11:38:48 +080091 return Response.status(NOT_FOUND)
92 .entity(SUBNET_NOT_FOUND).build();
Madan Jampani38a88212015-09-15 11:21:27 -070093 }
94 Subnet sub = nullIsNotFound(get(SubnetService.class)
95 .getSubnet(SubnetId.subnetId(id)),
96 SUBNET_NOT_FOUND);
97
98 ObjectNode result = new ObjectMapper().createObjectNode();
99 result.set("subnet", new SubnetCodec().encode(sub, this));
100 return ok(result.toString()).build();
101 }
102
103 @POST
104 @Produces(MediaType.APPLICATION_JSON)
105 @Consumes(MediaType.APPLICATION_JSON)
106 public Response createSubnet(final InputStream input) {
107
108 try {
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)),
114 SUBNET_NOT_CREATE);
115
116 if (!result) {
lishuai0f47f342015-09-16 11:38:48 +0800117 return Response.status(INTERNAL_SERVER_ERROR)
118 .entity(SUBNET_NOT_CREATE).build();
Madan Jampani38a88212015-09-15 11:21:27 -0700119 }
120 return Response.status(202).entity(result.toString()).build();
121 } catch (Exception e) {
122 return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
123 .build();
124 }
125 }
126
127 @PUT
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) {
133 try {
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);
139 if (!result) {
lishuai0f47f342015-09-16 11:38:48 +0800140 return Response.status(INTERNAL_SERVER_ERROR)
141 .entity(SUBNET_NOT_FOUND).build();
Madan Jampani38a88212015-09-15 11:21:27 -0700142 }
143 return Response.status(203).entity(result.toString()).build();
144 } catch (Exception e) {
145 return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
146 .build();
147 }
148 }
149
150 @Path("{subnetUUID}")
151 @DELETE
152 public Response deleteSingleSubnet(@PathParam("subnetUUID") String id)
153 throws IOException {
154 try {
155 SubnetId subId = SubnetId.subnetId(id);
156 Set<SubnetId> subIds = new HashSet<>();
157 subIds.add(subId);
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())
162 .build();
163 }
164 }
165
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");
172 }
173 log.debug("subnetNodes is {}", subnetNodes.toString());
174 if (subnetNodes.isArray()) {
175 subnets = changeJsonToSubs(subnetNodes);
176 } else {
177 subnets = changeJsonToSub(subnetNodes);
178 }
179 return subnets;
180 }
181
182 /**
183 * Returns a collection of subnets from subnetNodes.
184 *
185 * @param subnetNodes the subnet json node
186 * @return subnets a collection of subnets
187 */
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")) {
193 return null;
194 }
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());
lishuai0f47f342015-09-16 11:38:48 +0800201 String version = subnetNode.get("ip_version").asText();
202 Version ipVersion;
203 switch (version) {
204 case "4":
205 ipVersion = Version.INET;
206 break;
207 case "6":
208 ipVersion = Version.INET;
209 break;
210 default:
211 throw new IllegalArgumentException("ipVersion should be 4 or 6.");
212 }
Madan Jampani38a88212015-09-15 11:21:27 -0700213 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);
232 }
233 return Collections.unmodifiableCollection(subMap.values());
234 }
235
236 /**
237 * Returns a collection of subnets from subnetNodes.
238 *
239 * @param subnetNodes the subnet json node
240 * @return subnets a collection of subnets
241 */
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")) {
248 return null;
249 }
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();
257 Version ipVersion;
258 switch (version) {
259 case "4":
260 ipVersion = Version.INET;
261 break;
262 case "6":
263 ipVersion = Version.INET;
264 break;
265 default:
266 throw new IllegalArgumentException("ipVersion should be 4 or 6.");
267 }
268
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);
278
279 Mode ipV6AddressMode = getMode(subnetNodes.get("ipv6_address_mode")
280 .asText());
281 Mode ipV6RaMode = getMode(subnetNodes.get("ipv6_ra_mode").asText());
282
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());
290 }
291
292 /**
293 * Gets ipv6_address_mode or ipv6_ra_mode type.
294 *
295 * @param mode the String value in JsonNode
296 * @return ipV6Mode Mode of the ipV6Mode
297 */
298 private Mode getMode(String mode) {
299 Mode ipV6Mode;
300 if (mode == null) {
301 return null;
302 }
303 switch (mode) {
304 case "dhcpv6-stateful":
305 ipV6Mode = Mode.DHCPV6_STATEFUL;
306 break;
307 case "dhcpv6-stateless":
308 ipV6Mode = Mode.DHCPV6_STATELESS;
309 break;
310 case "slaac":
311 ipV6Mode = Mode.SLAAC;
312 break;
313 default:
314 ipV6Mode = null;
315 }
316 return ipV6Mode;
317 }
318
319 /**
320 * Changes JsonNode alocPools to a collection of the alocPools.
321 *
322 * @param allocationPools the allocationPools JsonNode
323 * @return a collection of allocationPools
324 */
325 public Iterable<AllocationPool> jsonNodeToAllocationPools(JsonNode allocationPools) {
326 checkNotNull(allocationPools, JSON_NOT_NULL);
327 ConcurrentMap<Integer, AllocationPool> alocplMaps = Maps
328 .newConcurrentMap();
329 Integer i = 0;
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);
335 i++;
336 }
337 return Collections.unmodifiableCollection(alocplMaps.values());
338 }
339
340 /**
341 * Changes hostRoutes JsonNode to a collection of the hostRoutes.
342 *
343 * @param hostRoutes the hostRoutes json node
344 * @return a collection of hostRoutes
345 */
346 public Iterable<HostRoute> jsonNodeToHostRoutes(JsonNode hostRoutes) {
347 checkNotNull(hostRoutes, JSON_NOT_NULL);
348 ConcurrentMap<Integer, HostRoute> hostRouteMaps = Maps
349 .newConcurrentMap();
350 Integer i = 0;
351 for (JsonNode node : hostRoutes) {
352 IpAddress nexthop = IpAddress.valueOf(node.get("nexthop").asText());
353 IpPrefix destination = IpPrefix.valueOf(node.get("destination")
354 .asText());
355 HostRoute hostRoute = new DefaultHostRoute(nexthop, destination);
356 hostRouteMaps.putIfAbsent(i, hostRoute);
357 i++;
358 }
359 return Collections.unmodifiableCollection(hostRouteMaps.values());
360 }
361
362 /**
363 * Returns the specified item if that items is null; otherwise throws not
364 * found exception.
365 *
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
371 */
372 protected <T> T nullIsNotFound(T item, String message) {
373 if (item == null) {
374 throw new ItemNotFoundException(message);
375 }
376 return item;
377 }
378
379}