Fixed package directory issues.
[neutron.git] / northbound-api / src / main / java / org / opendaylight / neutron / northbound / api / 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.neutron.northbound.api;
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.neutron.spi.INeutronNetworkCRUD;
30 import org.opendaylight.neutron.spi.INeutronPortCRUD;
31 import org.opendaylight.neutron.spi.INeutronRouterAware;
32 import org.opendaylight.neutron.spi.INeutronRouterCRUD;
33 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
34 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
35 import org.opendaylight.neutron.spi.NeutronNetwork;
36 import org.opendaylight.neutron.spi.NeutronPort;
37 import org.opendaylight.neutron.spi.NeutronRouter;
38 import org.opendaylight.neutron.spi.NeutronRouter_Interface;
39 import org.opendaylight.neutron.spi.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             @ResponseCode(code = 503, condition = "No providers available") })
78     public Response listRouters(
79             // return fields
80             @QueryParam("fields") List<String> fields,
81             // note: openstack isn't clear about filtering on lists, so we aren't handling them
82             @QueryParam("id") String queryID,
83             @QueryParam("name") String queryName,
84             @QueryParam("admin_state_up") String queryAdminStateUp,
85             @QueryParam("status") String queryStatus,
86             @QueryParam("tenant_id") String queryTenantID,
87             @QueryParam("external_gateway_info") String queryExternalGatewayInfo,
88             // pagination
89             @QueryParam("limit") String limit,
90             @QueryParam("marker") String marker,
91             @QueryParam("page_reverse") String pageReverse
92             // sorting not supported
93             ) {
94         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
95         if (routerInterface == null) {
96             throw new ServiceUnavailableException("Router CRUD Interface "
97                     + RestMessages.SERVICEUNAVAILABLE.toString());
98         }
99         List<NeutronRouter> allRouters = routerInterface.getAllRouters();
100         List<NeutronRouter> ans = new ArrayList<NeutronRouter>();
101         Iterator<NeutronRouter> i = allRouters.iterator();
102         while (i.hasNext()) {
103             NeutronRouter oSS = i.next();
104             if ((queryID == null || queryID.equals(oSS.getID())) &&
105                     (queryName == null || queryName.equals(oSS.getName())) &&
106                     (queryAdminStateUp == null || queryAdminStateUp.equals(oSS.getAdminStateUp())) &&
107                     (queryStatus == null || queryStatus.equals(oSS.getStatus())) &&
108                     (queryExternalGatewayInfo == null || queryExternalGatewayInfo.equals(oSS.getExternalGatewayInfo())) &&
109                     (queryTenantID == null || queryTenantID.equals(oSS.getTenantID()))) {
110                 if (fields.size() > 0)
111                     ans.add(extractFields(oSS,fields));
112                 else
113                     ans.add(oSS);
114             }
115         }
116         //TODO: apply pagination to results
117         return Response.status(200).entity(
118                 new NeutronRouterRequest(ans)).build();
119     }
120
121     /**
122      * Returns a specific Router */
123
124     @Path("{routerUUID}")
125     @GET
126     @Produces({ MediaType.APPLICATION_JSON })
127     //@TypeHint(OpenStackRouters.class)
128     @StatusCodes({
129             @ResponseCode(code = 200, condition = "Operation successful"),
130             @ResponseCode(code = 401, condition = "Unauthorized"),
131             @ResponseCode(code = 403, condition = "Forbidden"),
132             @ResponseCode(code = 404, condition = "Not Found"),
133             @ResponseCode(code = 501, condition = "Not Implemented"),
134             @ResponseCode(code = 503, condition = "No providers available") })
135     public Response showRouter(
136             @PathParam("routerUUID") String routerUUID,
137             // return fields
138             @QueryParam("fields") List<String> fields) {
139         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
140         if (routerInterface == null) {
141             throw new ServiceUnavailableException("Router CRUD Interface "
142                     + RestMessages.SERVICEUNAVAILABLE.toString());
143         }
144         if (!routerInterface.routerExists(routerUUID)) {
145             throw new ResourceNotFoundException("Router UUID not found");
146         }
147         if (fields.size() > 0) {
148             NeutronRouter ans = routerInterface.getRouter(routerUUID);
149             return Response.status(200).entity(
150                     new NeutronRouterRequest(extractFields(ans, fields))).build();
151         } else
152             return Response.status(200).entity(
153                     new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
154     }
155
156     /**
157      * Creates new Routers */
158
159     @POST
160     @Produces({ MediaType.APPLICATION_JSON })
161     @Consumes({ MediaType.APPLICATION_JSON })
162     //@TypeHint(OpenStackRouters.class)
163     @StatusCodes({
164             @ResponseCode(code = 201, condition = "Created"),
165             @ResponseCode(code = 400, condition = "Bad Request"),
166             @ResponseCode(code = 401, condition = "Unauthorized"),
167             @ResponseCode(code = 501, condition = "Not Implemented"),
168             @ResponseCode(code = 503, condition = "No providers available") })
169     public Response createRouters(final NeutronRouterRequest input) {
170         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
171         if (routerInterface == null) {
172             throw new ServiceUnavailableException("Router CRUD Interface "
173                     + RestMessages.SERVICEUNAVAILABLE.toString());
174         }
175         INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
176         if (networkInterface == null) {
177             throw new ServiceUnavailableException("Network CRUD Interface "
178                     + RestMessages.SERVICEUNAVAILABLE.toString());
179         }
180         if (input.isSingleton()) {
181             NeutronRouter singleton = input.getSingleton();
182
183             /*
184              * verify that the router doesn't already exist (issue: is deeper inspection necessary?)
185              * if there is external gateway information provided, verify that the specified network
186              * exists and has been designated as "router:external"
187              */
188             if (routerInterface.routerExists(singleton.getID()))
189                 throw new BadRequestException("router UUID already exists");
190             if (singleton.getExternalGatewayInfo() != null) {
191                 String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
192                 if (!networkInterface.networkExists(externNetworkPtr))
193                     throw new BadRequestException("External Network Pointer doesn't exist");
194                 NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
195                 if (!externNetwork.isRouterExternal())
196                     throw new BadRequestException("External Network Pointer isn't marked as router:external");
197             }
198             Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
199             if (instances != null) {
200                 if (instances.length > 0) {
201                     for (Object instance : instances) {
202                         INeutronRouterAware service = (INeutronRouterAware) instance;
203                         int status = service.canCreateRouter(singleton);
204                         if (status < 200 || status > 299)
205                             return Response.status(status).build();
206                     }
207                 } else {
208                     throw new ServiceUnavailableException("No providers registered.  Please try again later");
209                 }
210             } else {
211                 throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
212             }
213
214             /*
215              * add router to the cache
216              */
217             routerInterface.addRouter(singleton);
218             if (instances != null) {
219                 for (Object instance : instances) {
220                     INeutronRouterAware service = (INeutronRouterAware) instance;
221                     service.neutronRouterCreated(singleton);
222                 }
223             }
224         } else {
225
226             /*
227              * only singleton router creates supported
228              */
229             throw new BadRequestException("Only singleton router creates supported");
230         }
231         return Response.status(201).entity(input).build();
232     }
233
234     /**
235      * Updates a Router */
236
237     @Path("{routerUUID}")
238     @PUT
239     @Produces({ MediaType.APPLICATION_JSON })
240     @Consumes({ MediaType.APPLICATION_JSON })
241     //@TypeHint(OpenStackRouters.class)
242     @StatusCodes({
243             @ResponseCode(code = 200, condition = "Operation successful"),
244             @ResponseCode(code = 400, condition = "Bad Request"),
245             @ResponseCode(code = 401, condition = "Unauthorized"),
246             @ResponseCode(code = 404, condition = "Not Found"),
247             @ResponseCode(code = 501, condition = "Not Implemented"),
248             @ResponseCode(code = 503, condition = "No providers available") })
249     public Response updateRouter(
250             @PathParam("routerUUID") String routerUUID,
251             NeutronRouterRequest input
252             ) {
253         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
254         if (routerInterface == null) {
255             throw new ServiceUnavailableException("Router CRUD Interface "
256                     + RestMessages.SERVICEUNAVAILABLE.toString());
257         }
258         INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
259         if (networkInterface == null) {
260             throw new ServiceUnavailableException("Network CRUD Interface "
261                     + RestMessages.SERVICEUNAVAILABLE.toString());
262         }
263
264         /*
265          * router has to exist and only a single delta can be supplied
266          */
267         if (!routerInterface.routerExists(routerUUID))
268             throw new ResourceNotFoundException("Router UUID not found");
269         if (!input.isSingleton())
270             throw new BadRequestException("Only single router deltas supported");
271         NeutronRouter singleton = input.getSingleton();
272         NeutronRouter original = routerInterface.getRouter(routerUUID);
273
274         /*
275          * attribute changes blocked by Neutron
276          */
277         if (singleton.getID() != null || singleton.getTenantID() != null ||
278                 singleton.getStatus() != null)
279             throw new BadRequestException("Request attribute change not allowed");
280
281         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
282         if (instances != null) {
283             if (instances.length > 0) {
284                 for (Object instance : instances) {
285                     INeutronRouterAware service = (INeutronRouterAware) instance;
286                     int status = service.canUpdateRouter(singleton, original);
287                     if (status < 200 || status > 299)
288                         return Response.status(status).build();
289                 }
290             } else {
291                 throw new ServiceUnavailableException("No providers registered.  Please try again later");
292             }
293         } else {
294             throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
295         }
296         /*
297          * if the external gateway info is being changed, verify that the new network
298          * exists and has been designated as an external network
299          */
300         if (singleton.getExternalGatewayInfo() != null) {
301             String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
302             if (!networkInterface.networkExists(externNetworkPtr))
303                 throw new BadRequestException("External Network Pointer does not exist");
304             NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
305             if (!externNetwork.isRouterExternal())
306                 throw new BadRequestException("External Network Pointer isn't marked as router:external");
307         }
308
309         /*
310          * update the router entry and return the modified object
311          */
312         routerInterface.updateRouter(routerUUID, singleton);
313         NeutronRouter updatedRouter = routerInterface.getRouter(routerUUID);
314         if (instances != null) {
315             for (Object instance : instances) {
316                 INeutronRouterAware service = (INeutronRouterAware) instance;
317                 service.neutronRouterUpdated(updatedRouter);
318             }
319         }
320         return Response.status(200).entity(
321                 new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
322
323     }
324
325     /**
326      * Deletes a Router */
327
328     @Path("{routerUUID}")
329     @DELETE
330     @StatusCodes({
331             @ResponseCode(code = 204, condition = "No Content"),
332             @ResponseCode(code = 401, condition = "Unauthorized"),
333             @ResponseCode(code = 404, condition = "Not Found"),
334             @ResponseCode(code = 409, condition = "Conflict"),
335             @ResponseCode(code = 501, condition = "Not Implemented"),
336             @ResponseCode(code = 503, condition = "No providers available") })
337     public Response deleteRouter(
338             @PathParam("routerUUID") String routerUUID) {
339         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
340         if (routerInterface == null) {
341             throw new ServiceUnavailableException("Router CRUD Interface "
342                     + RestMessages.SERVICEUNAVAILABLE.toString());
343         }
344
345         /*
346          * verify that the router exists and is not in use before removing it
347          */
348         if (!routerInterface.routerExists(routerUUID))
349             throw new ResourceNotFoundException("Router UUID not found");
350         if (routerInterface.routerInUse(routerUUID))
351             throw new ResourceConflictException("Router UUID in Use");
352         NeutronRouter singleton = routerInterface.getRouter(routerUUID);
353         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
354         if (instances != null) {
355             if (instances.length > 0) {
356                 for (Object instance : instances) {
357                     INeutronRouterAware service = (INeutronRouterAware) instance;
358                     int status = service.canDeleteRouter(singleton);
359                     if (status < 200 || status > 299)
360                         return Response.status(status).build();
361                 }
362             } else {
363                 throw new ServiceUnavailableException("No providers registered.  Please try again later");
364             }
365         } else {
366             throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
367         }
368         routerInterface.removeRouter(routerUUID);
369         if (instances != null) {
370             for (Object instance : instances) {
371                 INeutronRouterAware service = (INeutronRouterAware) instance;
372                 service.neutronRouterDeleted(singleton);
373             }
374         }
375         return Response.status(204).build();
376     }
377
378     /**
379      * Adds an interface to a router */
380
381     @Path("{routerUUID}/add_router_interface")
382     @PUT
383     @Produces({ MediaType.APPLICATION_JSON })
384     @Consumes({ MediaType.APPLICATION_JSON })
385     //@TypeHint(OpenStackRouterInterfaces.class)
386     @StatusCodes({
387             @ResponseCode(code = 200, condition = "Operation successful"),
388             @ResponseCode(code = 400, condition = "Bad Request"),
389             @ResponseCode(code = 401, condition = "Unauthorized"),
390             @ResponseCode(code = 404, condition = "Not Found"),
391             @ResponseCode(code = 409, condition = "Conflict"),
392             @ResponseCode(code = 501, condition = "Not Implemented"),
393             @ResponseCode(code = 503, condition = "No providers available") })
394     public Response addRouterInterface(
395             @PathParam("routerUUID") String routerUUID,
396             NeutronRouter_Interface input
397             ) {
398         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
399         if (routerInterface == null) {
400             throw new ServiceUnavailableException("Router CRUD Interface "
401                     + RestMessages.SERVICEUNAVAILABLE.toString());
402         }
403         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
404         if (portInterface == null) {
405             throw new ServiceUnavailableException("Port CRUD Interface "
406                     + RestMessages.SERVICEUNAVAILABLE.toString());
407         }
408         INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
409         if (subnetInterface == null) {
410             throw new ServiceUnavailableException("Subnet CRUD Interface "
411                     + RestMessages.SERVICEUNAVAILABLE.toString());
412         }
413
414         /*
415          *  While the Neutron specification says that the router has to exist and the input can only specify either a subnet id
416          *  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
417          */
418         if (!routerInterface.routerExists(routerUUID))
419             throw new BadRequestException("Router UUID doesn't exist");
420         NeutronRouter target = routerInterface.getRouter(routerUUID);
421         if (input.getSubnetUUID() == null ||
422                     input.getPortUUID() == null)
423             throw new BadRequestException("Must specify at subnet id, port id or both");
424
425         // check that the port is part of the subnet
426         NeutronSubnet targetSubnet = subnetInterface.getSubnet(input.getSubnetUUID());
427         if (targetSubnet == null)
428             throw new BadRequestException("Subnet id doesn't exist");
429         NeutronPort targetPort = portInterface.getPort(input.getPortUUID());
430         if (targetPort == null)
431             throw new BadRequestException("Port id doesn't exist");
432         if (!targetSubnet.getPortsInSubnet().contains(targetPort))
433             throw new BadRequestException("Port id not part of subnet id");
434
435         if (targetPort.getFixedIPs().size() != 1)
436             throw new BadRequestException("Port id must have a single fixedIP address");
437         if (targetPort.getDeviceID() != null ||
438                 targetPort.getDeviceOwner() != null)
439             throw new ResourceConflictException("Target Port already allocated");
440         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
441         if (instances != null) {
442             if (instances.length > 0) {
443                 for (Object instance : instances) {
444                     INeutronRouterAware service = (INeutronRouterAware) instance;
445                     int status = service.canAttachInterface(target, input);
446                     if (status < 200 || status > 299)
447                         return Response.status(status).build();
448                 }
449             } else {
450                 throw new ServiceUnavailableException("No providers registered.  Please try again later");
451             }
452         } else {
453             throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
454         }
455
456         //mark the port device id and device owner fields
457         targetPort.setDeviceOwner("network:router_interface");
458         targetPort.setDeviceID(routerUUID);
459
460         target.addInterface(input.getPortUUID(), input);
461         if (instances != null) {
462             for (Object instance : instances) {
463                 INeutronRouterAware service = (INeutronRouterAware) instance;
464                 service.neutronRouterInterfaceAttached(target, input);
465             }
466         }
467
468         return Response.status(200).entity(input).build();
469     }
470
471     /**
472      * Removes an interface to a router */
473
474     @Path("{routerUUID}/remove_router_interface")
475     @PUT
476     @Produces({ MediaType.APPLICATION_JSON })
477     @Consumes({ MediaType.APPLICATION_JSON })
478     //@TypeHint(OpenStackRouterInterfaces.class)
479     @StatusCodes({
480             @ResponseCode(code = 200, condition = "Operation successful"),
481             @ResponseCode(code = 400, condition = "Bad Request"),
482             @ResponseCode(code = 401, condition = "Unauthorized"),
483             @ResponseCode(code = 404, condition = "Not Found"),
484             @ResponseCode(code = 409, condition = "Conflict"),
485             @ResponseCode(code = 501, condition = "Not Implemented"),
486             @ResponseCode(code = 503, condition = "No providers available") })
487     public Response removeRouterInterface(
488             @PathParam("routerUUID") String routerUUID,
489             NeutronRouter_Interface input
490             ) {
491         INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
492         if (routerInterface == null) {
493             throw new ServiceUnavailableException("Router CRUD Interface "
494                     + RestMessages.SERVICEUNAVAILABLE.toString());
495         }
496         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
497         if (portInterface == null) {
498             throw new ServiceUnavailableException("Port CRUD Interface "
499                     + RestMessages.SERVICEUNAVAILABLE.toString());
500         }
501         INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
502         if (subnetInterface == null) {
503             throw new ServiceUnavailableException("Subnet CRUD Interface "
504                     + RestMessages.SERVICEUNAVAILABLE.toString());
505         }
506
507         // verify the router exists
508         if (!routerInterface.routerExists(routerUUID))
509             throw new BadRequestException("Router does not exist");
510         NeutronRouter target = routerInterface.getRouter(routerUUID);
511
512         /*
513          * remove by subnet id.  Collect information about the impacted router for the response and
514          * remove the port corresponding to the gateway IP address of the subnet
515          */
516         if (input.getPortUUID() == null &&
517                 input.getSubnetUUID() != null) {
518             NeutronPort port = portInterface.getGatewayPort(input.getSubnetUUID());
519             if (port == null)
520                 throw new ResourceNotFoundException("Port UUID not found");
521             input.setPortUUID(port.getID());
522             input.setID(target.getID());
523             input.setTenantID(target.getTenantID());
524
525             Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
526             if (instances != null) {
527                 if (instances.length > 0) {
528                     for (Object instance : instances) {
529                         INeutronRouterAware service = (INeutronRouterAware) instance;
530                         int status = service.canDetachInterface(target, input);
531                         if (status < 200 || status > 299)
532                             return Response.status(status).build();
533                     }
534                 } else {
535                     throw new ServiceUnavailableException("No providers registered.  Please try again later");
536                 }
537             } else {
538                 throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
539             }
540
541             // reset the port ownership
542             port.setDeviceID(null);
543             port.setDeviceOwner(null);
544
545             target.removeInterface(input.getPortUUID());
546             if (instances != null) {
547                 for (Object instance : instances) {
548                     INeutronRouterAware service = (INeutronRouterAware) instance;
549                     service.neutronRouterInterfaceDetached(target, input);
550                 }
551             }
552             return Response.status(200).entity(input).build();
553         }
554
555         /*
556          * remove by port id. collect information about the impacted router for the response
557          * remove the interface and reset the port ownership
558          */
559         if (input.getPortUUID() != null &&
560                 input.getSubnetUUID() == null) {
561             NeutronRouter_Interface targetInterface = target.getInterfaces().get(input.getPortUUID());
562             if (targetInterface == null) {
563                 throw new ResourceNotFoundException("Router interface not found for given Port UUID");
564             }
565             input.setSubnetUUID(targetInterface.getSubnetUUID());
566             input.setID(target.getID());
567             input.setTenantID(target.getTenantID());
568             Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
569             if (instances != null) {
570                 if (instances.length > 0) {
571                     for (Object instance : instances) {
572                         INeutronRouterAware service = (INeutronRouterAware) instance;
573                         int status = service.canDetachInterface(target, input);
574                         if (status < 200 || status > 299)
575                             return Response.status(status).build();
576                     }
577                 } else {
578                     throw new ServiceUnavailableException("No providers registered.  Please try again later");
579                 }
580             } else {
581                 throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
582             }
583             NeutronPort port = portInterface.getPort(input.getPortUUID());
584             port.setDeviceID(null);
585             port.setDeviceOwner(null);
586             target.removeInterface(input.getPortUUID());
587             for (Object instance : instances) {
588                 INeutronRouterAware service = (INeutronRouterAware) instance;
589                 service.neutronRouterInterfaceDetached(target, input);
590             }
591             return Response.status(200).entity(input).build();
592         }
593
594         /*
595          * remove by both port and subnet ID.  Verify that the first fixed IP of the port is a valid
596          * IP address for the subnet, and then remove the interface, collecting information about the
597          * impacted router for the response and reset port ownership
598          */
599         if (input.getPortUUID() != null &&
600                 input.getSubnetUUID() != null) {
601             NeutronPort port = portInterface.getPort(input.getPortUUID());
602             if (port == null) {
603                 throw new ResourceNotFoundException("Port UUID not found");
604             }
605             if (port.getFixedIPs() == null) {
606                 throw new ResourceNotFoundException("Port UUID has no fixed IPs");
607             }
608             NeutronSubnet subnet = subnetInterface.getSubnet(input.getSubnetUUID());
609             if (subnet == null) {
610                 throw new ResourceNotFoundException("Subnet UUID not found");
611             }
612             if (!subnet.isValidIP(port.getFixedIPs().get(0).getIpAddress()))
613                 throw new ResourceConflictException("Target Port IP not in Target Subnet");
614             Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
615             if (instances != null) {
616                 if (instances.length > 0) {
617                     for (Object instance : instances) {
618                         INeutronRouterAware service = (INeutronRouterAware) instance;
619                         int status = service.canDetachInterface(target, input);
620                         if (status < 200 || status > 299)
621                             return Response.status(status).build();
622                     }
623                 } else {
624                     throw new ServiceUnavailableException("No providers registered.  Please try again later");
625                 }
626             } else {
627                 throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
628             }
629             input.setID(target.getID());
630             input.setTenantID(target.getTenantID());
631             port.setDeviceID(null);
632             port.setDeviceOwner(null);
633             target.removeInterface(input.getPortUUID());
634             if (instances != null) {
635                 for (Object instance : instances) {
636                     INeutronRouterAware service = (INeutronRouterAware) instance;
637                     service.canDetachInterface(target, input);
638                 }
639             }            for (Object instance : instances) {
640                 INeutronRouterAware service = (INeutronRouterAware) instance;
641                 service.neutronRouterInterfaceDetached(target, input);
642             }
643             return Response.status(200).entity(input).build();
644         }
645
646         // have to specify either a port ID or a subnet ID
647         throw new BadRequestException("Must specify port id or subnet id or both");
648     }
649 }