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