6f3ed13c363cd79dfd92ff5a6020e2f6e84a55dd
[controller.git] / opendaylight / northbound / networkconfiguration / neutron / src / main / java / org / opendaylight / controller / networkconfig / neutron / northbound / NeutronFloatingIPsNorthbound.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 import java.util.ArrayList;\r
12 import java.util.Iterator;\r
13 import java.util.List;\r
14 import javax.ws.rs.Consumes;\r
15 import javax.ws.rs.DELETE;\r
16 import javax.ws.rs.GET;\r
17 import javax.ws.rs.POST;\r
18 import javax.ws.rs.PUT;\r
19 import javax.ws.rs.Path;\r
20 import javax.ws.rs.PathParam;\r
21 import javax.ws.rs.Produces;\r
22 import javax.ws.rs.QueryParam;\r
23 import javax.ws.rs.core.MediaType;\r
24 import javax.ws.rs.core.Response;\r
25 \r
26 import org.codehaus.enunciate.jaxrs.ResponseCode;\r
27 import org.codehaus.enunciate.jaxrs.StatusCodes;\r
28 import org.opendaylight.controller.networkconfig.neutron.INeutronFloatingIPAware;\r
29 import org.opendaylight.controller.networkconfig.neutron.INeutronFloatingIPCRUD;\r
30 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;\r
31 import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;\r
32 import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;\r
33 import org.opendaylight.controller.networkconfig.neutron.NeutronFloatingIP;\r
34 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;\r
35 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;\r
36 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;\r
37 import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;\r
38 import org.opendaylight.controller.northbound.commons.RestMessages;\r
39 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;\r
40 import org.opendaylight.controller.sal.utils.ServiceHelper;\r
41 \r
42 /**\r
43  * Open DOVE Northbound REST APIs.<br>\r
44  * This class provides REST APIs for managing the open DOVE\r
45  *\r
46  * <br>\r
47  * <br>\r
48  * Authentication scheme : <b>HTTP Basic</b><br>\r
49  * Authentication realm : <b>opendaylight</b><br>\r
50  * Transport : <b>HTTP and HTTPS</b><br>\r
51  * <br>\r
52  * HTTPS Authentication is disabled by default. Administrator can enable it in\r
53  * tomcat-server.xml after adding a proper keystore / SSL certificate from a\r
54  * trusted authority.<br>\r
55  * More info :\r
56  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration\r
57  *\r
58  */\r
59 \r
60 @Path("/floatingips")\r
61 public class NeutronFloatingIPsNorthbound {\r
62 \r
63     private NeutronFloatingIP extractFields(NeutronFloatingIP o, List<String> fields) {\r
64         return o.extractFields(fields);\r
65     }\r
66 \r
67     /**\r
68      * Returns a list of all FloatingIPs */\r
69 \r
70     @GET\r
71     @Produces({ MediaType.APPLICATION_JSON })\r
72     @StatusCodes({\r
73             @ResponseCode(code = 200, condition = "Operation successful"),\r
74             @ResponseCode(code = 401, condition = "Unauthorized"),\r
75             @ResponseCode(code = 501, condition = "Not Implemented") })\r
76     public Response listFloatingIPs(\r
77             // return fields\r
78             @QueryParam("fields") List<String> fields,\r
79             // note: openstack isn't clear about filtering on lists, so we aren't handling them\r
80             @QueryParam("id") String queryID,\r
81             @QueryParam("floating_network_id") String queryFloatingNetworkId,\r
82             @QueryParam("port_id") String queryPortId,\r
83             @QueryParam("fixed_ip_address") String queryFixedIPAddress,\r
84             @QueryParam("floating_ip_address") String queryFloatingIPAddress,\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         INeutronFloatingIPCRUD floatingIPInterface = NeutronNBInterfaces.getIfNBFloatingIPCRUD("default",this);\r
93         if (floatingIPInterface == null) {\r
94             throw new ServiceUnavailableException("Floating IP CRUD Interface "\r
95                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
96         }\r
97         List<NeutronFloatingIP> allFloatingIPs = floatingIPInterface.getAllFloatingIPs();\r
98         List<NeutronFloatingIP> ans = new ArrayList<NeutronFloatingIP>();\r
99         Iterator<NeutronFloatingIP> i = allFloatingIPs.iterator();\r
100         while (i.hasNext()) {\r
101             NeutronFloatingIP oSS = i.next();\r
102             //match filters: TODO provider extension and router extension\r
103             if ((queryID == null || queryID.equals(oSS.getID())) &&\r
104                     (queryFloatingNetworkId == null || queryFloatingNetworkId.equals(oSS.getFloatingNetworkUUID())) &&\r
105                     (queryPortId == null || queryPortId.equals(oSS.getPortUUID())) &&\r
106                     (queryFixedIPAddress == null || queryFixedIPAddress.equals(oSS.getFixedIPAddress())) &&\r
107                     (queryFloatingIPAddress == null || queryFloatingIPAddress.equals(oSS.getFloatingIPAddress())) &&\r
108                     (queryTenantID == null || queryTenantID.equals(oSS.getTenantUUID()))) {\r
109                 if (fields.size() > 0)\r
110                     ans.add(extractFields(oSS,fields));\r
111                 else\r
112                     ans.add(oSS);\r
113             }\r
114         }\r
115         //TODO: apply pagination to results\r
116         return Response.status(200).entity(\r
117                 new NeutronFloatingIPRequest(ans)).build();\r
118     }\r
119 \r
120     /**\r
121      * Returns a specific FloatingIP */\r
122 \r
123     @Path("{floatingipUUID}")\r
124     @GET\r
125     @Produces({ MediaType.APPLICATION_JSON })\r
126     @StatusCodes({\r
127             @ResponseCode(code = 200, condition = "Operation successful"),\r
128             @ResponseCode(code = 401, condition = "Unauthorized"),\r
129             @ResponseCode(code = 404, condition = "Not Found"),\r
130             @ResponseCode(code = 501, condition = "Not Implemented") })\r
131     public Response showFloatingIP(\r
132             @PathParam("floatingipUUID") String floatingipUUID,\r
133             // return fields\r
134             @QueryParam("fields") List<String> fields ) {\r
135         INeutronFloatingIPCRUD floatingIPInterface = NeutronNBInterfaces.getIfNBFloatingIPCRUD("default",this);\r
136         if (floatingIPInterface == null) {\r
137             throw new ServiceUnavailableException("Floating IP CRUD Interface "\r
138                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
139         }\r
140         if (!floatingIPInterface.floatingIPExists(floatingipUUID))\r
141             return Response.status(404).build();\r
142         if (fields.size() > 0) {\r
143             NeutronFloatingIP ans = floatingIPInterface.getFloatingIP(floatingipUUID);\r
144             return Response.status(200).entity(\r
145                     new NeutronFloatingIPRequest(extractFields(ans, fields))).build();\r
146         } else\r
147             return Response.status(200).entity(\r
148                     new NeutronFloatingIPRequest(floatingIPInterface.getFloatingIP(floatingipUUID))).build();\r
149 \r
150     }\r
151 \r
152     /**\r
153      * Creates new FloatingIPs */\r
154 \r
155     @POST\r
156     @Produces({ MediaType.APPLICATION_JSON })\r
157     @Consumes({ MediaType.APPLICATION_JSON })\r
158     @StatusCodes({\r
159         @ResponseCode(code = 201, condition = "Created"),\r
160         @ResponseCode(code = 400, condition = "Bad Request"),\r
161         @ResponseCode(code = 401, condition = "Unauthorized"),\r
162         @ResponseCode(code = 409, condition = "Conflict"),\r
163         @ResponseCode(code = 501, condition = "Not Implemented") })\r
164     public Response createFloatingIPs(final NeutronFloatingIPRequest input) {\r
165         INeutronFloatingIPCRUD floatingIPInterface = NeutronNBInterfaces.getIfNBFloatingIPCRUD("default",this);\r
166         if (floatingIPInterface == null) {\r
167             throw new ServiceUnavailableException("Floating IP CRUD Interface "\r
168                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
169         }\r
170         INeutronNetworkCRUD networkInterface = NeutronNBInterfaces.getIfNBNetworkCRUD("default", this);\r
171         if (networkInterface == null) {\r
172             throw new ServiceUnavailableException("Network CRUD Interface "\r
173                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
174         }\r
175         INeutronSubnetCRUD subnetInterface = NeutronNBInterfaces.getIfNBSubnetCRUD("default", this);\r
176         if (subnetInterface == null) {\r
177             throw new ServiceUnavailableException("Subnet CRUD Interface "\r
178                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
179         }\r
180         INeutronPortCRUD portInterface = NeutronNBInterfaces.getIfNBPortCRUD("default", this);\r
181         if (portInterface == null) {\r
182             throw new ServiceUnavailableException("Port CRUD Interface "\r
183                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
184         }\r
185         if (input.isSingleton()) {\r
186             NeutronFloatingIP singleton = input.getSingleton();\r
187             // check existence of id in cache and return badrequest if exists\r
188             if (floatingIPInterface.floatingIPExists(singleton.getID()))\r
189                 return Response.status(400).build();\r
190             // check if the external network is specified, exists, and is an external network\r
191             String externalNetworkUUID = singleton.getFloatingNetworkUUID();\r
192             if (externalNetworkUUID == null)\r
193                 return Response.status(400).build();\r
194             if (!networkInterface.networkExists(externalNetworkUUID))\r
195                 return Response.status(400).build();\r
196             NeutronNetwork externNetwork = networkInterface.getNetwork(externalNetworkUUID);\r
197             if (!externNetwork.isRouterExternal())\r
198                 return Response.status(400).build();\r
199             // if floating IP is specified, make sure it can come from the network\r
200             String floatingIP = singleton.getFloatingIPAddress();\r
201             if (floatingIP != null) {\r
202                 if (externNetwork.getSubnets().size() > 1)\r
203                     return Response.status(400).build();\r
204                 NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));\r
205                 if (!externSubnet.isValidIP(floatingIP))\r
206                     return Response.status(400).build();\r
207                 if (externSubnet.isIPInUse(floatingIP))\r
208                     return Response.status(409).build();\r
209             }\r
210             // if port_id is specified, then check that the port exists and has at least one IP\r
211             String port_id = singleton.getPortUUID();\r
212             if (port_id != null) {\r
213                 String fixedIP = null;        // used for the fixedIP calculation\r
214                 if (!portInterface.portExists(port_id))\r
215                     return Response.status(404).build();\r
216                 NeutronPort port = portInterface.getPort(port_id);\r
217                 if (port.getFixedIPs().size() < 1)\r
218                     return Response.status(400).build();\r
219                 // if there is more than one fixed IP then check for fixed_ip_address\r
220                 // and that it is in the list of port addresses\r
221                 if (port.getFixedIPs().size() > 1) {\r
222                     fixedIP = singleton.getFixedIPAddress();\r
223                     if (fixedIP == null)\r
224                         return Response.status(400).build();\r
225                     Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();\r
226                     boolean validFixedIP = false;\r
227                     while (i.hasNext() && !validFixedIP) {\r
228                         Neutron_IPs ip = i.next();\r
229                         if (ip.getIpAddress().equals(fixedIP))\r
230                             validFixedIP = true;\r
231                     }\r
232                     if (!validFixedIP)\r
233                         return Response.status(400).build();\r
234                 } else {\r
235                     fixedIP = port.getFixedIPs().get(0).getIpAddress();\r
236                     if (singleton.getFixedIPAddress() != null && !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))\r
237                         return Response.status(400).build();\r
238                 }\r
239                 //lastly check that this fixed IP address isn't already used\r
240                 if (port.isBoundToFloatingIP(fixedIP))\r
241                     return Response.status(409).build();\r
242                 singleton.setFixedIPAddress(fixedIP);\r
243             }\r
244             Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);\r
245             if (instances != null) {\r
246                 for (Object instance : instances) {\r
247                     INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;\r
248                     int status = service.canCreateFloatingIP(singleton);\r
249                     if (status < 200 || status > 299)\r
250                         return Response.status(status).build();\r
251                 }\r
252             }\r
253             floatingIPInterface.addFloatingIP(singleton);\r
254             if (instances != null) {\r
255                 for (Object instance : instances) {\r
256                     INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;\r
257                     service.neutronFloatingIPCreated(singleton);\r
258                 }\r
259             }\r
260         } else {\r
261             return Response.status(400).build();\r
262         }\r
263         return Response.status(201).entity(input).build();\r
264     }\r
265 \r
266     /**\r
267      * Updates a FloatingIP */\r
268 \r
269     @Path("{floatingipUUID}")\r
270     @PUT\r
271     @Produces({ MediaType.APPLICATION_JSON })\r
272     @Consumes({ MediaType.APPLICATION_JSON })\r
273     @StatusCodes({\r
274             @ResponseCode(code = 200, condition = "Operation successful"),\r
275             @ResponseCode(code = 400, condition = "Bad Request"),\r
276             @ResponseCode(code = 401, condition = "Unauthorized"),\r
277             @ResponseCode(code = 404, condition = "Not Found"),\r
278             @ResponseCode(code = 409, condition = "Conflict"),\r
279             @ResponseCode(code = 501, condition = "Not Implemented") })\r
280     public Response updateFloatingIP(\r
281             @PathParam("floatingipUUID") String floatingipUUID,\r
282             NeutronFloatingIPRequest input\r
283             ) {\r
284         INeutronFloatingIPCRUD floatingIPInterface = NeutronNBInterfaces.getIfNBFloatingIPCRUD("default",this);\r
285         if (floatingIPInterface == null) {\r
286             throw new ServiceUnavailableException("Floating IP CRUD Interface "\r
287                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
288         }\r
289         INeutronNetworkCRUD networkInterface = NeutronNBInterfaces.getIfNBNetworkCRUD("default", this);\r
290         if (networkInterface == null) {\r
291             throw new ServiceUnavailableException("Network CRUD Interface "\r
292                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
293         }\r
294         INeutronSubnetCRUD subnetInterface = NeutronNBInterfaces.getIfNBSubnetCRUD("default", this);\r
295         if (subnetInterface == null) {\r
296             throw new ServiceUnavailableException("Subnet CRUD Interface "\r
297                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
298         }\r
299         INeutronPortCRUD portInterface = NeutronNBInterfaces.getIfNBPortCRUD("default", this);\r
300         if (portInterface == null) {\r
301             throw new ServiceUnavailableException("Port CRUD Interface "\r
302                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
303         }\r
304         if (!floatingIPInterface.floatingIPExists(floatingipUUID))\r
305             return Response.status(404).build();\r
306 \r
307         NeutronFloatingIP sourceFloatingIP = floatingIPInterface.getFloatingIP(floatingipUUID);\r
308         if (!input.isSingleton())\r
309             return Response.status(400).build();\r
310         NeutronFloatingIP singleton = input.getSingleton();\r
311         if (singleton.getID() != null)\r
312             return Response.status(400).build();\r
313 \r
314         NeutronNetwork externNetwork = networkInterface.getNetwork(\r
315                 sourceFloatingIP.getFloatingNetworkUUID());\r
316 \r
317         // if floating IP is specified, make sure it can come from the network\r
318         String floatingIP = singleton.getFloatingIPAddress();\r
319         if (floatingIP != null) {\r
320             if (externNetwork.getSubnets().size() > 1)\r
321                 return Response.status(400).build();\r
322             NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));\r
323             if (!externSubnet.isValidIP(floatingIP))\r
324                 return Response.status(400).build();\r
325             if (externSubnet.isIPInUse(floatingIP))\r
326                 return Response.status(409).build();\r
327         }\r
328 \r
329         // if port_id is specified, then check that the port exists and has at least one IP\r
330         String port_id = singleton.getPortUUID();\r
331         if (port_id != null) {\r
332             String fixedIP = null;        // used for the fixedIP calculation\r
333             if (!portInterface.portExists(port_id))\r
334                 return Response.status(404).build();\r
335             NeutronPort port = portInterface.getPort(port_id);\r
336             if (port.getFixedIPs().size() < 1)\r
337                 return Response.status(400).build();\r
338             // if there is more than one fixed IP then check for fixed_ip_address\r
339             // and that it is in the list of port addresses\r
340             if (port.getFixedIPs().size() > 1) {\r
341                 fixedIP = singleton.getFixedIPAddress();\r
342                 if (fixedIP == null)\r
343                     return Response.status(400).build();\r
344                 Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();\r
345                 boolean validFixedIP = false;\r
346                 while (i.hasNext() && !validFixedIP) {\r
347                     Neutron_IPs ip = i.next();\r
348                     if (ip.getIpAddress().equals(fixedIP))\r
349                         validFixedIP = true;\r
350                 }\r
351                 if (!validFixedIP)\r
352                     return Response.status(400).build();\r
353             } else {\r
354                 fixedIP = port.getFixedIPs().get(0).getIpAddress();\r
355                 if (singleton.getFixedIPAddress() != null &&\r
356                         !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))\r
357                     return Response.status(400).build();\r
358             }\r
359             //lastly check that this fixed IP address isn't already used\r
360             if (port.isBoundToFloatingIP(fixedIP))\r
361                 return Response.status(409).build();\r
362             singleton.setFixedIPAddress(fixedIP);\r
363         }\r
364         NeutronFloatingIP target = floatingIPInterface.getFloatingIP(floatingipUUID);\r
365         Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);\r
366         if (instances != null) {\r
367             for (Object instance : instances) {\r
368                 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;\r
369                 int status = service.canUpdateFloatingIP(singleton, target);\r
370                 if (status < 200 || status > 299)\r
371                     return Response.status(status).build();\r
372             }\r
373         }\r
374         floatingIPInterface.updateFloatingIP(floatingipUUID, singleton);\r
375         target = floatingIPInterface.getFloatingIP(floatingipUUID);\r
376         if (instances != null) {\r
377             for (Object instance : instances) {\r
378                 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;\r
379                 service.neutronFloatingIPUpdated(target);\r
380             }\r
381         }\r
382         return Response.status(200).entity(\r
383                 new NeutronFloatingIPRequest(target)).build();\r
384 \r
385     }\r
386 \r
387     /**\r
388      * Deletes a FloatingIP */\r
389 \r
390     @Path("{floatingipUUID}")\r
391     @DELETE\r
392     @StatusCodes({\r
393             @ResponseCode(code = 204, condition = "No Content"),\r
394             @ResponseCode(code = 401, condition = "Unauthorized"),\r
395             @ResponseCode(code = 404, condition = "Not Found"),\r
396             @ResponseCode(code = 501, condition = "Not Implemented") })\r
397     public Response deleteFloatingIP(\r
398             @PathParam("floatingipUUID") String floatingipUUID) {\r
399         INeutronFloatingIPCRUD floatingIPInterface = NeutronNBInterfaces.getIfNBFloatingIPCRUD("default",this);\r
400         if (floatingIPInterface == null) {\r
401             throw new ServiceUnavailableException("Floating IP CRUD Interface "\r
402                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
403         }\r
404         if (!floatingIPInterface.floatingIPExists(floatingipUUID))\r
405             return Response.status(404).build();\r
406         // TODO: need to undo port association if it exists\r
407         NeutronFloatingIP singleton = floatingIPInterface.getFloatingIP(floatingipUUID);\r
408         Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);\r
409         if (instances != null) {\r
410             for (Object instance : instances) {\r
411                 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;\r
412                 int status = service.canDeleteFloatingIP(singleton);\r
413                 if (status < 200 || status > 299)\r
414                     return Response.status(status).build();\r
415             }\r
416         }\r
417         floatingIPInterface.removeFloatingIP(floatingipUUID);\r
418         if (instances != null) {\r
419             for (Object instance : instances) {\r
420                 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;\r
421                 service.neutronFloatingIPDeleted(singleton);\r
422             }\r
423         }\r
424         return Response.status(204).build();\r
425     }\r
426 }\r