Merge "Cleanup root pom "name"."
[controller.git] / opendaylight / networkconfiguration / neutron / northbound / src / main / java / org / opendaylight / controller / networkconfig / neutron / northbound / NeutronRoutersNorthbound.java
1 /*
2  * Copyright IBM Corporation, 2013.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.networkconfig.neutron.northbound;
10
11 import java.util.ArrayList;
12 import java.util.Iterator;
13 import java.util.List;
14
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;
26
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;
40
41
42 /**
43  * Neutron Northbound REST APIs.<br>
44  * This class provides REST APIs for managing neutron routers
45  *
46  * <br>
47  * <br>
48  * Authentication scheme : <b>HTTP Basic</b><br>
49  * Authentication realm : <b>opendaylight</b><br>
50  * Transport : <b>HTTP and HTTPS</b><br>
51  * <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>
55  * More info :
56  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
57  *
58  */
59
60 @Path("/routers")
61 public class NeutronRoutersNorthbound {
62
63     private NeutronRouter extractFields(NeutronRouter o, List<String> fields) {
64         return o.extractFields(fields);
65     }
66
67     /**
68      * Returns a list of all Routers */
69
70     @GET
71     @Produces({ MediaType.APPLICATION_JSON })
72     //@TypeHint(OpenStackRouters.class)
73     @StatusCodes({
74             @ResponseCode(code = 200, condition = "Operation successful"),
75             @ResponseCode(code = 401, condition = "Unauthorized"),
76             @ResponseCode(code = 501, condition = "Not Implemented") })
77     public Response listRouters(
78             // return fields
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,
87             // pagination
88             @QueryParam("limit") String limit,
89             @QueryParam("marker") String marker,
90             @QueryParam("page_reverse") String pageReverse
91             // sorting not supported
92             ) {
93         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
94         if (routerInterface == null) {
95             throw new ServiceUnavailableException("Router CRUD Interface "
96                     + RestMessages.SERVICEUNAVAILABLE.toString());
97         }
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));
111                 else
112                     ans.add(oSS);
113             }
114         }
115         //TODO: apply pagination to results
116         return Response.status(200).entity(
117                 new NeutronRouterRequest(ans)).build();
118     }
119
120     /**
121      * Returns a specific Router */
122
123     @Path("{routerUUID}")
124     @GET
125     @Produces({ MediaType.APPLICATION_JSON })
126     //@TypeHint(OpenStackRouters.class)
127     @StatusCodes({
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,
135             // return fields
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());
141         }
142         if (!routerInterface.routerExists(routerUUID)) {
143             throw new ResourceNotFoundException("Router UUID not found");
144         }
145         if (fields.size() > 0) {
146             NeutronRouter ans = routerInterface.getRouter(routerUUID);
147             return Response.status(200).entity(
148                     new NeutronRouterRequest(extractFields(ans, fields))).build();
149         } else
150             return Response.status(200).entity(
151                     new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
152     }
153
154     /**
155      * Creates new Routers */
156
157     @POST
158     @Produces({ MediaType.APPLICATION_JSON })
159     @Consumes({ MediaType.APPLICATION_JSON })
160     //@TypeHint(OpenStackRouters.class)
161     @StatusCodes({
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());
171         }
172         INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
173         if (networkInterface == null) {
174             throw new ServiceUnavailableException("Network CRUD Interface "
175                     + RestMessages.SERVICEUNAVAILABLE.toString());
176         }
177         if (input.isSingleton()) {
178             NeutronRouter singleton = input.getSingleton();
179
180             /*
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"
184              */
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");
194             }
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();
203                     }
204                 } else {
205                     throw new ServiceUnavailableException("No providers registered.  Please try again later");
206                 }
207             } else {
208                 throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
209             }
210
211             /*
212              * add router to the cache
213              */
214             routerInterface.addRouter(singleton);
215             if (instances != null) {
216                 for (Object instance : instances) {
217                     INeutronRouterAware service = (INeutronRouterAware) instance;
218                     service.neutronRouterCreated(singleton);
219                 }
220             }
221         } else {
222
223             /*
224              * only singleton router creates supported
225              */
226             throw new BadRequestException("Only singleton router creates supported");
227         }
228         return Response.status(201).entity(input).build();
229     }
230
231     /**
232      * Updates a Router */
233
234     @Path("{routerUUID}")
235     @PUT
236     @Produces({ MediaType.APPLICATION_JSON })
237     @Consumes({ MediaType.APPLICATION_JSON })
238     //@TypeHint(OpenStackRouters.class)
239     @StatusCodes({
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
248             ) {
249         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
250         if (routerInterface == null) {
251             throw new ServiceUnavailableException("Router CRUD Interface "
252                     + RestMessages.SERVICEUNAVAILABLE.toString());
253         }
254         INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
255         if (networkInterface == null) {
256             throw new ServiceUnavailableException("Network CRUD Interface "
257                     + RestMessages.SERVICEUNAVAILABLE.toString());
258         }
259
260         /*
261          * router has to exist and only a single delta can be supplied
262          */
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);
269
270         /*
271          * attribute changes blocked by Neutron
272          */
273         if (singleton.getID() != null || singleton.getTenantID() != null ||
274                 singleton.getStatus() != null)
275             throw new BadRequestException("Request attribute change not allowed");
276
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();
285                 }
286             } else {
287                 throw new ServiceUnavailableException("No providers registered.  Please try again later");
288             }
289         } else {
290             throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
291         }
292         /*
293          * if the external gateway info is being changed, verify that the new network
294          * exists and has been designated as an external network
295          */
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");
303         }
304
305         /*
306          * update the router entry and return the modified object
307          */
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);
314             }
315         }
316         return Response.status(200).entity(
317                 new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
318
319     }
320
321     /**
322      * Deletes a Router */
323
324     @Path("{routerUUID}")
325     @DELETE
326     @StatusCodes({
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());
338         }
339
340         /*
341          * verify that the router exists and is not in use before removing it
342          */
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();
356                 }
357             } else {
358                 throw new ServiceUnavailableException("No providers registered.  Please try again later");
359             }
360         } else {
361             throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
362         }
363         routerInterface.removeRouter(routerUUID);
364         if (instances != null) {
365             for (Object instance : instances) {
366                 INeutronRouterAware service = (INeutronRouterAware) instance;
367                 service.neutronRouterDeleted(singleton);
368             }
369         }
370         return Response.status(204).build();
371     }
372
373     /**
374      * Adds an interface to a router */
375
376     @Path("{routerUUID}/add_router_interface")
377     @PUT
378     @Produces({ MediaType.APPLICATION_JSON })
379     @Consumes({ MediaType.APPLICATION_JSON })
380     //@TypeHint(OpenStackRouterInterfaces.class)
381     @StatusCodes({
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
391             ) {
392         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
393         if (routerInterface == null) {
394             throw new ServiceUnavailableException("Router CRUD Interface "
395                     + RestMessages.SERVICEUNAVAILABLE.toString());
396         }
397         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
398         if (portInterface == null) {
399             throw new ServiceUnavailableException("Port CRUD Interface "
400                     + RestMessages.SERVICEUNAVAILABLE.toString());
401         }
402         INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
403         if (subnetInterface == null) {
404             throw new ServiceUnavailableException("Subnet CRUD Interface "
405                     + RestMessages.SERVICEUNAVAILABLE.toString());
406         }
407
408         /*
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
411          */
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");
418
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");
428
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();
442                 }
443             } else {
444                 throw new ServiceUnavailableException("No providers registered.  Please try again later");
445             }
446         } else {
447             throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
448         }
449
450         //mark the port device id and device owner fields
451         targetPort.setDeviceOwner("network:router_interface");
452         targetPort.setDeviceID(routerUUID);
453
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);
459             }
460         }
461
462         return Response.status(200).entity(input).build();
463     }
464
465     /**
466      * Removes an interface to a router */
467
468     @Path("{routerUUID}/remove_router_interface")
469     @PUT
470     @Produces({ MediaType.APPLICATION_JSON })
471     @Consumes({ MediaType.APPLICATION_JSON })
472     //@TypeHint(OpenStackRouterInterfaces.class)
473     @StatusCodes({
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
483             ) {
484         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
485         if (routerInterface == null) {
486             throw new ServiceUnavailableException("Router CRUD Interface "
487                     + RestMessages.SERVICEUNAVAILABLE.toString());
488         }
489         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
490         if (portInterface == null) {
491             throw new ServiceUnavailableException("Port CRUD Interface "
492                     + RestMessages.SERVICEUNAVAILABLE.toString());
493         }
494         INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
495         if (subnetInterface == null) {
496             throw new ServiceUnavailableException("Subnet CRUD Interface "
497                     + RestMessages.SERVICEUNAVAILABLE.toString());
498         }
499
500         // verify the router exists
501         if (!routerInterface.routerExists(routerUUID))
502             throw new BadRequestException("Router does not exist");
503         NeutronRouter target = routerInterface.getRouter(routerUUID);
504
505         /*
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
508          */
509         if (input.getPortUUID() == null &&
510                 input.getSubnetUUID() != null) {
511             NeutronPort port = portInterface.getGatewayPort(input.getSubnetUUID());
512             if (port == null)
513                 throw new ResourceNotFoundException("Port UUID not found");
514             input.setPortUUID(port.getID());
515             input.setID(target.getID());
516             input.setTenantID(target.getTenantID());
517
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();
526                     }
527                 } else {
528                     throw new ServiceUnavailableException("No providers registered.  Please try again later");
529                 }
530             } else {
531                 throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
532             }
533
534             // reset the port ownership
535             port.setDeviceID(null);
536             port.setDeviceOwner(null);
537
538             target.removeInterface(input.getPortUUID());
539             if (instances != null) {
540                 for (Object instance : instances) {
541                     INeutronRouterAware service = (INeutronRouterAware) instance;
542                     service.neutronRouterInterfaceDetached(target, input);
543                 }
544             }
545             return Response.status(200).entity(input).build();
546         }
547
548         /*
549          * remove by port id. collect information about the impacted router for the response
550          * remove the interface and reset the port ownership
551          */
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");
557             }
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();
569                     }
570                 } else {
571                     throw new ServiceUnavailableException("No providers registered.  Please try again later");
572                 }
573             } else {
574                 throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
575             }
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);
583             }
584             return Response.status(200).entity(input).build();
585         }
586
587         /*
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
591          */
592         if (input.getPortUUID() != null &&
593                 input.getSubnetUUID() != null) {
594             NeutronPort port = portInterface.getPort(input.getPortUUID());
595             if (port == null) {
596                 throw new ResourceNotFoundException("Port UUID not found");
597             }
598             if (port.getFixedIPs() == null) {
599                 throw new ResourceNotFoundException("Port UUID has no fixed IPs");
600             }
601             NeutronSubnet subnet = subnetInterface.getSubnet(input.getSubnetUUID());
602             if (subnet == null) {
603                 throw new ResourceNotFoundException("Subnet UUID not found");
604             }
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();
615                     }
616                 } else {
617                     throw new ServiceUnavailableException("No providers registered.  Please try again later");
618                 }
619             } else {
620                 throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
621             }
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);
631                 }
632             }            for (Object instance : instances) {
633                 INeutronRouterAware service = (INeutronRouterAware) instance;
634                 service.neutronRouterInterfaceDetached(target, input);
635             }
636             return Response.status(200).entity(input).build();
637         }
638
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");
641     }
642 }