Merge "Remove unused spring dependency and wrong version in web pom"
[controller.git] / opendaylight / northbound / networkconfiguration / neutron / src / main / java / org / opendaylight / controller / networkconfig / neutron / northbound / NeutronSubnetsNorthbound.java
1 /*\r
2  * Copyright IBM Corporation, 2013.  All rights reserved.\r
3  *\r
4  * This program and the accompanying materials are made available under the\r
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
6  * and is available at http://www.eclipse.org/legal/epl-v10.html\r
7  */\r
8 \r
9 package org.opendaylight.controller.networkconfig.neutron.northbound;\r
10 \r
11 \r
12 import java.util.ArrayList;\r
13 import java.util.HashMap;\r
14 import java.util.Iterator;\r
15 import java.util.List;\r
16 import javax.ws.rs.Consumes;\r
17 import javax.ws.rs.DELETE;\r
18 import javax.ws.rs.GET;\r
19 import javax.ws.rs.POST;\r
20 import javax.ws.rs.PUT;\r
21 import javax.ws.rs.Path;\r
22 import javax.ws.rs.PathParam;\r
23 import javax.ws.rs.Produces;\r
24 import javax.ws.rs.QueryParam;\r
25 import javax.ws.rs.core.MediaType;\r
26 import javax.ws.rs.core.Response;\r
27 \r
28 import org.codehaus.enunciate.jaxrs.ResponseCode;\r
29 import org.codehaus.enunciate.jaxrs.StatusCodes;\r
30 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkAware;\r
31 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;\r
32 import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetAware;\r
33 import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;\r
34 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;\r
35 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;\r
36 import org.opendaylight.controller.northbound.commons.RestMessages;\r
37 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;\r
38 import org.opendaylight.controller.sal.utils.ServiceHelper;\r
39 \r
40 /**\r
41  * Open DOVE Northbound REST APIs.<br>\r
42  * This class provides REST APIs for managing open DOVE internals related to Subnets\r
43  *\r
44  * <br>\r
45  * <br>\r
46  * Authentication scheme : <b>HTTP Basic</b><br>\r
47  * Authentication realm : <b>opendaylight</b><br>\r
48  * Transport : <b>HTTP and HTTPS</b><br>\r
49  * <br>\r
50  * HTTPS Authentication is disabled by default. Administrator can enable it in\r
51  * tomcat-server.xml after adding a proper keystore / SSL certificate from a\r
52  * trusted authority.<br>\r
53  * More info :\r
54  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration\r
55  *\r
56  */\r
57 \r
58 @Path("/subnets")\r
59 public class NeutronSubnetsNorthbound {\r
60 \r
61     private NeutronSubnet extractFields(NeutronSubnet o, List<String> fields) {\r
62         return o.extractFields(fields);\r
63     }\r
64 \r
65 \r
66     /**\r
67      * Returns a list of all Subnets */\r
68     @GET\r
69     @Produces({ MediaType.APPLICATION_JSON })\r
70     //@TypeHint(OpenStackSubnets.class)\r
71     @StatusCodes({\r
72             @ResponseCode(code = 200, condition = "Operation successful"),\r
73             @ResponseCode(code = 401, condition = "Unauthorized"),\r
74             @ResponseCode(code = 501, condition = "Not Implemented") })\r
75     public Response listSubnets(\r
76             // return fields\r
77             @QueryParam("fields") List<String> fields,\r
78             // note: openstack isn't clear about filtering on lists, so we aren't handling them\r
79             @QueryParam("id") String queryID,\r
80             @QueryParam("network_id") String queryNetworkID,\r
81             @QueryParam("name") String queryName,\r
82             @QueryParam("ip_version") String queryIPVersion,\r
83             @QueryParam("cidr") String queryCIDR,\r
84             @QueryParam("gateway_ip") String queryGatewayIP,\r
85             @QueryParam("enable_dhcp") String queryEnableDHCP,\r
86             @QueryParam("tenant_id") String queryTenantID,\r
87             // pagination\r
88             @QueryParam("limit") String limit,\r
89             @QueryParam("marker") String marker,\r
90             @QueryParam("page_reverse") String pageReverse\r
91             // sorting not supported\r
92             ) {\r
93         INeutronSubnetCRUD subnetInterface = NeutronNBInterfaces.getIfNBSubnetCRUD("default", this);\r
94         if (subnetInterface == null) {\r
95             throw new ServiceUnavailableException("Subnet CRUD Interface "\r
96                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
97         }\r
98         List<NeutronSubnet> allNetworks = subnetInterface.getAllSubnets();\r
99         List<NeutronSubnet> ans = new ArrayList<NeutronSubnet>();\r
100         Iterator<NeutronSubnet> i = allNetworks.iterator();\r
101         while (i.hasNext()) {\r
102             NeutronSubnet oSS = i.next();\r
103             if ((queryID == null || queryID.equals(oSS.getID())) &&\r
104                     (queryNetworkID == null || queryNetworkID.equals(oSS.getNetworkUUID())) &&\r
105                     (queryName == null || queryName.equals(oSS.getName())) &&\r
106                     (queryIPVersion == null || queryIPVersion.equals(oSS.getIpVersion())) &&\r
107                     (queryCIDR == null || queryCIDR.equals(oSS.getCidr())) &&\r
108                     (queryGatewayIP == null || queryGatewayIP.equals(oSS.getGatewayIP())) &&\r
109                     (queryEnableDHCP == null || queryEnableDHCP.equals(oSS.getEnableDHCP())) &&\r
110                     (queryTenantID == null || queryTenantID.equals(oSS.getTenantID()))) {\r
111                 if (fields.size() > 0)\r
112                     ans.add(extractFields(oSS,fields));\r
113                 else\r
114                     ans.add(oSS);\r
115             }\r
116         }\r
117         //TODO: apply pagination to results\r
118         return Response.status(200).entity(\r
119                 new NeutronSubnetRequest(ans)).build();\r
120     }\r
121 \r
122     /**\r
123      * Returns a specific Subnet */\r
124 \r
125     @Path("{subnetUUID}")\r
126     @GET\r
127     @Produces({ MediaType.APPLICATION_JSON })\r
128     //@TypeHint(OpenStackSubnets.class)\r
129     @StatusCodes({\r
130             @ResponseCode(code = 200, condition = "Operation successful"),\r
131             @ResponseCode(code = 401, condition = "Unauthorized"),\r
132             @ResponseCode(code = 404, condition = "Not Found"),\r
133             @ResponseCode(code = 501, condition = "Not Implemented") })\r
134     public Response showSubnet(\r
135             @PathParam("subnetUUID") String subnetUUID,\r
136             // return fields\r
137             @QueryParam("fields") List<String> fields) {\r
138         INeutronSubnetCRUD subnetInterface = NeutronNBInterfaces.getIfNBSubnetCRUD("default",this);\r
139         if (subnetInterface == null) {\r
140             throw new ServiceUnavailableException("Subnet CRUD Interface "\r
141                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
142         }\r
143         if (!subnetInterface.subnetExists(subnetUUID))\r
144             return Response.status(404).build();\r
145         if (fields.size() > 0) {\r
146             NeutronSubnet ans = subnetInterface.getSubnet(subnetUUID);\r
147             return Response.status(200).entity(\r
148                     new NeutronSubnetRequest(extractFields(ans, fields))).build();\r
149         } else\r
150             return Response.status(200).entity(\r
151                     new NeutronSubnetRequest(subnetInterface.getSubnet(subnetUUID))).build();\r
152     }\r
153 \r
154     /**\r
155      * Creates new Subnets */\r
156 \r
157     @POST\r
158     @Produces({ MediaType.APPLICATION_JSON })\r
159     @Consumes({ MediaType.APPLICATION_JSON })\r
160     //@TypeHint(OpenStackSubnets.class)\r
161     @StatusCodes({\r
162             @ResponseCode(code = 201, condition = "Created"),\r
163             @ResponseCode(code = 400, condition = "Bad Request"),\r
164             @ResponseCode(code = 401, condition = "Unauthorized"),\r
165             @ResponseCode(code = 403, condition = "Forbidden"),\r
166             @ResponseCode(code = 404, condition = "Not Found"),\r
167             @ResponseCode(code = 409, condition = "Conflict"),\r
168             @ResponseCode(code = 501, condition = "Not Implemented") })\r
169     public Response createSubnets(final NeutronSubnetRequest input) {\r
170         INeutronSubnetCRUD subnetInterface = NeutronNBInterfaces.getIfNBSubnetCRUD("default",this);\r
171         if (subnetInterface == null) {\r
172             throw new ServiceUnavailableException("Subnet CRUD Interface "\r
173                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
174         }\r
175         INeutronNetworkCRUD networkInterface = NeutronNBInterfaces.getIfNBNetworkCRUD("default", this);\r
176         if (networkInterface == null) {\r
177             throw new ServiceUnavailableException("Network CRUD Interface "\r
178                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
179         }\r
180         if (input.isSingleton()) {\r
181             NeutronSubnet singleton = input.getSingleton();\r
182 \r
183             /*\r
184              *  Verify that the subnet doesn't already exist (Issue: is a deeper check necessary?)\r
185              *  the specified network exists, the subnet has a valid network address,\r
186              *  and that the gateway IP doesn't overlap with the allocation pools\r
187              *  *then* add the subnet to the cache\r
188              */\r
189             if (subnetInterface.subnetExists(singleton.getID()))\r
190                 return Response.status(400).build();\r
191             if (!networkInterface.networkExists(singleton.getNetworkUUID()))\r
192                 return Response.status(404).build();\r
193             if (!singleton.isValidCIDR())\r
194                 return Response.status(400).build();\r
195             singleton.initDefaults();\r
196             if (singleton.gatewayIP_Pool_overlap())\r
197                 return Response.status(409).build();\r
198             Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);\r
199             if (instances != null) {\r
200                 for (Object instance : instances) {\r
201                     INeutronSubnetAware service = (INeutronSubnetAware) instance;\r
202                     int status = service.canCreateSubnet(singleton);\r
203                     if (status < 200 || status > 299)\r
204                         return Response.status(status).build();\r
205                 }\r
206             }\r
207             subnetInterface.addSubnet(singleton);\r
208             if (instances != null) {\r
209                 for (Object instance : instances) {\r
210                     INeutronSubnetAware service = (INeutronSubnetAware) instance;\r
211                     service.neutronSubnetCreated(singleton);\r
212                 }\r
213             }\r
214         } else {\r
215             List<NeutronSubnet> bulk = input.getBulk();\r
216             Iterator<NeutronSubnet> i = bulk.iterator();\r
217             HashMap<String, NeutronSubnet> testMap = new HashMap<String, NeutronSubnet>();\r
218             Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);\r
219             while (i.hasNext()) {\r
220                 NeutronSubnet test = i.next();\r
221 \r
222                 /*\r
223                  *  Verify that the subnet doesn't already exist (Issue: is a deeper check necessary?)\r
224                  *  the specified network exists, the subnet has a valid network address,\r
225                  *  and that the gateway IP doesn't overlap with the allocation pools,\r
226                  *  and that the bulk request doesn't already contain a subnet with this id\r
227                  */\r
228 \r
229                 test.initDefaults();\r
230                 if (subnetInterface.subnetExists(test.getID()))\r
231                     return Response.status(400).build();\r
232                 if (testMap.containsKey(test.getID()))\r
233                     return Response.status(400).build();\r
234                 testMap.put(test.getID(), test);\r
235                 if (!networkInterface.networkExists(test.getNetworkUUID()))\r
236                     return Response.status(404).build();\r
237                 if (!test.isValidCIDR())\r
238                     return Response.status(400).build();\r
239                 if (test.gatewayIP_Pool_overlap())\r
240                     return Response.status(409).build();\r
241                 if (instances != null) {\r
242                     for (Object instance : instances) {\r
243                         INeutronSubnetAware service = (INeutronSubnetAware) instance;\r
244                         int status = service.canCreateSubnet(test);\r
245                         if (status < 200 || status > 299)\r
246                             return Response.status(status).build();\r
247                     }\r
248                 }\r
249             }\r
250 \r
251             /*\r
252              * now, each element of the bulk request can be added to the cache\r
253              */\r
254             i = bulk.iterator();\r
255             while (i.hasNext()) {\r
256                 NeutronSubnet test = i.next();\r
257                 subnetInterface.addSubnet(test);\r
258                 if (instances != null) {\r
259                     for (Object instance : instances) {\r
260                         INeutronSubnetAware service = (INeutronSubnetAware) instance;\r
261                         service.neutronSubnetCreated(test);\r
262                     }\r
263                 }\r
264             }\r
265         }\r
266         return Response.status(201).entity(input).build();\r
267     }\r
268 \r
269     /**\r
270      * Updates a Subnet */\r
271 \r
272     @Path("{subnetUUID}")\r
273     @PUT\r
274     @Produces({ MediaType.APPLICATION_JSON })\r
275     @Consumes({ MediaType.APPLICATION_JSON })\r
276     //@TypeHint(OpenStackSubnets.class)\r
277     @StatusCodes({\r
278             @ResponseCode(code = 200, condition = "Operation successful"),\r
279             @ResponseCode(code = 400, condition = "Bad Request"),\r
280             @ResponseCode(code = 401, condition = "Unauthorized"),\r
281             @ResponseCode(code = 403, condition = "Forbidden"),\r
282             @ResponseCode(code = 404, condition = "Not Found"),\r
283             @ResponseCode(code = 501, condition = "Not Implemented") })\r
284     public Response updateSubnet(\r
285             @PathParam("subnetUUID") String subnetUUID, final NeutronSubnetRequest input\r
286             ) {\r
287         INeutronSubnetCRUD subnetInterface = NeutronNBInterfaces.getIfNBSubnetCRUD("default", this);\r
288         if (subnetInterface == null) {\r
289             throw new ServiceUnavailableException("Subnet CRUD Interface "\r
290                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
291         }\r
292 \r
293         /*\r
294          * verify the subnet exists and there is only one delta provided\r
295          */\r
296         if (!subnetInterface.subnetExists(subnetUUID))\r
297             return Response.status(404).build();\r
298         if (!input.isSingleton())\r
299             return Response.status(400).build();\r
300         NeutronSubnet delta = input.getSingleton();\r
301         NeutronSubnet original = subnetInterface.getSubnet(subnetUUID);\r
302 \r
303         /*\r
304          * updates restricted by Neutron\r
305          */\r
306         if (delta.getID() != null || delta.getTenantID() != null ||\r
307                 delta.getIpVersion() != null || delta.getCidr() != null ||\r
308                 delta.getAllocationPools() != null)\r
309             return Response.status(400).build();\r
310 \r
311         Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);\r
312         if (instances != null) {\r
313             for (Object instance : instances) {\r
314                 INeutronSubnetAware service = (INeutronSubnetAware) instance;\r
315                 int status = service.canUpdateSubnet(delta, original);\r
316                 if (status < 200 || status > 299)\r
317                     return Response.status(status).build();\r
318             }\r
319         }\r
320 \r
321         /*\r
322          * update the object and return it\r
323          */\r
324         subnetInterface.updateSubnet(subnetUUID, delta);\r
325         NeutronSubnet updatedSubnet = subnetInterface.getSubnet(subnetUUID);\r
326         if (instances != null) {\r
327             for (Object instance : instances) {\r
328                 INeutronSubnetAware service = (INeutronSubnetAware) instance;\r
329                 service.neutronSubnetUpdated(updatedSubnet);\r
330             }\r
331         }\r
332         return Response.status(200).entity(\r
333                 new NeutronSubnetRequest(subnetInterface.getSubnet(subnetUUID))).build();\r
334     }\r
335 \r
336     /**\r
337      * Deletes a Subnet */\r
338 \r
339     @Path("{subnetUUID}")\r
340     @DELETE\r
341     @StatusCodes({\r
342             @ResponseCode(code = 204, condition = "No Content"),\r
343             @ResponseCode(code = 401, condition = "Unauthorized"),\r
344             @ResponseCode(code = 404, condition = "Not Found"),\r
345             @ResponseCode(code = 409, condition = "Conflict"),\r
346             @ResponseCode(code = 501, condition = "Not Implemented") })\r
347     public Response deleteSubnet(\r
348             @PathParam("subnetUUID") String subnetUUID) {\r
349         INeutronSubnetCRUD subnetInterface = NeutronNBInterfaces.getIfNBSubnetCRUD("default", this);\r
350         if (subnetInterface == null) {\r
351             throw new ServiceUnavailableException("Network CRUD Interface "\r
352                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
353         }\r
354 \r
355         /*\r
356          * verify the subnet exists and it isn't currently in use\r
357          */\r
358         if (!subnetInterface.subnetExists(subnetUUID))\r
359             return Response.status(404).build();\r
360         if (subnetInterface.subnetInUse(subnetUUID))\r
361             return Response.status(409).build();\r
362         NeutronSubnet singleton = subnetInterface.getSubnet(subnetUUID);\r
363         Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);\r
364         if (instances != null) {\r
365             for (Object instance : instances) {\r
366                 INeutronSubnetAware service = (INeutronSubnetAware) instance;\r
367                 int status = service.canDeleteSubnet(singleton);\r
368                 if (status < 200 || status > 299)\r
369                     return Response.status(status).build();\r
370             }\r
371         }\r
372 \r
373         /*\r
374          * remove it and return 204 status\r
375          */\r
376         subnetInterface.removeSubnet(subnetUUID);\r
377         if (instances != null) {\r
378             for (Object instance : instances) {\r
379                 INeutronSubnetAware service = (INeutronSubnetAware) instance;\r
380                 service.neutronSubnetDeleted(singleton);\r
381             }\r
382         }\r
383         return Response.status(204).build();\r
384     }\r
385 }\r