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