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;
15 import javax.ws.rs.Consumes;
16 import javax.ws.rs.DELETE;
17 import javax.ws.rs.GET;
18 import javax.ws.rs.POST;
19 import javax.ws.rs.PUT;
20 import javax.ws.rs.Path;
21 import javax.ws.rs.PathParam;
22 import javax.ws.rs.Produces;
23 import javax.ws.rs.QueryParam;
24 import javax.ws.rs.core.MediaType;
25 import javax.ws.rs.core.Response;
27 import org.codehaus.enunciate.jaxrs.ResponseCode;
28 import org.codehaus.enunciate.jaxrs.StatusCodes;
29 import org.opendaylight.controller.networkconfig.neutron.INeutronFloatingIPAware;
30 import org.opendaylight.controller.networkconfig.neutron.INeutronFloatingIPCRUD;
31 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
32 import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
33 import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
34 import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
35 import org.opendaylight.controller.networkconfig.neutron.NeutronFloatingIP;
36 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
37 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
38 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
39 import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
42 * Neutron Northbound REST APIs.<br>
43 * This class provides REST APIs for managing Neutron Floating IPs
47 * Authentication scheme : <b>HTTP Basic</b><br>
48 * Authentication realm : <b>opendaylight</b><br>
49 * Transport : <b>HTTP and HTTPS</b><br>
51 * HTTPS Authentication is disabled by default. Administrator can enable it in
52 * tomcat-server.xml after adding a proper keystore / SSL certificate from a
53 * trusted authority.<br>
55 * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
60 public class NeutronFloatingIPsNorthbound {
62 private NeutronFloatingIP extractFields(NeutronFloatingIP o, List<String> fields) {
63 return o.extractFields(fields);
67 * Returns a list of all FloatingIPs */
70 @Produces({ MediaType.APPLICATION_JSON })
72 @ResponseCode(code = 200, condition = "Operation successful"),
73 @ResponseCode(code = 401, condition = "Unauthorized"),
74 @ResponseCode(code = 501, condition = "Not Implemented") })
75 public Response listFloatingIPs(
77 @QueryParam("fields") List<String> fields,
78 // note: openstack isn't clear about filtering on lists, so we aren't handling them
79 @QueryParam("id") String queryID,
80 @QueryParam("floating_network_id") String queryFloatingNetworkId,
81 @QueryParam("port_id") String queryPortId,
82 @QueryParam("fixed_ip_address") String queryFixedIPAddress,
83 @QueryParam("floating_ip_address") String queryFloatingIPAddress,
84 @QueryParam("tenant_id") String queryTenantID,
86 @QueryParam("limit") String limit,
87 @QueryParam("marker") String marker,
88 @QueryParam("page_reverse") String pageReverse
89 // sorting not supported
91 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
92 if (floatingIPInterface == null) {
93 throw new ServiceUnavailableException("Floating IP CRUD Interface "
94 + RestMessages.SERVICEUNAVAILABLE.toString());
96 List<NeutronFloatingIP> allFloatingIPs = floatingIPInterface.getAllFloatingIPs();
97 List<NeutronFloatingIP> ans = new ArrayList<NeutronFloatingIP>();
98 Iterator<NeutronFloatingIP> i = allFloatingIPs.iterator();
100 NeutronFloatingIP oSS = i.next();
101 //match filters: TODO provider extension and router extension
102 if ((queryID == null || queryID.equals(oSS.getID())) &&
103 (queryFloatingNetworkId == null || queryFloatingNetworkId.equals(oSS.getFloatingNetworkUUID())) &&
104 (queryPortId == null || queryPortId.equals(oSS.getPortUUID())) &&
105 (queryFixedIPAddress == null || queryFixedIPAddress.equals(oSS.getFixedIPAddress())) &&
106 (queryFloatingIPAddress == null || queryFloatingIPAddress.equals(oSS.getFloatingIPAddress())) &&
107 (queryTenantID == null || queryTenantID.equals(oSS.getTenantUUID()))) {
108 if (fields.size() > 0)
109 ans.add(extractFields(oSS,fields));
114 //TODO: apply pagination to results
115 return Response.status(200).entity(
116 new NeutronFloatingIPRequest(ans)).build();
120 * Returns a specific FloatingIP */
122 @Path("{floatingipUUID}")
124 @Produces({ MediaType.APPLICATION_JSON })
126 @ResponseCode(code = 200, condition = "Operation successful"),
127 @ResponseCode(code = 401, condition = "Unauthorized"),
128 @ResponseCode(code = 404, condition = "Not Found"),
129 @ResponseCode(code = 501, condition = "Not Implemented") })
130 public Response showFloatingIP(
131 @PathParam("floatingipUUID") String floatingipUUID,
133 @QueryParam("fields") List<String> fields ) {
134 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
135 if (floatingIPInterface == null) {
136 throw new ServiceUnavailableException("Floating IP CRUD Interface "
137 + RestMessages.SERVICEUNAVAILABLE.toString());
139 if (!floatingIPInterface.floatingIPExists(floatingipUUID))
140 throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
141 if (fields.size() > 0) {
142 NeutronFloatingIP ans = floatingIPInterface.getFloatingIP(floatingipUUID);
143 return Response.status(200).entity(
144 new NeutronFloatingIPRequest(extractFields(ans, fields))).build();
146 return Response.status(200).entity(
147 new NeutronFloatingIPRequest(floatingIPInterface.getFloatingIP(floatingipUUID))).build();
152 * Creates new FloatingIPs */
155 @Produces({ MediaType.APPLICATION_JSON })
156 @Consumes({ MediaType.APPLICATION_JSON })
158 @ResponseCode(code = 201, condition = "Created"),
159 @ResponseCode(code = 400, condition = "Bad Request"),
160 @ResponseCode(code = 401, condition = "Unauthorized"),
161 @ResponseCode(code = 409, condition = "Conflict"),
162 @ResponseCode(code = 501, condition = "Not Implemented") })
163 public Response createFloatingIPs(final NeutronFloatingIPRequest input) {
164 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
165 if (floatingIPInterface == null) {
166 throw new ServiceUnavailableException("Floating IP CRUD Interface "
167 + RestMessages.SERVICEUNAVAILABLE.toString());
169 INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
170 if (networkInterface == null) {
171 throw new ServiceUnavailableException("Network CRUD Interface "
172 + RestMessages.SERVICEUNAVAILABLE.toString());
174 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
175 if (subnetInterface == null) {
176 throw new ServiceUnavailableException("Subnet CRUD Interface "
177 + RestMessages.SERVICEUNAVAILABLE.toString());
179 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD( this);
180 if (portInterface == null) {
181 throw new ServiceUnavailableException("Port CRUD Interface "
182 + RestMessages.SERVICEUNAVAILABLE.toString());
184 if (input.isSingleton()) {
185 NeutronFloatingIP singleton = input.getSingleton();
186 // check existence of id in cache and return badrequest if exists
187 if (floatingIPInterface.floatingIPExists(singleton.getID()))
188 throw new BadRequestException("Floating IP UUID already exists.");
189 // check if the external network is specified, exists, and is an external network
190 String externalNetworkUUID = singleton.getFloatingNetworkUUID();
191 if (externalNetworkUUID == null)
192 throw new BadRequestException("external network UUID doesn't exist.");
193 if (!networkInterface.networkExists(externalNetworkUUID))
194 throw new BadRequestException("external network UUID doesn't exist.");
195 NeutronNetwork externNetwork = networkInterface.getNetwork(externalNetworkUUID);
196 if (!externNetwork.isRouterExternal())
197 throw new BadRequestException("external network isn't marked router:external");
198 // if floating IP is specified, make sure it can come from the network
199 String floatingIP = singleton.getFloatingIPAddress();
200 if (floatingIP != null) {
201 if (externNetwork.getSubnets().size() != 1)
202 throw new BadRequestException("external network doesn't have a subnet");
203 NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
204 if (!externSubnet.isValidIP(floatingIP))
205 throw new BadRequestException("external IP isn't valid for the specified subnet.");
206 if (externSubnet.isIPInUse(floatingIP))
207 throw new ResourceConflictException("floating IP is in use.");
209 // if port_id is specified, then check that the port exists and has at least one IP
210 String port_id = singleton.getPortUUID();
211 if (port_id != null) {
212 String fixedIP = null; // used for the fixedIP calculation
213 if (!portInterface.portExists(port_id))
214 throw new ResourceNotFoundException("Port UUID doesn't exist.");
215 NeutronPort port = portInterface.getPort(port_id);
216 if (port.getFixedIPs().size() < 1)
217 throw new BadRequestException("port UUID doesn't have an IP address.");
218 // if there is more than one fixed IP then check for fixed_ip_address
219 // and that it is in the list of port addresses
220 if (port.getFixedIPs().size() > 1) {
221 fixedIP = singleton.getFixedIPAddress();
223 throw new BadRequestException("fixed IP address doesn't exist.");
224 Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
225 boolean validFixedIP = false;
226 while (i.hasNext() && !validFixedIP) {
227 Neutron_IPs ip = i.next();
228 if (ip.getIpAddress().equals(fixedIP))
232 throw new BadRequestException("can't find a valid fixed IP address");
234 fixedIP = port.getFixedIPs().get(0).getIpAddress();
235 if (singleton.getFixedIPAddress() != null && !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
236 throw new BadRequestException("mismatched fixed IP address in request");
238 //lastly check that this fixed IP address isn't already used
239 if (port.isBoundToFloatingIP(fixedIP))
240 throw new ResourceConflictException("fixed IP is in use.");
241 singleton.setFixedIPAddress(fixedIP);
243 Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
244 if (instances != null) {
245 if (instances.length > 0) {
246 for (Object instance : instances) {
247 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
248 int status = service.canCreateFloatingIP(singleton);
249 if (status < 200 || status > 299)
250 return Response.status(status).build();
253 throw new ServiceUnavailableException("No providers registered. Please try again later");
256 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
258 floatingIPInterface.addFloatingIP(singleton);
259 if (instances != null) {
260 for (Object instance : instances) {
261 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
262 service.neutronFloatingIPCreated(singleton);
266 throw new BadRequestException("only singleton requests allowed.");
268 return Response.status(201).entity(input).build();
272 * Updates a FloatingIP */
274 @Path("{floatingipUUID}")
276 @Produces({ MediaType.APPLICATION_JSON })
277 @Consumes({ MediaType.APPLICATION_JSON })
279 @ResponseCode(code = 200, condition = "Operation successful"),
280 @ResponseCode(code = 400, condition = "Bad Request"),
281 @ResponseCode(code = 401, condition = "Unauthorized"),
282 @ResponseCode(code = 404, condition = "Not Found"),
283 @ResponseCode(code = 409, condition = "Conflict"),
284 @ResponseCode(code = 501, condition = "Not Implemented") })
285 public Response updateFloatingIP(
286 @PathParam("floatingipUUID") String floatingipUUID,
287 NeutronFloatingIPRequest input
289 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
290 if (floatingIPInterface == null) {
291 throw new ServiceUnavailableException("Floating IP CRUD Interface "
292 + RestMessages.SERVICEUNAVAILABLE.toString());
294 INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
295 if (networkInterface == null) {
296 throw new ServiceUnavailableException("Network CRUD Interface "
297 + RestMessages.SERVICEUNAVAILABLE.toString());
299 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
300 if (subnetInterface == null) {
301 throw new ServiceUnavailableException("Subnet CRUD Interface "
302 + RestMessages.SERVICEUNAVAILABLE.toString());
304 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD( this);
305 if (portInterface == null) {
306 throw new ServiceUnavailableException("Port CRUD Interface "
307 + RestMessages.SERVICEUNAVAILABLE.toString());
309 if (!floatingIPInterface.floatingIPExists(floatingipUUID))
310 throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
312 NeutronFloatingIP sourceFloatingIP = floatingIPInterface.getFloatingIP(floatingipUUID);
313 if (!input.isSingleton())
314 throw new BadRequestException("only singleton requests allowed.");
315 NeutronFloatingIP singleton = input.getSingleton();
316 if (singleton.getID() == null)
317 throw new BadRequestException("singleton UUID doesn't exist.");
319 NeutronNetwork externNetwork = networkInterface.getNetwork(
320 sourceFloatingIP.getFloatingNetworkUUID());
322 // if floating IP is specified, make sure it can come from the network
323 String floatingIP = singleton.getFloatingIPAddress();
324 if (floatingIP != null) {
325 if (externNetwork.getSubnets().size() != 1)
326 throw new BadRequestException("external network doesn't have a subnet.");
327 NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
328 if (!externSubnet.isValidIP(floatingIP))
329 throw new BadRequestException("floating IP not valid for external subnet");
330 if (externSubnet.isIPInUse(floatingIP))
331 throw new ResourceConflictException("floating IP is in use.");
334 // if port_id is specified, then check that the port exists and has at least one IP
335 String port_id = singleton.getPortUUID();
336 if (port_id != null) {
337 String fixedIP = null; // used for the fixedIP calculation
338 if (!portInterface.portExists(port_id))
339 throw new ResourceNotFoundException("Port UUID doesn't exist.");
340 NeutronPort port = portInterface.getPort(port_id);
341 if (port.getFixedIPs().size() < 1)
342 throw new BadRequestException("port ID doesn't have a fixed IP address.");
343 // if there is more than one fixed IP then check for fixed_ip_address
344 // and that it is in the list of port addresses
345 if (port.getFixedIPs().size() > 1) {
346 fixedIP = singleton.getFixedIPAddress();
348 throw new BadRequestException("request doesn't have a fixed IP address");
349 Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
350 boolean validFixedIP = false;
351 while (i.hasNext() && !validFixedIP) {
352 Neutron_IPs ip = i.next();
353 if (ip.getIpAddress().equals(fixedIP))
357 throw new BadRequestException("couldn't find a valid fixed IP address");
359 fixedIP = port.getFixedIPs().get(0).getIpAddress();
360 if (singleton.getFixedIPAddress() != null &&
361 !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
362 throw new BadRequestException("mismatch in fixed IP addresses");
364 //lastly check that this fixed IP address isn't already used
365 if (port.isBoundToFloatingIP(fixedIP))
366 throw new ResourceConflictException("fixed IP is in use.");
367 singleton.setFixedIPAddress(fixedIP);
369 NeutronFloatingIP target = floatingIPInterface.getFloatingIP(floatingipUUID);
370 Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
371 if (instances != null) {
372 if (instances.length > 0) {
373 for (Object instance : instances) {
374 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
375 int status = service.canUpdateFloatingIP(singleton, target);
376 if (status < 200 || status > 299)
377 return Response.status(status).build();
380 throw new ServiceUnavailableException("No providers registered. Please try again later");
383 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
385 floatingIPInterface.updateFloatingIP(floatingipUUID, singleton);
386 target = floatingIPInterface.getFloatingIP(floatingipUUID);
387 if (instances != null) {
388 for (Object instance : instances) {
389 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
390 service.neutronFloatingIPUpdated(target);
393 return Response.status(200).entity(
394 new NeutronFloatingIPRequest(target)).build();
399 * Deletes a FloatingIP */
401 @Path("{floatingipUUID}")
404 @ResponseCode(code = 204, condition = "No Content"),
405 @ResponseCode(code = 401, condition = "Unauthorized"),
406 @ResponseCode(code = 404, condition = "Not Found"),
407 @ResponseCode(code = 501, condition = "Not Implemented") })
408 public Response deleteFloatingIP(
409 @PathParam("floatingipUUID") String floatingipUUID) {
410 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
411 if (floatingIPInterface == null) {
412 throw new ServiceUnavailableException("Floating IP CRUD Interface "
413 + RestMessages.SERVICEUNAVAILABLE.toString());
415 if (!floatingIPInterface.floatingIPExists(floatingipUUID))
416 throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
417 // TODO: need to undo port association if it exists
418 NeutronFloatingIP singleton = floatingIPInterface.getFloatingIP(floatingipUUID);
419 Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
420 if (instances != null) {
421 if (instances.length > 0) {
422 for (Object instance : instances) {
423 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
424 int status = service.canDeleteFloatingIP(singleton);
425 if (status < 200 || status > 299)
426 return Response.status(status).build();
429 throw new ServiceUnavailableException("No providers registered. Please try again later");
432 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
434 floatingIPInterface.removeFloatingIP(floatingipUUID);
435 if (instances != null) {
436 for (Object instance : instances) {
437 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
438 service.neutronFloatingIPDeleted(singleton);
441 return Response.status(204).build();