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.neutron.northbound.api;
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.neutron.spi.INeutronFloatingIPAware;
30 import org.opendaylight.neutron.spi.INeutronFloatingIPCRUD;
31 import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
32 import org.opendaylight.neutron.spi.INeutronPortCRUD;
33 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
34 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
35 import org.opendaylight.neutron.spi.NeutronFloatingIP;
36 import org.opendaylight.neutron.spi.NeutronNetwork;
37 import org.opendaylight.neutron.spi.NeutronPort;
38 import org.opendaylight.neutron.spi.NeutronSubnet;
39 import org.opendaylight.neutron.spi.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 @ResponseCode(code = 503, condition = "No providers available") })
76 public Response listFloatingIPs(
78 @QueryParam("fields") List<String> fields,
79 // note: openstack isn't clear about filtering on lists, so we aren't handling them
80 @QueryParam("id") String queryID,
81 @QueryParam("floating_network_id") String queryFloatingNetworkId,
82 @QueryParam("port_id") String queryPortId,
83 @QueryParam("fixed_ip_address") String queryFixedIPAddress,
84 @QueryParam("floating_ip_address") String queryFloatingIPAddress,
85 @QueryParam("tenant_id") String queryTenantID,
86 @QueryParam("router_id") String queryRouterID,
87 @QueryParam("status") String queryStatus,
89 @QueryParam("limit") String limit,
90 @QueryParam("marker") String marker,
91 @QueryParam("page_reverse") String pageReverse
92 // sorting not supported
94 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
95 if (floatingIPInterface == null) {
96 throw new ServiceUnavailableException("Floating IP CRUD Interface "
97 + RestMessages.SERVICEUNAVAILABLE.toString());
99 List<NeutronFloatingIP> allFloatingIPs = floatingIPInterface.getAllFloatingIPs();
100 List<NeutronFloatingIP> ans = new ArrayList<NeutronFloatingIP>();
101 Iterator<NeutronFloatingIP> i = allFloatingIPs.iterator();
102 while (i.hasNext()) {
103 NeutronFloatingIP oSS = i.next();
104 //match filters: TODO provider extension and router extension
105 if ((queryID == null || queryID.equals(oSS.getID())) &&
106 (queryFloatingNetworkId == null || queryFloatingNetworkId.equals(oSS.getFloatingNetworkUUID())) &&
107 (queryPortId == null || queryPortId.equals(oSS.getPortUUID())) &&
108 (queryFixedIPAddress == null || queryFixedIPAddress.equals(oSS.getFixedIPAddress())) &&
109 (queryFloatingIPAddress == null || queryFloatingIPAddress.equals(oSS.getFloatingIPAddress())) &&
110 (queryStatus == null || queryStatus.equals(oSS.getStatus())) &&
111 (queryRouterID == null || queryRouterID.equals(oSS.getRouterUUID())) &&
112 (queryTenantID == null || queryTenantID.equals(oSS.getTenantUUID()))) {
113 if (fields.size() > 0)
114 ans.add(extractFields(oSS,fields));
119 //TODO: apply pagination to results
120 return Response.status(200).entity(
121 new NeutronFloatingIPRequest(ans)).build();
125 * Returns a specific FloatingIP */
127 @Path("{floatingipUUID}")
129 @Produces({ MediaType.APPLICATION_JSON })
131 @ResponseCode(code = 200, condition = "Operation successful"),
132 @ResponseCode(code = 401, condition = "Unauthorized"),
133 @ResponseCode(code = 404, condition = "Not Found"),
134 @ResponseCode(code = 501, condition = "Not Implemented"),
135 @ResponseCode(code = 503, condition = "No providers available") })
136 public Response showFloatingIP(
137 @PathParam("floatingipUUID") String floatingipUUID,
139 @QueryParam("fields") List<String> fields ) {
140 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
141 if (floatingIPInterface == null) {
142 throw new ServiceUnavailableException("Floating IP CRUD Interface "
143 + RestMessages.SERVICEUNAVAILABLE.toString());
145 if (!floatingIPInterface.floatingIPExists(floatingipUUID))
146 throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
147 if (fields.size() > 0) {
148 NeutronFloatingIP ans = floatingIPInterface.getFloatingIP(floatingipUUID);
149 return Response.status(200).entity(
150 new NeutronFloatingIPRequest(extractFields(ans, fields))).build();
152 return Response.status(200).entity(
153 new NeutronFloatingIPRequest(floatingIPInterface.getFloatingIP(floatingipUUID))).build();
158 * Creates new FloatingIPs */
161 @Produces({ MediaType.APPLICATION_JSON })
162 @Consumes({ MediaType.APPLICATION_JSON })
164 @ResponseCode(code = 201, condition = "Created"),
165 @ResponseCode(code = 400, condition = "Bad Request"),
166 @ResponseCode(code = 401, condition = "Unauthorized"),
167 @ResponseCode(code = 409, condition = "Conflict"),
168 @ResponseCode(code = 501, condition = "Not Implemented"),
169 @ResponseCode(code = 503, condition = "No providers available") })
170 public Response createFloatingIPs(final NeutronFloatingIPRequest input) {
171 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
172 if (floatingIPInterface == null) {
173 throw new ServiceUnavailableException("Floating IP CRUD Interface "
174 + RestMessages.SERVICEUNAVAILABLE.toString());
176 INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
177 if (networkInterface == null) {
178 throw new ServiceUnavailableException("Network CRUD Interface "
179 + RestMessages.SERVICEUNAVAILABLE.toString());
181 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
182 if (subnetInterface == null) {
183 throw new ServiceUnavailableException("Subnet CRUD Interface "
184 + RestMessages.SERVICEUNAVAILABLE.toString());
186 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD( this);
187 if (portInterface == null) {
188 throw new ServiceUnavailableException("Port CRUD Interface "
189 + RestMessages.SERVICEUNAVAILABLE.toString());
191 if (input.isSingleton()) {
192 NeutronFloatingIP singleton = input.getSingleton();
193 // check existence of id in cache and return badrequest if exists
194 if (floatingIPInterface.floatingIPExists(singleton.getID()))
195 throw new BadRequestException("Floating IP UUID already exists.");
196 // check if the external network is specified, exists, and is an external network
197 String externalNetworkUUID = singleton.getFloatingNetworkUUID();
198 if (externalNetworkUUID == null)
199 throw new BadRequestException("external network UUID doesn't exist.");
200 if (!networkInterface.networkExists(externalNetworkUUID))
201 throw new BadRequestException("external network UUID doesn't exist.");
202 NeutronNetwork externNetwork = networkInterface.getNetwork(externalNetworkUUID);
203 if (!externNetwork.isRouterExternal())
204 throw new BadRequestException("external network isn't marked router:external");
205 // if floating IP is specified, make sure it can come from the network
206 String floatingIP = singleton.getFloatingIPAddress();
207 if (floatingIP != null) {
208 if (externNetwork.getSubnets().size() != 1)
209 throw new BadRequestException("external network doesn't have a subnet");
210 NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
211 if (!externSubnet.isValidIP(floatingIP))
212 throw new BadRequestException("external IP isn't valid for the specified subnet.");
213 if (externSubnet.isIPInUse(floatingIP))
214 throw new ResourceConflictException("floating IP is in use.");
216 // if port_id is specified, then check that the port exists and has at least one IP
217 String port_id = singleton.getPortUUID();
218 if (port_id != null) {
219 String fixedIP = null; // used for the fixedIP calculation
220 if (!portInterface.portExists(port_id))
221 throw new ResourceNotFoundException("Port UUID doesn't exist.");
222 NeutronPort port = portInterface.getPort(port_id);
223 if (port.getFixedIPs().size() < 1)
224 throw new BadRequestException("port UUID doesn't have an IP address.");
225 // if there is more than one fixed IP then check for fixed_ip_address
226 // and that it is in the list of port addresses
227 if (port.getFixedIPs().size() > 1) {
228 fixedIP = singleton.getFixedIPAddress();
230 throw new BadRequestException("fixed IP address doesn't exist.");
231 Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
232 boolean validFixedIP = false;
233 while (i.hasNext() && !validFixedIP) {
234 Neutron_IPs ip = i.next();
235 if (ip.getIpAddress().equals(fixedIP))
239 throw new BadRequestException("can't find a valid fixed IP address");
241 fixedIP = port.getFixedIPs().get(0).getIpAddress();
242 if (singleton.getFixedIPAddress() != null && !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
243 throw new BadRequestException("mismatched fixed IP address in request");
245 //lastly check that this fixed IP address isn't already used
246 if (port.isBoundToFloatingIP(fixedIP))
247 throw new ResourceConflictException("fixed IP is in use.");
248 singleton.setFixedIPAddress(fixedIP);
250 Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
251 if (instances != null) {
252 if (instances.length > 0) {
253 for (Object instance : instances) {
254 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
255 int status = service.canCreateFloatingIP(singleton);
256 if (status < 200 || status > 299)
257 return Response.status(status).build();
260 throw new ServiceUnavailableException("No providers registered. Please try again later");
263 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
265 floatingIPInterface.addFloatingIP(singleton);
266 if (instances != null) {
267 for (Object instance : instances) {
268 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
269 service.neutronFloatingIPCreated(singleton);
273 throw new BadRequestException("only singleton requests allowed.");
275 return Response.status(201).entity(input).build();
279 * Updates a FloatingIP */
281 @Path("{floatingipUUID}")
283 @Produces({ MediaType.APPLICATION_JSON })
284 @Consumes({ MediaType.APPLICATION_JSON })
286 @ResponseCode(code = 200, condition = "Operation successful"),
287 @ResponseCode(code = 400, condition = "Bad Request"),
288 @ResponseCode(code = 401, condition = "Unauthorized"),
289 @ResponseCode(code = 404, condition = "Not Found"),
290 @ResponseCode(code = 409, condition = "Conflict"),
291 @ResponseCode(code = 501, condition = "Not Implemented"),
292 @ResponseCode(code = 503, condition = "No providers available") })
293 public Response updateFloatingIP(
294 @PathParam("floatingipUUID") String floatingipUUID,
295 NeutronFloatingIPRequest input
297 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
298 if (floatingIPInterface == null) {
299 throw new ServiceUnavailableException("Floating IP CRUD Interface "
300 + RestMessages.SERVICEUNAVAILABLE.toString());
302 INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
303 if (networkInterface == null) {
304 throw new ServiceUnavailableException("Network CRUD Interface "
305 + RestMessages.SERVICEUNAVAILABLE.toString());
307 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
308 if (subnetInterface == null) {
309 throw new ServiceUnavailableException("Subnet CRUD Interface "
310 + RestMessages.SERVICEUNAVAILABLE.toString());
312 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD( this);
313 if (portInterface == null) {
314 throw new ServiceUnavailableException("Port CRUD Interface "
315 + RestMessages.SERVICEUNAVAILABLE.toString());
317 if (!floatingIPInterface.floatingIPExists(floatingipUUID))
318 throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
320 NeutronFloatingIP sourceFloatingIP = floatingIPInterface.getFloatingIP(floatingipUUID);
321 if (!input.isSingleton())
322 throw new BadRequestException("only singleton requests allowed.");
323 NeutronFloatingIP singleton = input.getSingleton();
324 if (singleton.getID() == null)
325 throw new BadRequestException("singleton UUID doesn't exist.");
327 NeutronNetwork externNetwork = networkInterface.getNetwork(
328 sourceFloatingIP.getFloatingNetworkUUID());
330 // if floating IP is specified, make sure it can come from the network
331 String floatingIP = singleton.getFloatingIPAddress();
332 if (floatingIP != null) {
333 if (externNetwork.getSubnets().size() != 1)
334 throw new BadRequestException("external network doesn't have a subnet.");
335 NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
336 if (!externSubnet.isValidIP(floatingIP))
337 throw new BadRequestException("floating IP not valid for external subnet");
338 if (externSubnet.isIPInUse(floatingIP))
339 throw new ResourceConflictException("floating IP is in use.");
342 // if port_id is specified, then check that the port exists and has at least one IP
343 String port_id = singleton.getPortUUID();
344 if (port_id != null) {
345 String fixedIP = null; // used for the fixedIP calculation
346 if (!portInterface.portExists(port_id))
347 throw new ResourceNotFoundException("Port UUID doesn't exist.");
348 NeutronPort port = portInterface.getPort(port_id);
349 if (port.getFixedIPs().size() < 1)
350 throw new BadRequestException("port ID doesn't have a fixed IP address.");
351 // if there is more than one fixed IP then check for fixed_ip_address
352 // and that it is in the list of port addresses
353 if (port.getFixedIPs().size() > 1) {
354 fixedIP = singleton.getFixedIPAddress();
356 throw new BadRequestException("request doesn't have a fixed IP address");
357 Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
358 boolean validFixedIP = false;
359 while (i.hasNext() && !validFixedIP) {
360 Neutron_IPs ip = i.next();
361 if (ip.getIpAddress().equals(fixedIP))
365 throw new BadRequestException("couldn't find a valid fixed IP address");
367 fixedIP = port.getFixedIPs().get(0).getIpAddress();
368 if (singleton.getFixedIPAddress() != null &&
369 !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
370 throw new BadRequestException("mismatch in fixed IP addresses");
372 //lastly check that this fixed IP address isn't already used
373 if (port.isBoundToFloatingIP(fixedIP))
374 throw new ResourceConflictException("fixed IP is in use.");
375 singleton.setFixedIPAddress(fixedIP);
377 NeutronFloatingIP target = floatingIPInterface.getFloatingIP(floatingipUUID);
378 Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
379 if (instances != null) {
380 if (instances.length > 0) {
381 for (Object instance : instances) {
382 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
383 int status = service.canUpdateFloatingIP(singleton, target);
384 if (status < 200 || status > 299)
385 return Response.status(status).build();
388 throw new ServiceUnavailableException("No providers registered. Please try again later");
391 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
393 floatingIPInterface.updateFloatingIP(floatingipUUID, singleton);
394 target = floatingIPInterface.getFloatingIP(floatingipUUID);
395 if (instances != null) {
396 for (Object instance : instances) {
397 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
398 service.neutronFloatingIPUpdated(target);
401 return Response.status(200).entity(
402 new NeutronFloatingIPRequest(target)).build();
407 * Deletes a FloatingIP */
409 @Path("{floatingipUUID}")
412 @ResponseCode(code = 204, condition = "No Content"),
413 @ResponseCode(code = 401, condition = "Unauthorized"),
414 @ResponseCode(code = 404, condition = "Not Found"),
415 @ResponseCode(code = 501, condition = "Not Implemented"),
416 @ResponseCode(code = 503, condition = "No providers available") })
417 public Response deleteFloatingIP(
418 @PathParam("floatingipUUID") String floatingipUUID) {
419 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
420 if (floatingIPInterface == null) {
421 throw new ServiceUnavailableException("Floating IP CRUD Interface "
422 + RestMessages.SERVICEUNAVAILABLE.toString());
424 if (!floatingIPInterface.floatingIPExists(floatingipUUID))
425 throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
426 // TODO: need to undo port association if it exists
427 NeutronFloatingIP singleton = floatingIPInterface.getFloatingIP(floatingipUUID);
428 Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
429 if (instances != null) {
430 if (instances.length > 0) {
431 for (Object instance : instances) {
432 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
433 int status = service.canDeleteFloatingIP(singleton);
434 if (status < 200 || status > 299)
435 return Response.status(status).build();
438 throw new ServiceUnavailableException("No providers registered. Please try again later");
441 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
443 floatingIPInterface.removeFloatingIP(floatingipUUID);
444 if (instances != null) {
445 for (Object instance : instances) {
446 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
447 service.neutronFloatingIPDeleted(singleton);
450 return Response.status(204).build();