3979e1e3621704f4021631158388f2a22e11d5c1
[onosfw.git] /
1 /*
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  */
16 package org.onosproject.vtnweb.resources;
17
18 import static com.google.common.base.Preconditions.checkArgument;
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.concurrent.ConcurrentMap;
30
31 import javax.ws.rs.Consumes;
32 import javax.ws.rs.DELETE;
33 import javax.ws.rs.GET;
34 import javax.ws.rs.POST;
35 import javax.ws.rs.PUT;
36 import javax.ws.rs.Path;
37 import javax.ws.rs.PathParam;
38 import javax.ws.rs.Produces;
39 import javax.ws.rs.core.MediaType;
40 import javax.ws.rs.core.Response;
41
42 import org.onlab.packet.IpAddress;
43 import org.onlab.packet.IpAddress.Version;
44 import org.onlab.packet.IpPrefix;
45 import org.onlab.util.ItemNotFoundException;
46 import org.onosproject.rest.AbstractWebResource;
47 import org.onosproject.vtnrsc.AllocationPool;
48 import org.onosproject.vtnrsc.DefaultAllocationPool;
49 import org.onosproject.vtnrsc.DefaultHostRoute;
50 import org.onosproject.vtnrsc.DefaultSubnet;
51 import org.onosproject.vtnrsc.HostRoute;
52 import org.onosproject.vtnrsc.Subnet;
53 import org.onosproject.vtnrsc.SubnetId;
54 import org.onosproject.vtnrsc.TenantId;
55 import org.onosproject.vtnrsc.TenantNetworkId;
56 import org.onosproject.vtnrsc.Subnet.Mode;
57 import org.onosproject.vtnrsc.subnet.SubnetService;
58 import org.onosproject.vtnrsc.web.SubnetCodec;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 import com.fasterxml.jackson.databind.JsonNode;
63 import com.fasterxml.jackson.databind.ObjectMapper;
64 import com.fasterxml.jackson.databind.node.ObjectNode;
65 import com.google.common.collect.Maps;
66 import com.google.common.collect.Sets;
67
68 @Path("subnets")
69 public 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<>();
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<>();
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,
215                                               Sets.newHashSet(hostRoutesIt), ipV6AddressMode,
216                                               ipV6RaMode, Sets.newHashSet(allocationPoolsIt));
217             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);
230         checkArgument(subnetNodes.get("enable_dhcp").isBoolean(), "enable_dhcp should be boolean");
231         checkArgument(subnetNodes.get("shared").isBoolean(), "shared should be boolean");
232         Map<SubnetId, Subnet> subMap = new HashMap<>();
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:
252             throw new IllegalArgumentException("ipVersion should be 4 or 6.");
253         }
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,
271                                           dhcpEnabled, shared, Sets.newHashSet(hostRoutesIt),
272                                           ipV6AddressMode, ipV6RaMode,
273                                           Sets.newHashSet(allocationPoolsIt));
274         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 }