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 for (Object instance : instances) {
246 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
247 int status = service.canCreateFloatingIP(singleton);
248 if (status < 200 || status > 299)
249 return Response.status(status).build();
252 floatingIPInterface.addFloatingIP(singleton);
253 if (instances != null) {
254 for (Object instance : instances) {
255 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
256 service.neutronFloatingIPCreated(singleton);
260 throw new BadRequestException("only singleton requests allowed.");
262 return Response.status(201).entity(input).build();
266 * Updates a FloatingIP */
268 @Path("{floatingipUUID}")
270 @Produces({ MediaType.APPLICATION_JSON })
271 @Consumes({ MediaType.APPLICATION_JSON })
273 @ResponseCode(code = 200, condition = "Operation successful"),
274 @ResponseCode(code = 400, condition = "Bad Request"),
275 @ResponseCode(code = 401, condition = "Unauthorized"),
276 @ResponseCode(code = 404, condition = "Not Found"),
277 @ResponseCode(code = 409, condition = "Conflict"),
278 @ResponseCode(code = 501, condition = "Not Implemented") })
279 public Response updateFloatingIP(
280 @PathParam("floatingipUUID") String floatingipUUID,
281 NeutronFloatingIPRequest input
283 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
284 if (floatingIPInterface == null) {
285 throw new ServiceUnavailableException("Floating IP CRUD Interface "
286 + RestMessages.SERVICEUNAVAILABLE.toString());
288 INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
289 if (networkInterface == null) {
290 throw new ServiceUnavailableException("Network CRUD Interface "
291 + RestMessages.SERVICEUNAVAILABLE.toString());
293 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
294 if (subnetInterface == null) {
295 throw new ServiceUnavailableException("Subnet CRUD Interface "
296 + RestMessages.SERVICEUNAVAILABLE.toString());
298 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD( this);
299 if (portInterface == null) {
300 throw new ServiceUnavailableException("Port CRUD Interface "
301 + RestMessages.SERVICEUNAVAILABLE.toString());
303 if (!floatingIPInterface.floatingIPExists(floatingipUUID))
304 throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
306 NeutronFloatingIP sourceFloatingIP = floatingIPInterface.getFloatingIP(floatingipUUID);
307 if (!input.isSingleton())
308 throw new BadRequestException("only singleton requests allowed.");
309 NeutronFloatingIP singleton = input.getSingleton();
310 if (singleton.getID() == null)
311 throw new BadRequestException("singleton UUID doesn't exist.");
313 NeutronNetwork externNetwork = networkInterface.getNetwork(
314 sourceFloatingIP.getFloatingNetworkUUID());
316 // if floating IP is specified, make sure it can come from the network
317 String floatingIP = singleton.getFloatingIPAddress();
318 if (floatingIP != null) {
319 if (externNetwork.getSubnets().size() != 1)
320 throw new BadRequestException("external network doesn't have a subnet.");
321 NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
322 if (!externSubnet.isValidIP(floatingIP))
323 throw new BadRequestException("floating IP not valid for external subnet");
324 if (externSubnet.isIPInUse(floatingIP))
325 throw new ResourceConflictException("floating IP is in use.");
328 // if port_id is specified, then check that the port exists and has at least one IP
329 String port_id = singleton.getPortUUID();
330 if (port_id != null) {
331 String fixedIP = null; // used for the fixedIP calculation
332 if (!portInterface.portExists(port_id))
333 throw new ResourceNotFoundException("Port UUID doesn't exist.");
334 NeutronPort port = portInterface.getPort(port_id);
335 if (port.getFixedIPs().size() < 1)
336 throw new BadRequestException("port ID doesn't have a fixed IP address.");
337 // if there is more than one fixed IP then check for fixed_ip_address
338 // and that it is in the list of port addresses
339 if (port.getFixedIPs().size() > 1) {
340 fixedIP = singleton.getFixedIPAddress();
342 throw new BadRequestException("request doesn't have a fixed IP address");
343 Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
344 boolean validFixedIP = false;
345 while (i.hasNext() && !validFixedIP) {
346 Neutron_IPs ip = i.next();
347 if (ip.getIpAddress().equals(fixedIP))
351 throw new BadRequestException("couldn't find a valid fixed IP address");
353 fixedIP = port.getFixedIPs().get(0).getIpAddress();
354 if (singleton.getFixedIPAddress() != null &&
355 !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
356 throw new BadRequestException("mismatch in fixed IP addresses");
358 //lastly check that this fixed IP address isn't already used
359 if (port.isBoundToFloatingIP(fixedIP))
360 throw new ResourceConflictException("fixed IP is in use.");
361 singleton.setFixedIPAddress(fixedIP);
363 NeutronFloatingIP target = floatingIPInterface.getFloatingIP(floatingipUUID);
364 Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
365 if (instances != null) {
366 for (Object instance : instances) {
367 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
368 int status = service.canUpdateFloatingIP(singleton, target);
369 if (status < 200 || status > 299)
370 return Response.status(status).build();
373 floatingIPInterface.updateFloatingIP(floatingipUUID, singleton);
374 target = floatingIPInterface.getFloatingIP(floatingipUUID);
375 if (instances != null) {
376 for (Object instance : instances) {
377 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
378 service.neutronFloatingIPUpdated(target);
381 return Response.status(200).entity(
382 new NeutronFloatingIPRequest(target)).build();
387 * Deletes a FloatingIP */
389 @Path("{floatingipUUID}")
392 @ResponseCode(code = 204, condition = "No Content"),
393 @ResponseCode(code = 401, condition = "Unauthorized"),
394 @ResponseCode(code = 404, condition = "Not Found"),
395 @ResponseCode(code = 501, condition = "Not Implemented") })
396 public Response deleteFloatingIP(
397 @PathParam("floatingipUUID") String floatingipUUID) {
398 INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
399 if (floatingIPInterface == null) {
400 throw new ServiceUnavailableException("Floating IP CRUD Interface "
401 + RestMessages.SERVICEUNAVAILABLE.toString());
403 if (!floatingIPInterface.floatingIPExists(floatingipUUID))
404 throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
405 // TODO: need to undo port association if it exists
406 NeutronFloatingIP singleton = floatingIPInterface.getFloatingIP(floatingipUUID);
407 Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
408 if (instances != null) {
409 for (Object instance : instances) {
410 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
411 int status = service.canDeleteFloatingIP(singleton);
412 if (status < 200 || status > 299)
413 return Response.status(status).build();
416 floatingIPInterface.removeFloatingIP(floatingipUUID);
417 if (instances != null) {
418 for (Object instance : instances) {
419 INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
420 service.neutronFloatingIPDeleted(singleton);
423 return Response.status(204).build();