Merge "Remove @deprecation from FWaaS classes"
[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      * Creates new Routers */
203
204     @POST
205     @Produces({ MediaType.APPLICATION_JSON })
206     @Consumes({ MediaType.APPLICATION_JSON })
207     //@TypeHint(OpenStackRouters.class)
208     @StatusCodes({
209             @ResponseCode(code = HttpURLConnection.HTTP_CREATED, condition = "Created"),
210             @ResponseCode(code = HttpURLConnection.HTTP_BAD_REQUEST, condition = "Bad Request"),
211             @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
212             @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
213             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
214     public Response createRouters(final NeutronRouterRequest input) {
215         NeutronCRUDInterfaces interfaces = getNeutronInterfaces(true);
216         INeutronRouterCRUD routerInterface = interfaces.getRouterInterface();
217         INeutronNetworkCRUD networkInterface = interfaces.getNetworkInterface();
218         if (input.isSingleton()) {
219             NeutronRouter singleton = input.getSingleton();
220
221             /*
222              * verify that the router doesn't already exist (issue: is deeper inspection necessary?)
223              * if there is external gateway information provided, verify that the specified network
224              * exists and has been designated as "router:external"
225              */
226             if (routerInterface.routerExists(singleton.getID())) {
227                 throw new BadRequestException("router UUID already exists");
228             }
229             if (singleton.getExternalGatewayInfo() != null) {
230                 String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
231                 if (!networkInterface.networkExists(externNetworkPtr)) {
232                     throw new BadRequestException("External Network Pointer doesn't exist");
233                 }
234                 NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
235                 if (!externNetwork.isRouterExternal()) {
236                     throw new BadRequestException("External Network Pointer isn't marked as router:external");
237                 }
238             }
239             Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
240             if (instances != null) {
241                 if (instances.length > 0) {
242                     for (Object instance : instances) {
243                         INeutronRouterAware service = (INeutronRouterAware) instance;
244                         int status = service.canCreateRouter(singleton);
245                         if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
246                             return Response.status(status).build();
247                         }
248                     }
249                 } else {
250                     throw new ServiceUnavailableException(NO_PROVIDERS);
251                 }
252             } else {
253                 throw new ServiceUnavailableException(NO_PROVIDER_LIST);
254             }
255
256             /*
257              * add router to the cache
258              */
259             routerInterface.addRouter(singleton);
260             if (instances != null) {
261                 for (Object instance : instances) {
262                     INeutronRouterAware service = (INeutronRouterAware) instance;
263                     service.neutronRouterCreated(singleton);
264                 }
265             }
266         } else {
267
268             /*
269              * only singleton router creates supported
270              */
271             throw new BadRequestException("Only singleton router creates supported");
272         }
273         return Response.status(HttpURLConnection.HTTP_CREATED).entity(input).build();
274     }
275
276     /**
277      * Updates a Router */
278
279     @Path("{routerUUID}")
280     @PUT
281     @Produces({ MediaType.APPLICATION_JSON })
282     @Consumes({ MediaType.APPLICATION_JSON })
283     //@TypeHint(OpenStackRouters.class)
284     @StatusCodes({
285             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
286             @ResponseCode(code = HttpURLConnection.HTTP_BAD_REQUEST, condition = "Bad Request"),
287             @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
288             @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
289             @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
290             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
291     public Response updateRouter(
292             @PathParam("routerUUID") String routerUUID,
293             NeutronRouterRequest input
294             ) {
295         NeutronCRUDInterfaces interfaces = getNeutronInterfaces(true);
296         INeutronRouterCRUD routerInterface = interfaces.getRouterInterface();
297         INeutronNetworkCRUD networkInterface = interfaces.getNetworkInterface();
298
299         /*
300          * router has to exist and only a single delta can be supplied
301          */
302         if (!routerInterface.routerExists(routerUUID)) {
303             throw new ResourceNotFoundException(UUID_NO_EXIST);
304         }
305         if (!input.isSingleton()) {
306             throw new BadRequestException("Only single router deltas supported");
307         }
308         NeutronRouter singleton = input.getSingleton();
309         NeutronRouter original = routerInterface.getRouter(routerUUID);
310
311         /*
312          * attribute changes blocked by Neutron
313          */
314         if (singleton.getID() != null || singleton.getTenantID() != null ||
315                 singleton.getStatus() != null) {
316             throw new BadRequestException("Request attribute change not allowed");
317         }
318
319         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
320         if (instances != null) {
321             if (instances.length > 0) {
322                 for (Object instance : instances) {
323                     INeutronRouterAware service = (INeutronRouterAware) instance;
324                     int status = service.canUpdateRouter(singleton, original);
325                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
326                         return Response.status(status).build();
327                     }
328                 }
329             } else {
330                 throw new ServiceUnavailableException(NO_PROVIDERS);
331             }
332         } else {
333             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
334         }
335         /*
336          * if the external gateway info is being changed, verify that the new network
337          * exists and has been designated as an external network
338          */
339         if (singleton.getExternalGatewayInfo() != null) {
340             String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
341             if (!networkInterface.networkExists(externNetworkPtr)) {
342                 throw new BadRequestException("External Network Pointer does not exist");
343             }
344             NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
345             if (!externNetwork.isRouterExternal()) {
346                 throw new BadRequestException("External Network Pointer isn't marked as router:external");
347             }
348         }
349
350         /*
351          * update the router entry and return the modified object
352          */
353         routerInterface.updateRouter(routerUUID, singleton);
354         NeutronRouter updatedRouter = routerInterface.getRouter(routerUUID);
355         if (instances != null) {
356             for (Object instance : instances) {
357                 INeutronRouterAware service = (INeutronRouterAware) instance;
358                 service.neutronRouterUpdated(updatedRouter);
359             }
360         }
361         return Response.status(HttpURLConnection.HTTP_OK).entity(
362                 new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
363
364     }
365
366     /**
367      * Deletes a Router */
368
369     @Path("{routerUUID}")
370     @DELETE
371     @StatusCodes({
372             @ResponseCode(code = HttpURLConnection.HTTP_NO_CONTENT, condition = "No Content"),
373             @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
374             @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
375             @ResponseCode(code = HttpURLConnection.HTTP_CONFLICT, condition = "Conflict"),
376             @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
377             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
378     public Response deleteRouter(
379             @PathParam("routerUUID") String routerUUID) {
380         INeutronRouterCRUD routerInterface = getNeutronInterfaces(false).getRouterInterface();
381
382         /*
383          * verify that the router exists and is not in use before removing it
384          */
385         if (!routerInterface.routerExists(routerUUID)) {
386             throw new ResourceNotFoundException(UUID_NO_EXIST);
387         }
388         if (routerInterface.routerInUse(routerUUID)) {
389             throw new ResourceConflictException("Router UUID in Use");
390         }
391         NeutronRouter singleton = routerInterface.getRouter(routerUUID);
392         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
393         if (instances != null) {
394             if (instances.length > 0) {
395                 for (Object instance : instances) {
396                     INeutronRouterAware service = (INeutronRouterAware) instance;
397                     int status = service.canDeleteRouter(singleton);
398                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
399                         return Response.status(status).build();
400                     }
401                 }
402             } else {
403                 throw new ServiceUnavailableException(NO_PROVIDERS);
404             }
405         } else {
406             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
407         }
408         routerInterface.removeRouter(routerUUID);
409         if (instances != null) {
410             for (Object instance : instances) {
411                 INeutronRouterAware service = (INeutronRouterAware) instance;
412                 service.neutronRouterDeleted(singleton);
413             }
414         }
415         return Response.status(HttpURLConnection.HTTP_NO_CONTENT).build();
416     }
417
418     /**
419      * Adds an interface to a router */
420
421     @Path("{routerUUID}/add_router_interface")
422     @PUT
423     @Produces({ MediaType.APPLICATION_JSON })
424     @Consumes({ MediaType.APPLICATION_JSON })
425     //@TypeHint(OpenStackRouterInterfaces.class)
426     @StatusCodes({
427             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
428             @ResponseCode(code = HttpURLConnection.HTTP_BAD_REQUEST, condition = "Bad Request"),
429             @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
430             @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
431             @ResponseCode(code = HttpURLConnection.HTTP_CONFLICT, condition = "Conflict"),
432             @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
433             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
434     public Response addRouterInterface(
435             @PathParam("routerUUID") String routerUUID,
436             NeutronRouter_Interface input
437             ) {
438         NeutronCRUDInterfaces interfaces = getAttachInterfaces();
439         INeutronRouterCRUD routerInterface = interfaces.getRouterInterface();
440         INeutronPortCRUD portInterface = interfaces.getPortInterface();
441         INeutronSubnetCRUD subnetInterface = interfaces.getSubnetInterface();
442
443         /*
444          *  While the Neutron specification says that the router has to exist and the input can only specify either a subnet id
445          *  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
446          */
447         if (!routerInterface.routerExists(routerUUID)) {
448             throw new BadRequestException(UUID_NO_EXIST);
449         }
450         NeutronRouter target = routerInterface.getRouter(routerUUID);
451         if (input.getSubnetUUID() == null ||
452                     input.getPortUUID() == null) {
453             throw new BadRequestException("Must specify at subnet id, port id or both");
454         }
455
456         // check that the port is part of the subnet
457         NeutronSubnet targetSubnet = subnetInterface.getSubnet(input.getSubnetUUID());
458         if (targetSubnet == null) {
459             throw new BadRequestException("Subnet id doesn't exist");
460         }
461         NeutronPort targetPort = portInterface.getPort(input.getPortUUID());
462         if (targetPort == null) {
463             throw new BadRequestException("Port id doesn't exist");
464         }
465         if (!targetSubnet.getPortsInSubnet().contains(targetPort)) {
466             throw new BadRequestException("Port id not part of subnet id");
467         }
468
469         if (targetPort.getFixedIPs().size() != 1) {
470             throw new BadRequestException("Port id must have a single fixedIP address");
471         }
472         if (targetPort.getDeviceID() != null && !targetPort.getDeviceID().equals(routerUUID)) {
473             throw new ResourceConflictException("Target Port already allocated to a different device id");
474         }
475         if (targetPort.getDeviceOwner() != null &&
476             !targetPort.getDeviceOwner().equalsIgnoreCase(ROUTER_INTERFACE_STR) &&
477             !targetPort.getDeviceOwner().equalsIgnoreCase(ROUTER_GATEWAY_STR)) {
478             throw new ResourceConflictException("Target Port already allocated to non-router interface");
479         }
480         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
481         if (instances != null) {
482             if (instances.length > 0) {
483                 for (Object instance : instances) {
484                     INeutronRouterAware service = (INeutronRouterAware) instance;
485                     int status = service.canAttachInterface(target, input);
486                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
487                         return Response.status(status).build();
488                     }
489                 }
490             } else {
491                 throw new ServiceUnavailableException(NO_PROVIDERS);
492             }
493         } else {
494             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
495         }
496
497         //mark the port device id and device owner fields
498         if (targetPort.getDeviceOwner() == null || targetPort.getDeviceOwner().isEmpty()) {
499             targetPort.setDeviceOwner(ROUTER_INTERFACE_STR);
500         }
501         targetPort.setDeviceID(routerUUID);
502
503         target.addInterface(input.getPortUUID(), input);
504         if (instances != null) {
505             for (Object instance : instances) {
506                 INeutronRouterAware service = (INeutronRouterAware) instance;
507                 service.neutronRouterInterfaceAttached(target, input);
508             }
509         }
510
511         return Response.status(HttpURLConnection.HTTP_OK).entity(input).build();
512     }
513
514     /**
515      * Removes an interface to a router */
516
517     @Path("{routerUUID}/remove_router_interface")
518     @PUT
519     @Produces({ MediaType.APPLICATION_JSON })
520     @Consumes({ MediaType.APPLICATION_JSON })
521     //@TypeHint(OpenStackRouterInterfaces.class)
522     @StatusCodes({
523             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
524             @ResponseCode(code = HttpURLConnection.HTTP_BAD_REQUEST, condition = "Bad Request"),
525             @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
526             @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
527             @ResponseCode(code = HttpURLConnection.HTTP_CONFLICT, condition = "Conflict"),
528             @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
529             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
530     public Response removeRouterInterface(
531             @PathParam("routerUUID") String routerUUID,
532             NeutronRouter_Interface input
533             ) {
534         NeutronCRUDInterfaces interfaces = getAttachInterfaces();
535         INeutronRouterCRUD routerInterface = interfaces.getRouterInterface();
536         INeutronPortCRUD portInterface = interfaces.getPortInterface();
537         INeutronSubnetCRUD subnetInterface = interfaces.getSubnetInterface();
538
539         // verify the router exists
540         if (!routerInterface.routerExists(routerUUID)) {
541             throw new BadRequestException("Router does not exist");
542         }
543         NeutronRouter target = routerInterface.getRouter(routerUUID);
544
545         /*
546          * remove by subnet id.  Collect information about the impacted router for the response and
547          * remove the port corresponding to the gateway IP address of the subnet
548          */
549         if (input.getPortUUID() == null &&
550                 input.getSubnetUUID() != null) {
551             NeutronPort port = portInterface.getGatewayPort(input.getSubnetUUID());
552             if (port == null) {
553                 throw new ResourceNotFoundException("Port UUID not found");
554             }
555             input.setPortUUID(port.getID());
556             input.setID(target.getID());
557             input.setTenantID(target.getTenantID());
558
559             Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
560             if (instances != null) {
561                 if (instances.length > 0) {
562                     for (Object instance : instances) {
563                         INeutronRouterAware service = (INeutronRouterAware) instance;
564                         int status = service.canDetachInterface(target, input);
565                         if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
566                             return Response.status(status).build();
567                         }
568                     }
569                 } else {
570                     throw new ServiceUnavailableException(NO_PROVIDERS);
571                 }
572             } else {
573                 throw new ServiceUnavailableException(NO_PROVIDER_LIST);
574             }
575
576             // reset the port ownership
577             port.setDeviceID(null);
578             port.setDeviceOwner(null);
579
580             target.removeInterface(input.getPortUUID());
581             if (instances != null) {
582                 for (Object instance : instances) {
583                     INeutronRouterAware service = (INeutronRouterAware) instance;
584                     service.neutronRouterInterfaceDetached(target, input);
585                 }
586             }
587             return Response.status(HttpURLConnection.HTTP_OK).entity(input).build();
588         }
589
590         /*
591          * remove by port id. collect information about the impacted router for the response
592          * remove the interface and reset the port ownership
593          */
594         if (input.getPortUUID() != null &&
595                 input.getSubnetUUID() == null) {
596             NeutronRouter_Interface targetInterface = target.getInterfaces().get(input.getPortUUID());
597             if (targetInterface == null) {
598                 throw new ResourceNotFoundException("Router interface not found for given Port UUID");
599             }
600             input.setSubnetUUID(targetInterface.getSubnetUUID());
601             input.setID(target.getID());
602             input.setTenantID(target.getTenantID());
603             Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
604             if (instances != null) {
605                 if (instances.length > 0) {
606                     for (Object instance : instances) {
607                         INeutronRouterAware service = (INeutronRouterAware) instance;
608                         int status = service.canDetachInterface(target, input);
609                         if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
610                             return Response.status(status).build();
611                         }
612                     }
613                 } else {
614                     throw new ServiceUnavailableException(NO_PROVIDERS);
615                 }
616             } else {
617                 throw new ServiceUnavailableException(NO_PROVIDER_LIST);
618             }
619             NeutronPort port = portInterface.getPort(input.getPortUUID());
620             port.setDeviceID(null);
621             port.setDeviceOwner(null);
622             target.removeInterface(input.getPortUUID());
623             for (Object instance : instances) {
624                 INeutronRouterAware service = (INeutronRouterAware) instance;
625                 service.neutronRouterInterfaceDetached(target, input);
626             }
627             return Response.status(HttpURLConnection.HTTP_OK).entity(input).build();
628         }
629
630         /*
631          * remove by both port and subnet ID.  Verify that the first fixed IP of the port is a valid
632          * IP address for the subnet, and then remove the interface, collecting information about the
633          * impacted router for the response and reset port ownership
634          */
635         if (input.getPortUUID() != null &&
636                 input.getSubnetUUID() != null) {
637             NeutronPort port = portInterface.getPort(input.getPortUUID());
638             if (port == null) {
639                 throw new ResourceNotFoundException("Port UUID not found");
640             }
641             if (port.getFixedIPs() == null) {
642                 throw new ResourceNotFoundException("Port UUID has no fixed IPs");
643             }
644             NeutronSubnet subnet = subnetInterface.getSubnet(input.getSubnetUUID());
645             if (subnet == null) {
646                 throw new ResourceNotFoundException("Subnet UUID not found");
647             }
648             if (!subnet.isValidIP(port.getFixedIPs().get(0).getIpAddress())) {
649                 throw new ResourceConflictException("Target Port IP not in Target Subnet");
650             }
651             Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
652             if (instances != null) {
653                 if (instances.length > 0) {
654                     for (Object instance : instances) {
655                         INeutronRouterAware service = (INeutronRouterAware) instance;
656                         int status = service.canDetachInterface(target, input);
657                         if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
658                             return Response.status(status).build();
659                         }
660                     }
661                 } else {
662                     throw new ServiceUnavailableException(NO_PROVIDERS);
663                 }
664             } else {
665                 throw new ServiceUnavailableException(NO_PROVIDER_LIST);
666             }
667             input.setID(target.getID());
668             input.setTenantID(target.getTenantID());
669             port.setDeviceID(null);
670             port.setDeviceOwner(null);
671             target.removeInterface(input.getPortUUID());
672             if (instances != null) {
673                 for (Object instance : instances) {
674                     INeutronRouterAware service = (INeutronRouterAware) instance;
675                     service.canDetachInterface(target, input);
676                 }
677             }            for (Object instance : instances) {
678                 INeutronRouterAware service = (INeutronRouterAware) instance;
679                 service.neutronRouterInterfaceDetached(target, input);
680             }
681             return Response.status(HttpURLConnection.HTTP_OK).entity(input).build();
682         }
683
684         // have to specify either a port ID or a subnet ID
685         throw new BadRequestException("Must specify port id or subnet id or both");
686     }
687 }