2 * Copyright IBM Corporation, 2013. All rights reserved.
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
9 package org.opendaylight.controller.networkconfig.neutron.northbound;
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;
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;
44 * Open DOVE Northbound REST APIs.<br>
45 * This class provides REST APIs for managing the open DOVE
49 * Authentication scheme : <b>HTTP Basic</b><br>
50 * Authentication realm : <b>opendaylight</b><br>
51 * Transport : <b>HTTP and HTTPS</b><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>
57 * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
62 public class NeutronFloatingIPsNorthbound {
64 private NeutronFloatingIP extractFields(NeutronFloatingIP o, List<String> fields) {
65 return o.extractFields(fields);
69 * Returns a list of all FloatingIPs */
72 @Produces({ MediaType.APPLICATION_JSON })
74 @ResponseCode(code = 200, condition = "Operation successful"),
75 @ResponseCode(code = 401, condition = "Unauthorized"),
76 @ResponseCode(code = 501, condition = "Not Implemented") })
77 public Response listFloatingIPs(
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,
88 @QueryParam("limit") String limit,
89 @QueryParam("marker") String marker,
90 @QueryParam("page_reverse") String pageReverse
91 // sorting not supported
93 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
94 if (floatingIPInterface == null) {
95 throw new ServiceUnavailableException("Floating IP CRUD Interface "
96 + RestMessages.SERVICEUNAVAILABLE.toString());
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));
116 //TODO: apply pagination to results
117 return Response.status(200).entity(
118 new NeutronFloatingIPRequest(ans)).build();
122 * Returns a specific FloatingIP */
124 @Path("{floatingipUUID}")
126 @Produces({ MediaType.APPLICATION_JSON })
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,
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());
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();
148 return Response.status(200).entity(
149 new NeutronFloatingIPRequest(floatingIPInterface.getFloatingIP(floatingipUUID))).build();
154 * Creates new FloatingIPs */
157 @Produces({ MediaType.APPLICATION_JSON })
158 @Consumes({ MediaType.APPLICATION_JSON })
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());
171 INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
172 if (networkInterface == null) {
173 throw new ServiceUnavailableException("Network CRUD Interface "
174 + RestMessages.SERVICEUNAVAILABLE.toString());
176 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
177 if (subnetInterface == null) {
178 throw new ServiceUnavailableException("Subnet CRUD Interface "
179 + RestMessages.SERVICEUNAVAILABLE.toString());
181 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD( this);
182 if (portInterface == null) {
183 throw new ServiceUnavailableException("Port CRUD Interface "
184 + RestMessages.SERVICEUNAVAILABLE.toString());
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();
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();
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))
234 return Response.status(400).build();
236 fixedIP = port.getFixedIPs().get(0).getIpAddress();
237 if (singleton.getFixedIPAddress() != null && !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
238 return Response.status(400).build();
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);
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();
254 floatingIPInterface.addFloatingIP(singleton);
255 if (instances != null) {
256 for (Object instance : instances) {
257 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
258 service.neutronFloatingIPCreated(singleton);
262 return Response.status(400).build();
264 return Response.status(201).entity(input).build();
268 * Updates a FloatingIP */
270 @Path("{floatingipUUID}")
272 @Produces({ MediaType.APPLICATION_JSON })
273 @Consumes({ MediaType.APPLICATION_JSON })
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
285 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
286 if (floatingIPInterface == null) {
287 throw new ServiceUnavailableException("Floating IP CRUD Interface "
288 + RestMessages.SERVICEUNAVAILABLE.toString());
290 INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
291 if (networkInterface == null) {
292 throw new ServiceUnavailableException("Network CRUD Interface "
293 + RestMessages.SERVICEUNAVAILABLE.toString());
295 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
296 if (subnetInterface == null) {
297 throw new ServiceUnavailableException("Subnet CRUD Interface "
298 + RestMessages.SERVICEUNAVAILABLE.toString());
300 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD( this);
301 if (portInterface == null) {
302 throw new ServiceUnavailableException("Port CRUD Interface "
303 + RestMessages.SERVICEUNAVAILABLE.toString());
305 if (!floatingIPInterface.floatingIPExists(floatingipUUID))
306 return Response.status(404).build();
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();
315 NeutronNetwork externNetwork = networkInterface.getNetwork(
316 sourceFloatingIP.getFloatingNetworkUUID());
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();
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();
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))
353 return Response.status(400).build();
355 fixedIP = port.getFixedIPs().get(0).getIpAddress();
356 if (singleton.getFixedIPAddress() != null &&
357 !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
358 return Response.status(400).build();
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);
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();
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);
383 return Response.status(200).entity(
384 new NeutronFloatingIPRequest(target)).build();
389 * Deletes a FloatingIP */
391 @Path("{floatingipUUID}")
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());
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();
418 floatingIPInterface.removeFloatingIP(floatingipUUID);
419 if (instances != null) {
420 for (Object instance : instances) {
421 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
422 service.neutronFloatingIPDeleted(singleton);
425 return Response.status(204).build();