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