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.INeutronNetworkCRUD;
30 import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
31 import org.opendaylight.controller.networkconfig.neutron.INeutronRouterAware;
32 import org.opendaylight.controller.networkconfig.neutron.INeutronRouterCRUD;
33 import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
34 import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
35 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
36 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
37 import org.opendaylight.controller.networkconfig.neutron.NeutronRouter;
38 import org.opendaylight.controller.networkconfig.neutron.NeutronRouter_Interface;
39 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
43 * Neutron Northbound REST APIs.<br>
44 * This class provides REST APIs for managing neutron routers
48 * Authentication scheme : <b>HTTP Basic</b><br>
49 * Authentication realm : <b>opendaylight</b><br>
50 * Transport : <b>HTTP and HTTPS</b><br>
52 * HTTPS Authentication is disabled by default. Administrator can enable it in
53 * tomcat-server.xml after adding a proper keystore / SSL certificate from a
54 * trusted authority.<br>
56 * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
61 public class NeutronRoutersNorthbound {
63 private NeutronRouter extractFields(NeutronRouter o, List<String> fields) {
64 return o.extractFields(fields);
68 * Returns a list of all Routers */
71 @Produces({ MediaType.APPLICATION_JSON })
72 //@TypeHint(OpenStackRouters.class)
74 @ResponseCode(code = 200, condition = "Operation successful"),
75 @ResponseCode(code = 401, condition = "Unauthorized"),
76 @ResponseCode(code = 501, condition = "Not Implemented") })
77 public Response listRouters(
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("name") String queryName,
83 @QueryParam("admin_state_up") String queryAdminStateUp,
84 @QueryParam("status") String queryStatus,
85 @QueryParam("tenant_id") String queryTenantID,
86 @QueryParam("external_gateway_info") String queryExternalGatewayInfo,
88 @QueryParam("limit") String limit,
89 @QueryParam("marker") String marker,
90 @QueryParam("page_reverse") String pageReverse
91 // sorting not supported
93 INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
94 if (routerInterface == null) {
95 throw new ServiceUnavailableException("Router CRUD Interface "
96 + RestMessages.SERVICEUNAVAILABLE.toString());
98 List<NeutronRouter> allRouters = routerInterface.getAllRouters();
99 List<NeutronRouter> ans = new ArrayList<NeutronRouter>();
100 Iterator<NeutronRouter> i = allRouters.iterator();
101 while (i.hasNext()) {
102 NeutronRouter oSS = i.next();
103 if ((queryID == null || queryID.equals(oSS.getID())) &&
104 (queryName == null || queryName.equals(oSS.getName())) &&
105 (queryAdminStateUp == null || queryAdminStateUp.equals(oSS.getAdminStateUp())) &&
106 (queryStatus == null || queryStatus.equals(oSS.getStatus())) &&
107 (queryExternalGatewayInfo == null || queryExternalGatewayInfo.equals(oSS.getExternalGatewayInfo())) &&
108 (queryTenantID == null || queryTenantID.equals(oSS.getTenantID()))) {
109 if (fields.size() > 0)
110 ans.add(extractFields(oSS,fields));
115 //TODO: apply pagination to results
116 return Response.status(200).entity(
117 new NeutronRouterRequest(ans)).build();
121 * Returns a specific Router */
123 @Path("{routerUUID}")
125 @Produces({ MediaType.APPLICATION_JSON })
126 //@TypeHint(OpenStackRouters.class)
128 @ResponseCode(code = 200, condition = "Operation successful"),
129 @ResponseCode(code = 401, condition = "Unauthorized"),
130 @ResponseCode(code = 403, condition = "Forbidden"),
131 @ResponseCode(code = 404, condition = "Not Found"),
132 @ResponseCode(code = 501, condition = "Not Implemented") })
133 public Response showRouter(
134 @PathParam("routerUUID") String routerUUID,
136 @QueryParam("fields") List<String> fields) {
137 INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
138 if (routerInterface == null) {
139 throw new ServiceUnavailableException("Router CRUD Interface "
140 + RestMessages.SERVICEUNAVAILABLE.toString());
142 if (!routerInterface.routerExists(routerUUID)) {
143 throw new ResourceNotFoundException("Router UUID not found");
145 if (fields.size() > 0) {
146 NeutronRouter ans = routerInterface.getRouter(routerUUID);
147 return Response.status(200).entity(
148 new NeutronRouterRequest(extractFields(ans, fields))).build();
150 return Response.status(200).entity(
151 new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
155 * Creates new Routers */
158 @Produces({ MediaType.APPLICATION_JSON })
159 @Consumes({ MediaType.APPLICATION_JSON })
160 //@TypeHint(OpenStackRouters.class)
162 @ResponseCode(code = 201, condition = "Created"),
163 @ResponseCode(code = 400, condition = "Bad Request"),
164 @ResponseCode(code = 401, condition = "Unauthorized"),
165 @ResponseCode(code = 501, condition = "Not Implemented") })
166 public Response createRouters(final NeutronRouterRequest input) {
167 INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
168 if (routerInterface == null) {
169 throw new ServiceUnavailableException("Router CRUD Interface "
170 + RestMessages.SERVICEUNAVAILABLE.toString());
172 INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
173 if (networkInterface == null) {
174 throw new ServiceUnavailableException("Network CRUD Interface "
175 + RestMessages.SERVICEUNAVAILABLE.toString());
177 if (input.isSingleton()) {
178 NeutronRouter singleton = input.getSingleton();
181 * verify that the router doesn't already exist (issue: is deeper inspection necessary?)
182 * if there is external gateway information provided, verify that the specified network
183 * exists and has been designated as "router:external"
185 if (routerInterface.routerExists(singleton.getID()))
186 throw new BadRequestException("router UUID already exists");
187 if (singleton.getExternalGatewayInfo() != null) {
188 String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
189 if (!networkInterface.networkExists(externNetworkPtr))
190 throw new BadRequestException("External Network Pointer doesn't exist");
191 NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
192 if (!externNetwork.isRouterExternal())
193 throw new BadRequestException("External Network Pointer isn't marked as router:external");
195 Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
196 if (instances != null) {
197 if (instances.length > 0) {
198 for (Object instance : instances) {
199 INeutronRouterAware service = (INeutronRouterAware) instance;
200 int status = service.canCreateRouter(singleton);
201 if (status < 200 || status > 299)
202 return Response.status(status).build();
205 throw new ServiceUnavailableException("No providers registered. Please try again later");
208 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
212 * add router to the cache
214 routerInterface.addRouter(singleton);
215 if (instances != null) {
216 for (Object instance : instances) {
217 INeutronRouterAware service = (INeutronRouterAware) instance;
218 service.neutronRouterCreated(singleton);
224 * only singleton router creates supported
226 throw new BadRequestException("Only singleton router creates supported");
228 return Response.status(201).entity(input).build();
232 * Updates a Router */
234 @Path("{routerUUID}")
236 @Produces({ MediaType.APPLICATION_JSON })
237 @Consumes({ MediaType.APPLICATION_JSON })
238 //@TypeHint(OpenStackRouters.class)
240 @ResponseCode(code = 200, condition = "Operation successful"),
241 @ResponseCode(code = 400, condition = "Bad Request"),
242 @ResponseCode(code = 401, condition = "Unauthorized"),
243 @ResponseCode(code = 404, condition = "Not Found"),
244 @ResponseCode(code = 501, condition = "Not Implemented") })
245 public Response updateRouter(
246 @PathParam("routerUUID") String routerUUID,
247 NeutronRouterRequest input
249 INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
250 if (routerInterface == null) {
251 throw new ServiceUnavailableException("Router CRUD Interface "
252 + RestMessages.SERVICEUNAVAILABLE.toString());
254 INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
255 if (networkInterface == null) {
256 throw new ServiceUnavailableException("Network CRUD Interface "
257 + RestMessages.SERVICEUNAVAILABLE.toString());
261 * router has to exist and only a single delta can be supplied
263 if (!routerInterface.routerExists(routerUUID))
264 throw new ResourceNotFoundException("Router UUID not found");
265 if (!input.isSingleton())
266 throw new BadRequestException("Only single router deltas supported");
267 NeutronRouter singleton = input.getSingleton();
268 NeutronRouter original = routerInterface.getRouter(routerUUID);
271 * attribute changes blocked by Neutron
273 if (singleton.getID() != null || singleton.getTenantID() != null ||
274 singleton.getStatus() != null)
275 throw new BadRequestException("Request attribute change not allowed");
277 Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
278 if (instances != null) {
279 if (instances.length > 0) {
280 for (Object instance : instances) {
281 INeutronRouterAware service = (INeutronRouterAware) instance;
282 int status = service.canUpdateRouter(singleton, original);
283 if (status < 200 || status > 299)
284 return Response.status(status).build();
287 throw new ServiceUnavailableException("No providers registered. Please try again later");
290 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
293 * if the external gateway info is being changed, verify that the new network
294 * exists and has been designated as an external network
296 if (singleton.getExternalGatewayInfo() != null) {
297 String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
298 if (!networkInterface.networkExists(externNetworkPtr))
299 throw new BadRequestException("External Network Pointer does not exist");
300 NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
301 if (!externNetwork.isRouterExternal())
302 throw new BadRequestException("External Network Pointer isn't marked as router:external");
306 * update the router entry and return the modified object
308 routerInterface.updateRouter(routerUUID, singleton);
309 NeutronRouter updatedRouter = routerInterface.getRouter(routerUUID);
310 if (instances != null) {
311 for (Object instance : instances) {
312 INeutronRouterAware service = (INeutronRouterAware) instance;
313 service.neutronRouterUpdated(updatedRouter);
316 return Response.status(200).entity(
317 new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
322 * Deletes a Router */
324 @Path("{routerUUID}")
327 @ResponseCode(code = 204, condition = "No Content"),
328 @ResponseCode(code = 401, condition = "Unauthorized"),
329 @ResponseCode(code = 404, condition = "Not Found"),
330 @ResponseCode(code = 409, condition = "Conflict"),
331 @ResponseCode(code = 501, condition = "Not Implemented") })
332 public Response deleteRouter(
333 @PathParam("routerUUID") String routerUUID) {
334 INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
335 if (routerInterface == null) {
336 throw new ServiceUnavailableException("Router CRUD Interface "
337 + RestMessages.SERVICEUNAVAILABLE.toString());
341 * verify that the router exists and is not in use before removing it
343 if (!routerInterface.routerExists(routerUUID))
344 throw new ResourceNotFoundException("Router UUID not found");
345 if (routerInterface.routerInUse(routerUUID))
346 throw new ResourceConflictException("Router UUID in Use");
347 NeutronRouter singleton = routerInterface.getRouter(routerUUID);
348 Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
349 if (instances != null) {
350 if (instances.length > 0) {
351 for (Object instance : instances) {
352 INeutronRouterAware service = (INeutronRouterAware) instance;
353 int status = service.canDeleteRouter(singleton);
354 if (status < 200 || status > 299)
355 return Response.status(status).build();
358 throw new ServiceUnavailableException("No providers registered. Please try again later");
361 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
363 routerInterface.removeRouter(routerUUID);
364 if (instances != null) {
365 for (Object instance : instances) {
366 INeutronRouterAware service = (INeutronRouterAware) instance;
367 service.neutronRouterDeleted(singleton);
370 return Response.status(204).build();
374 * Adds an interface to a router */
376 @Path("{routerUUID}/add_router_interface")
378 @Produces({ MediaType.APPLICATION_JSON })
379 @Consumes({ MediaType.APPLICATION_JSON })
380 //@TypeHint(OpenStackRouterInterfaces.class)
382 @ResponseCode(code = 200, condition = "Operation successful"),
383 @ResponseCode(code = 400, condition = "Bad Request"),
384 @ResponseCode(code = 401, condition = "Unauthorized"),
385 @ResponseCode(code = 404, condition = "Not Found"),
386 @ResponseCode(code = 409, condition = "Conflict"),
387 @ResponseCode(code = 501, condition = "Not Implemented") })
388 public Response addRouterInterface(
389 @PathParam("routerUUID") String routerUUID,
390 NeutronRouter_Interface input
392 INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
393 if (routerInterface == null) {
394 throw new ServiceUnavailableException("Router CRUD Interface "
395 + RestMessages.SERVICEUNAVAILABLE.toString());
397 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
398 if (portInterface == null) {
399 throw new ServiceUnavailableException("Port CRUD Interface "
400 + RestMessages.SERVICEUNAVAILABLE.toString());
402 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
403 if (subnetInterface == null) {
404 throw new ServiceUnavailableException("Subnet CRUD Interface "
405 + RestMessages.SERVICEUNAVAILABLE.toString());
409 * While the Neutron specification says that the router has to exist and the input can only specify either a subnet id
410 * or a port id, but not both, this code assumes that the plugin has filled everything in for us and so both must be present
412 if (!routerInterface.routerExists(routerUUID))
413 throw new BadRequestException("Router UUID doesn't exist");
414 NeutronRouter target = routerInterface.getRouter(routerUUID);
415 if (input.getSubnetUUID() == null ||
416 input.getPortUUID() == null)
417 throw new BadRequestException("Must specify at subnet id, port id or both");
419 // check that the port is part of the subnet
420 NeutronSubnet targetSubnet = subnetInterface.getSubnet(input.getSubnetUUID());
421 if (targetSubnet == null)
422 throw new BadRequestException("Subnet id doesn't exist");
423 NeutronPort targetPort = portInterface.getPort(input.getPortUUID());
424 if (targetPort == null)
425 throw new BadRequestException("Port id doesn't exist");
426 if (!targetSubnet.getPortsInSubnet().contains(targetPort))
427 throw new BadRequestException("Port id not part of subnet id");
429 if (targetPort.getFixedIPs().size() != 1)
430 throw new BadRequestException("Port id must have a single fixedIP address");
431 if (targetPort.getDeviceID() != null ||
432 targetPort.getDeviceOwner() != null)
433 throw new ResourceConflictException("Target Port already allocated");
434 Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
435 if (instances != null) {
436 if (instances.length > 0) {
437 for (Object instance : instances) {
438 INeutronRouterAware service = (INeutronRouterAware) instance;
439 int status = service.canAttachInterface(target, input);
440 if (status < 200 || status > 299)
441 return Response.status(status).build();
444 throw new ServiceUnavailableException("No providers registered. Please try again later");
447 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
450 //mark the port device id and device owner fields
451 targetPort.setDeviceOwner("network:router_interface");
452 targetPort.setDeviceID(routerUUID);
454 target.addInterface(input.getPortUUID(), input);
455 if (instances != null) {
456 for (Object instance : instances) {
457 INeutronRouterAware service = (INeutronRouterAware) instance;
458 service.neutronRouterInterfaceAttached(target, input);
462 return Response.status(200).entity(input).build();
466 * Removes an interface to a router */
468 @Path("{routerUUID}/remove_router_interface")
470 @Produces({ MediaType.APPLICATION_JSON })
471 @Consumes({ MediaType.APPLICATION_JSON })
472 //@TypeHint(OpenStackRouterInterfaces.class)
474 @ResponseCode(code = 200, condition = "Operation successful"),
475 @ResponseCode(code = 400, condition = "Bad Request"),
476 @ResponseCode(code = 401, condition = "Unauthorized"),
477 @ResponseCode(code = 404, condition = "Not Found"),
478 @ResponseCode(code = 409, condition = "Conflict"),
479 @ResponseCode(code = 501, condition = "Not Implemented") })
480 public Response removeRouterInterface(
481 @PathParam("routerUUID") String routerUUID,
482 NeutronRouter_Interface input
484 INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
485 if (routerInterface == null) {
486 throw new ServiceUnavailableException("Router CRUD Interface "
487 + RestMessages.SERVICEUNAVAILABLE.toString());
489 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
490 if (portInterface == null) {
491 throw new ServiceUnavailableException("Port CRUD Interface "
492 + RestMessages.SERVICEUNAVAILABLE.toString());
494 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
495 if (subnetInterface == null) {
496 throw new ServiceUnavailableException("Subnet CRUD Interface "
497 + RestMessages.SERVICEUNAVAILABLE.toString());
500 // verify the router exists
501 if (!routerInterface.routerExists(routerUUID))
502 throw new BadRequestException("Router does not exist");
503 NeutronRouter target = routerInterface.getRouter(routerUUID);
506 * remove by subnet id. Collect information about the impacted router for the response and
507 * remove the port corresponding to the gateway IP address of the subnet
509 if (input.getPortUUID() == null &&
510 input.getSubnetUUID() != null) {
511 NeutronPort port = portInterface.getGatewayPort(input.getSubnetUUID());
513 throw new ResourceNotFoundException("Port UUID not found");
514 input.setPortUUID(port.getID());
515 input.setID(target.getID());
516 input.setTenantID(target.getTenantID());
518 Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
519 if (instances != null) {
520 if (instances.length > 0) {
521 for (Object instance : instances) {
522 INeutronRouterAware service = (INeutronRouterAware) instance;
523 int status = service.canDetachInterface(target, input);
524 if (status < 200 || status > 299)
525 return Response.status(status).build();
528 throw new ServiceUnavailableException("No providers registered. Please try again later");
531 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
534 // reset the port ownership
535 port.setDeviceID(null);
536 port.setDeviceOwner(null);
538 target.removeInterface(input.getPortUUID());
539 if (instances != null) {
540 for (Object instance : instances) {
541 INeutronRouterAware service = (INeutronRouterAware) instance;
542 service.neutronRouterInterfaceDetached(target, input);
545 return Response.status(200).entity(input).build();
549 * remove by port id. collect information about the impacted router for the response
550 * remove the interface and reset the port ownership
552 if (input.getPortUUID() != null &&
553 input.getSubnetUUID() == null) {
554 NeutronRouter_Interface targetInterface = target.getInterfaces().get(input.getPortUUID());
555 if (targetInterface == null) {
556 throw new ResourceNotFoundException("Router interface not found for given Port UUID");
558 input.setSubnetUUID(targetInterface.getSubnetUUID());
559 input.setID(target.getID());
560 input.setTenantID(target.getTenantID());
561 Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
562 if (instances != null) {
563 if (instances.length > 0) {
564 for (Object instance : instances) {
565 INeutronRouterAware service = (INeutronRouterAware) instance;
566 int status = service.canDetachInterface(target, input);
567 if (status < 200 || status > 299)
568 return Response.status(status).build();
571 throw new ServiceUnavailableException("No providers registered. Please try again later");
574 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
576 NeutronPort port = portInterface.getPort(input.getPortUUID());
577 port.setDeviceID(null);
578 port.setDeviceOwner(null);
579 target.removeInterface(input.getPortUUID());
580 for (Object instance : instances) {
581 INeutronRouterAware service = (INeutronRouterAware) instance;
582 service.neutronRouterInterfaceDetached(target, input);
584 return Response.status(200).entity(input).build();
588 * remove by both port and subnet ID. Verify that the first fixed IP of the port is a valid
589 * IP address for the subnet, and then remove the interface, collecting information about the
590 * impacted router for the response and reset port ownership
592 if (input.getPortUUID() != null &&
593 input.getSubnetUUID() != null) {
594 NeutronPort port = portInterface.getPort(input.getPortUUID());
596 throw new ResourceNotFoundException("Port UUID not found");
598 if (port.getFixedIPs() == null) {
599 throw new ResourceNotFoundException("Port UUID has no fixed IPs");
601 NeutronSubnet subnet = subnetInterface.getSubnet(input.getSubnetUUID());
602 if (subnet == null) {
603 throw new ResourceNotFoundException("Subnet UUID not found");
605 if (!subnet.isValidIP(port.getFixedIPs().get(0).getIpAddress()))
606 throw new ResourceConflictException("Target Port IP not in Target Subnet");
607 Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
608 if (instances != null) {
609 if (instances.length > 0) {
610 for (Object instance : instances) {
611 INeutronRouterAware service = (INeutronRouterAware) instance;
612 int status = service.canDetachInterface(target, input);
613 if (status < 200 || status > 299)
614 return Response.status(status).build();
617 throw new ServiceUnavailableException("No providers registered. Please try again later");
620 throw new ServiceUnavailableException("Couldn't get providers list. Please try again later");
622 input.setID(target.getID());
623 input.setTenantID(target.getTenantID());
624 port.setDeviceID(null);
625 port.setDeviceOwner(null);
626 target.removeInterface(input.getPortUUID());
627 if (instances != null) {
628 for (Object instance : instances) {
629 INeutronRouterAware service = (INeutronRouterAware) instance;
630 service.canDetachInterface(target, input);
632 } for (Object instance : instances) {
633 INeutronRouterAware service = (INeutronRouterAware) instance;
634 service.neutronRouterInterfaceDetached(target, input);
636 return Response.status(200).entity(input).build();
639 // have to specify either a port ID or a subnet ID
640 throw new BadRequestException("Must specify port id or subnet id or both");