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