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