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