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