Merge changes from topics 'remove_fip_chm', 'fip_tests'
[neutron.git] / northbound-api / src / main / java / org / opendaylight / neutron / northbound / api / NeutronRoutersNorthbound.java
1 /*
2  * Copyright (c) 2013, 2015 IBM Corporation and others.  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.NeutronRouter;
38 import org.opendaylight.neutron.spi.NeutronRouter_Interface;
39
40
41 /**
42  * Neutron Northbound REST APIs.<br>
43  * This class provides REST APIs for managing neutron routers
44  *
45  * <br>
46  * <br>
47  * Authentication scheme : <b>HTTP Basic</b><br>
48  * Authentication realm : <b>opendaylight</b><br>
49  * Transport : <b>HTTP and HTTPS</b><br>
50  * <br>
51  * HTTPS Authentication is disabled by default. Administrator can enable it in
52  * tomcat-server.xml after adding a proper keystore / SSL certificate from a
53  * trusted authority.<br>
54  * More info :
55  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
56  *
57  */
58
59 @Path("/routers")
60 public class NeutronRoutersNorthbound {
61     static final String ROUTER_INTERFACE_STR = "network:router_interface";
62     static final String ROUTER_GATEWAY_STR = "network:router_gateway";
63     private static final int HTTP_OK_BOTTOM = 200;
64     private static final int HTTP_OK_TOP = 299;
65     private static final String INTERFACE_NAME = "Router CRUD Interface";
66     private static final String UUID_NO_EXIST = "Router UUID does not exist.";
67     private static final String NO_PROVIDERS = "No providers registered.  Please try again later";
68     private static final String NO_PROVIDER_LIST = "Couldn't get providers list.  Please try again later";
69
70     private NeutronRouter extractFields(NeutronRouter o, List<String> fields) {
71         return o.extractFields(fields);
72     }
73
74     private NeutronCRUDInterfaces getNeutronInterfaces(boolean flag) {
75         NeutronCRUDInterfaces answer = new NeutronCRUDInterfaces().fetchINeutronRouterCRUD(this);
76         if (answer.getRouterInterface() == null) {
77             throw new ServiceUnavailableException(INTERFACE_NAME
78                 + RestMessages.SERVICEUNAVAILABLE.toString());
79         }
80         if (flag) {
81             answer = answer.fetchINeutronNetworkCRUD(this);
82             if (answer.getNetworkInterface() == null) {
83                 throw new ServiceUnavailableException("Network CRUD Interface "
84                     + RestMessages.SERVICEUNAVAILABLE.toString());
85             }
86         }
87         return answer;
88     }
89
90     private NeutronCRUDInterfaces getAttachInterfaces() {
91         NeutronCRUDInterfaces answer = new NeutronCRUDInterfaces().fetchINeutronRouterCRUD(this);
92         if (answer.getRouterInterface() == null) {
93             throw new ServiceUnavailableException(INTERFACE_NAME
94                     + RestMessages.SERVICEUNAVAILABLE.toString());
95         }
96         answer = answer.fetchINeutronPortCRUD(this).fetchINeutronSubnetCRUD(this);
97         if (answer.getPortInterface() == null) {
98             throw new ServiceUnavailableException("Port CRUD Interface "
99                     + RestMessages.SERVICEUNAVAILABLE.toString());
100         }
101         if (answer.getSubnetInterface() == null) {
102             throw new ServiceUnavailableException("Subnet CRUD Interface "
103                     + RestMessages.SERVICEUNAVAILABLE.toString());
104         }
105         return answer;
106     }
107
108     /**
109      * Returns a list of all Routers */
110
111     @GET
112     @Produces({ MediaType.APPLICATION_JSON })
113     //@TypeHint(OpenStackRouters.class)
114     @StatusCodes({
115             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
116             @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
117             @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
118             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
119     public Response listRouters(
120             // return fields
121             @QueryParam("fields") List<String> fields,
122             // note: openstack isn't clear about filtering on lists, so we aren't handling them
123             @QueryParam("id") String queryID,
124             @QueryParam("name") String queryName,
125             @QueryParam("admin_state_up") String queryAdminStateUp,
126             @QueryParam("status") String queryStatus,
127             @QueryParam("tenant_id") String queryTenantID,
128             @QueryParam("external_gateway_info") String queryExternalGatewayInfo,
129             // pagination
130             @QueryParam("limit") String limit,
131             @QueryParam("marker") String marker,
132             @QueryParam("page_reverse") String pageReverse
133             // sorting not supported
134             ) {
135         INeutronRouterCRUD routerInterface = getNeutronInterfaces(false).getRouterInterface();
136         if (routerInterface == null) {
137             throw new ServiceUnavailableException(INTERFACE_NAME
138                     + RestMessages.SERVICEUNAVAILABLE.toString());
139         }
140         List<NeutronRouter> allRouters = routerInterface.getAllRouters();
141         List<NeutronRouter> ans = new ArrayList<NeutronRouter>();
142         Iterator<NeutronRouter> i = allRouters.iterator();
143         while (i.hasNext()) {
144             NeutronRouter oSS = i.next();
145             if ((queryID == null || queryID.equals(oSS.getID())) &&
146                     (queryName == null || queryName.equals(oSS.getName())) &&
147                     (queryAdminStateUp == null || queryAdminStateUp.equals(oSS.getAdminStateUp())) &&
148                     (queryStatus == null || queryStatus.equals(oSS.getStatus())) &&
149                     (queryExternalGatewayInfo == null || queryExternalGatewayInfo.equals(oSS.getExternalGatewayInfo())) &&
150                     (queryTenantID == null || queryTenantID.equals(oSS.getTenantID()))) {
151                 if (fields.size() > 0) {
152                     ans.add(extractFields(oSS,fields));
153                 } else {
154                     ans.add(oSS);
155                 }
156             }
157         }
158         //TODO: apply pagination to results
159         return Response.status(HttpURLConnection.HTTP_OK).entity(
160                 new NeutronRouterRequest(ans)).build();
161     }
162
163     /**
164      * Returns a specific Router */
165
166     @Path("{routerUUID}")
167     @GET
168     @Produces({ MediaType.APPLICATION_JSON })
169     //@TypeHint(OpenStackRouters.class)
170     @StatusCodes({
171             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
172             @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
173             @ResponseCode(code = HttpURLConnection.HTTP_FORBIDDEN, condition = "Forbidden"),
174             @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
175             @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
176             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
177     public Response showRouter(
178             @PathParam("routerUUID") String routerUUID,
179             // return fields
180             @QueryParam("fields") List<String> fields) {
181         INeutronRouterCRUD routerInterface = getNeutronInterfaces(false).getRouterInterface();
182         if (routerInterface == null) {
183             throw new ServiceUnavailableException(INTERFACE_NAME
184                     + RestMessages.SERVICEUNAVAILABLE.toString());
185         }
186         if (!routerInterface.routerExists(routerUUID)) {
187             throw new ResourceNotFoundException(UUID_NO_EXIST);
188         }
189         if (fields.size() > 0) {
190             NeutronRouter ans = routerInterface.getRouter(routerUUID);
191             return Response.status(HttpURLConnection.HTTP_OK).entity(
192                     new NeutronRouterRequest(extractFields(ans, fields))).build();
193         } else {
194             return Response.status(HttpURLConnection.HTTP_OK).entity(
195                     new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
196         }
197     }
198
199     /**
200      * Creates new Routers */
201
202     @POST
203     @Produces({ MediaType.APPLICATION_JSON })
204     @Consumes({ MediaType.APPLICATION_JSON })
205     //@TypeHint(OpenStackRouters.class)
206     @StatusCodes({
207             @ResponseCode(code = HttpURLConnection.HTTP_CREATED, condition = "Created"),
208             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
209     public Response createRouters(final NeutronRouterRequest input) {
210         NeutronCRUDInterfaces interfaces = getNeutronInterfaces(true);
211         INeutronRouterCRUD routerInterface = interfaces.getRouterInterface();
212         if (input.isSingleton()) {
213             NeutronRouter singleton = input.getSingleton();
214
215             Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
216             if (instances != null) {
217                 if (instances.length > 0) {
218                     for (Object instance : instances) {
219                         INeutronRouterAware service = (INeutronRouterAware) instance;
220                         int status = service.canCreateRouter(singleton);
221                         if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
222                             return Response.status(status).build();
223                         }
224                     }
225                 } else {
226                     throw new ServiceUnavailableException(NO_PROVIDERS);
227                 }
228             } else {
229                 throw new ServiceUnavailableException(NO_PROVIDER_LIST);
230             }
231
232             /*
233              * add router to the cache
234              */
235             routerInterface.addRouter(singleton);
236             if (instances != null) {
237                 for (Object instance : instances) {
238                     INeutronRouterAware service = (INeutronRouterAware) instance;
239                     service.neutronRouterCreated(singleton);
240                 }
241             }
242         } else {
243
244             /*
245              * only singleton router creates supported
246              */
247             throw new BadRequestException("Only singleton router creates supported");
248         }
249         return Response.status(HttpURLConnection.HTTP_CREATED).entity(input).build();
250     }
251
252     /**
253      * Updates a Router */
254
255     @Path("{routerUUID}")
256     @PUT
257     @Produces({ MediaType.APPLICATION_JSON })
258     @Consumes({ MediaType.APPLICATION_JSON })
259     //@TypeHint(OpenStackRouters.class)
260     @StatusCodes({
261             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
262             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
263     public Response updateRouter(
264             @PathParam("routerUUID") String routerUUID,
265             NeutronRouterRequest input
266             ) {
267         NeutronCRUDInterfaces interfaces = getNeutronInterfaces(true);
268         INeutronRouterCRUD routerInterface = interfaces.getRouterInterface();
269         INeutronNetworkCRUD networkInterface = interfaces.getNetworkInterface();
270
271         NeutronRouter updatedRouter = input.getSingleton();
272         NeutronRouter original = routerInterface.getRouter(routerUUID);
273         updatedRouter.setID(routerUUID);
274         updatedRouter.setTenantID(original.getTenantID());
275
276         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
277         if (instances != null) {
278             if (instances.length > 0) {
279                 for (Object instance : instances) {
280                     INeutronRouterAware service = (INeutronRouterAware) instance;
281                     int status = service.canUpdateRouter(updatedRouter, original);
282                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
283                         return Response.status(status).build();
284                     }
285                 }
286             } else {
287                 throw new ServiceUnavailableException(NO_PROVIDERS);
288             }
289         } else {
290             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
291         }
292
293         /*
294          * update the router entry and return the modified object
295          */
296         routerInterface.updateRouter(routerUUID, updatedRouter);
297         if (instances != null) {
298             for (Object instance : instances) {
299                 INeutronRouterAware service = (INeutronRouterAware) instance;
300                 service.neutronRouterUpdated(updatedRouter);
301             }
302         }
303         return Response.status(HttpURLConnection.HTTP_OK).entity(
304                 new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
305
306     }
307
308     /**
309      * Deletes a Router */
310
311     @Path("{routerUUID}")
312     @DELETE
313     @StatusCodes({
314             @ResponseCode(code = HttpURLConnection.HTTP_NO_CONTENT, condition = "No Content"),
315             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
316     public Response deleteRouter(
317             @PathParam("routerUUID") String routerUUID) {
318         INeutronRouterCRUD routerInterface = getNeutronInterfaces(false).getRouterInterface();
319
320         NeutronRouter singleton = routerInterface.getRouter(routerUUID);
321         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
322         if (instances != null) {
323             if (instances.length > 0) {
324                 for (Object instance : instances) {
325                     INeutronRouterAware service = (INeutronRouterAware) instance;
326                     int status = service.canDeleteRouter(singleton);
327                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
328                         return Response.status(status).build();
329                     }
330                 }
331             } else {
332                 throw new ServiceUnavailableException(NO_PROVIDERS);
333             }
334         } else {
335             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
336         }
337         routerInterface.removeRouter(routerUUID);
338         if (instances != null) {
339             for (Object instance : instances) {
340                 INeutronRouterAware service = (INeutronRouterAware) instance;
341                 service.neutronRouterDeleted(singleton);
342             }
343         }
344         return Response.status(HttpURLConnection.HTTP_NO_CONTENT).build();
345     }
346
347     /**
348      * Adds an interface to a router */
349
350     @Path("{routerUUID}/add_router_interface")
351     @PUT
352     @Produces({ MediaType.APPLICATION_JSON })
353     @Consumes({ MediaType.APPLICATION_JSON })
354     //@TypeHint(OpenStackRouterInterfaces.class)
355     @StatusCodes({
356             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
357             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
358     public Response addRouterInterface(
359             @PathParam("routerUUID") String routerUUID,
360             NeutronRouter_Interface input
361             ) {
362         NeutronCRUDInterfaces interfaces = getAttachInterfaces();
363         INeutronRouterCRUD routerInterface = interfaces.getRouterInterface();
364
365         NeutronRouter target = routerInterface.getRouter(routerUUID);
366         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
367         if (instances != null) {
368             if (instances.length > 0) {
369                 for (Object instance : instances) {
370                     INeutronRouterAware service = (INeutronRouterAware) instance;
371                     int status = service.canAttachInterface(target, input);
372                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
373                         return Response.status(status).build();
374                     }
375                 }
376             } else {
377                 throw new ServiceUnavailableException(NO_PROVIDERS);
378             }
379         } else {
380             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
381         }
382
383         target.addInterface(input.getPortUUID(), input);
384         if (instances != null) {
385             for (Object instance : instances) {
386                 INeutronRouterAware service = (INeutronRouterAware) instance;
387                 service.neutronRouterInterfaceAttached(target, input);
388             }
389         }
390
391         return Response.status(HttpURLConnection.HTTP_OK).entity(input).build();
392     }
393
394
395     private int checkDownstreamDetach(NeutronRouter target, NeutronRouter_Interface input) {
396         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
397         if (instances != null) {
398             if (instances.length > 0) {
399                 for (Object instance : instances) {
400                     INeutronRouterAware service = (INeutronRouterAware) instance;
401                     int status = service.canDetachInterface(target, input);
402                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
403                         return status;
404                     }
405                 }
406             } else {
407                 throw new ServiceUnavailableException(NO_PROVIDERS);
408             }
409         } else {
410             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
411         }
412         return HTTP_OK_BOTTOM;
413     }
414
415     /**
416      * Removes an interface to a router */
417
418     @Path("{routerUUID}/remove_router_interface")
419     @PUT
420     @Produces({ MediaType.APPLICATION_JSON })
421     @Consumes({ MediaType.APPLICATION_JSON })
422     //@TypeHint(OpenStackRouterInterfaces.class)
423     @StatusCodes({
424             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
425             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
426     public Response removeRouterInterface(
427             @PathParam("routerUUID") String routerUUID,
428             NeutronRouter_Interface input
429             ) {
430         NeutronCRUDInterfaces interfaces = getAttachInterfaces();
431         INeutronRouterCRUD routerInterface = interfaces.getRouterInterface();
432         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
433
434         NeutronRouter target = routerInterface.getRouter(routerUUID);
435         input.setID(target.getID());
436         input.setTenantID(target.getTenantID());
437         int status = checkDownstreamDetach(target, input);
438         if (status != HTTP_OK_BOTTOM) {
439             return Response.status(status).build();
440         }
441         target.removeInterface(input.getPortUUID());
442         for (Object instance : instances) {
443             INeutronRouterAware service = (INeutronRouterAware) instance;
444             service.neutronRouterInterfaceDetached(target, input);
445         }
446         return Response.status(HttpURLConnection.HTTP_OK).entity(input).build();
447     }
448 }