Make NN more transparent, part III
[neutron.git] / northbound-api / src / main / java / org / opendaylight / neutron / northbound / api / NeutronSubnetsNorthbound.java
1 /*
2  * Copyright IBM Corporation and others, 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.DefaultValue;
20 import javax.ws.rs.GET;
21 import javax.ws.rs.POST;
22 import javax.ws.rs.PUT;
23 import javax.ws.rs.Path;
24 import javax.ws.rs.PathParam;
25 import javax.ws.rs.Produces;
26 import javax.ws.rs.QueryParam;
27 import javax.ws.rs.core.Context;
28 import javax.ws.rs.core.MediaType;
29 import javax.ws.rs.core.Response;
30 import javax.ws.rs.core.UriInfo;
31
32 import org.codehaus.enunciate.jaxrs.ResponseCode;
33 import org.codehaus.enunciate.jaxrs.StatusCodes;
34 import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
35 import org.opendaylight.neutron.spi.INeutronSubnetAware;
36 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
37 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
38 import org.opendaylight.neutron.spi.NeutronSubnet;
39
40 /**
41  * Neutron Northbound REST APIs for Subnets.<br>
42  * This class provides REST APIs for managing neutron Subnets
43  *
44  * <br>
45  * <br>
46  * Authentication scheme : <b>HTTP Basic</b><br>
47  * Authentication realm : <b>opendaylight</b><br>
48  * Transport : <b>HTTP and HTTPS</b><br>
49  * <br>
50  * HTTPS Authentication is disabled by default. Administrator can enable it in
51  * tomcat-server.xml after adding a proper keystore / SSL certificate from a
52  * trusted authority.<br>
53  * More info :
54  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
55  *
56  */
57
58 @Path("/subnets")
59 public class NeutronSubnetsNorthbound {
60     private static final int HTTP_OK_BOTTOM = 200;
61     private static final int HTTP_OK_TOP = 299;
62     private static final String INTERFACE_NAME = "Subnet CRUD Interface";
63     private static final String UUID_NO_EXIST = "Subnet UUID does not exist.";
64     private static final String NO_PROVIDERS = "No providers registered.  Please try again later";
65     private static final String NO_PROVIDER_LIST = "Couldn't get providers list.  Please try again later";
66
67     private NeutronSubnet extractFields(NeutronSubnet o, List<String> fields) {
68         return o.extractFields(fields);
69     }
70
71     private NeutronCRUDInterfaces getNeutronInterfaces(boolean needNetwork) {
72         NeutronCRUDInterfaces answer = new NeutronCRUDInterfaces().fetchINeutronSubnetCRUD(this);
73         if (answer.getSubnetInterface() == null) {
74             throw new ServiceUnavailableException(INTERFACE_NAME
75                 + RestMessages.SERVICEUNAVAILABLE.toString());
76         }
77         if (needNetwork) {
78             answer = answer.fetchINeutronNetworkCRUD(this);
79             if (answer.getNetworkInterface() == null) {
80                 throw new ServiceUnavailableException("Network CRUD Interface "
81                     + RestMessages.SERVICEUNAVAILABLE.toString());
82             }
83         }
84         return answer;
85     }
86
87     @Context
88     UriInfo uriInfo;
89
90     /**
91      * Returns a list of all Subnets */
92     @GET
93     @Produces({ MediaType.APPLICATION_JSON })
94     //@TypeHint(OpenStackSubnets.class)
95     @StatusCodes({
96             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
97             @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
98             @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
99             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
100     public Response listSubnets(
101             // return fields
102             @QueryParam("fields") List<String> fields,
103             // note: openstack isn't clear about filtering on lists, so we aren't handling them
104             @QueryParam("id") String queryID,
105             @QueryParam("network_id") String queryNetworkID,
106             @QueryParam("name") String queryName,
107             @QueryParam("ip_version") String queryIPVersion,
108             @QueryParam("cidr") String queryCIDR,
109             @QueryParam("gateway_ip") String queryGatewayIP,
110             @QueryParam("enable_dhcp") String queryEnableDHCP,
111             @QueryParam("tenant_id") String queryTenantID,
112             @QueryParam("ipv6_address_mode") String queryIpV6AddressMode,
113             @QueryParam("ipv6_ra_mode") String queryIpV6RaMode,
114             // linkTitle
115             @QueryParam("limit") Integer limit,
116             @QueryParam("marker") String marker,
117             @DefaultValue("false") @QueryParam("page_reverse") Boolean pageReverse
118             // sorting not supported
119             ) {
120         INeutronSubnetCRUD subnetInterface = getNeutronInterfaces(false).getSubnetInterface();
121         List<NeutronSubnet> allNetworks = subnetInterface.getAllSubnets();
122         List<NeutronSubnet> ans = new ArrayList<NeutronSubnet>();
123         Iterator<NeutronSubnet> i = allNetworks.iterator();
124         while (i.hasNext()) {
125             NeutronSubnet oSS = i.next();
126             if ((queryID == null || queryID.equals(oSS.getID())) &&
127                     (queryNetworkID == null || queryNetworkID.equals(oSS.getNetworkUUID())) &&
128                     (queryName == null || queryName.equals(oSS.getName())) &&
129                     (queryIPVersion == null || queryIPVersion.equals(oSS.getIpVersion())) &&
130                     (queryCIDR == null || queryCIDR.equals(oSS.getCidr())) &&
131                     (queryGatewayIP == null || queryGatewayIP.equals(oSS.getGatewayIP())) &&
132                     (queryEnableDHCP == null || queryEnableDHCP.equals(oSS.getEnableDHCP())) &&
133                     (queryTenantID == null || queryTenantID.equals(oSS.getTenantID())) &&
134                     (queryIpV6AddressMode == null || queryIpV6AddressMode.equals(oSS.getIpV6AddressMode())) &&
135                     (queryIpV6RaMode == null || queryIpV6RaMode.equals(oSS.getIpV6RaMode()))){
136                 if (fields.size() > 0) {
137                     ans.add(extractFields(oSS,fields));
138                 } else {
139                     ans.add(oSS);
140                 }
141             }
142         }
143
144         if (limit != null && ans.size() > 1) {
145             // Return a paginated request
146             NeutronSubnetRequest request = (NeutronSubnetRequest) PaginatedRequestFactory.createRequest(limit,
147                     marker, pageReverse, uriInfo, ans, NeutronSubnet.class);
148             return Response.status(HttpURLConnection.HTTP_OK).entity(request).build();
149         }
150
151         return Response.status(HttpURLConnection.HTTP_OK).entity(
152                 new NeutronSubnetRequest(ans)).build();
153     }
154
155     /**
156      * Returns a specific Subnet */
157
158     @Path("{subnetUUID}")
159     @GET
160     @Produces({ MediaType.APPLICATION_JSON })
161     //@TypeHint(OpenStackSubnets.class)
162     @StatusCodes({
163             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
164             @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
165             @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
166             @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
167             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
168     public Response showSubnet(
169             @PathParam("subnetUUID") String subnetUUID,
170             // return fields
171             @QueryParam("fields") List<String> fields) {
172         INeutronSubnetCRUD subnetInterface = getNeutronInterfaces(false).getSubnetInterface();
173         if (!subnetInterface.subnetExists(subnetUUID)) {
174             throw new ResourceNotFoundException(UUID_NO_EXIST);
175         }
176         if (fields.size() > 0) {
177             NeutronSubnet ans = subnetInterface.getSubnet(subnetUUID);
178             return Response.status(HttpURLConnection.HTTP_OK).entity(
179                     new NeutronSubnetRequest(extractFields(ans, fields))).build();
180         } else {
181             return Response.status(HttpURLConnection.HTTP_OK).entity(
182                     new NeutronSubnetRequest(subnetInterface.getSubnet(subnetUUID))).build();
183         }
184     }
185
186     /**
187      * Creates new Subnets */
188
189     @POST
190     @Produces({ MediaType.APPLICATION_JSON })
191     @Consumes({ MediaType.APPLICATION_JSON })
192     //@TypeHint(OpenStackSubnets.class)
193     @StatusCodes({
194             @ResponseCode(code = HttpURLConnection.HTTP_CREATED, condition = "Created"),
195             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
196     public Response createSubnets(final NeutronSubnetRequest input) {
197         NeutronCRUDInterfaces interfaces = getNeutronInterfaces(true);
198         INeutronSubnetCRUD subnetInterface = interfaces.getSubnetInterface();
199         if (input.isSingleton()) {
200             NeutronSubnet singleton = input.getSingleton();
201
202             Object[] instances = NeutronUtil.getInstances(INeutronSubnetAware.class, this);
203             if (instances != null) {
204                 if (instances.length > 0) {
205                     for (Object instance : instances) {
206                         INeutronSubnetAware service = (INeutronSubnetAware) instance;
207                         int status = service.canCreateSubnet(singleton);
208                         if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
209                             return Response.status(status).build();
210                         }
211                     }
212                 } else {
213                     throw new ServiceUnavailableException(NO_PROVIDERS);
214                 }
215             } else {
216                 throw new ServiceUnavailableException(NO_PROVIDER_LIST);
217             }
218             subnetInterface.addSubnet(singleton);
219             if (instances != null) {
220                 for (Object instance : instances) {
221                     INeutronSubnetAware service = (INeutronSubnetAware) instance;
222                     service.neutronSubnetCreated(singleton);
223                 }
224             }
225         } else {
226             Object[] instances = NeutronUtil.getInstances(INeutronSubnetAware.class, this);
227             for (NeutronSubnet test : input.getBulk()) {
228                 if (instances != null) {
229                     if (instances.length > 0) {
230                         for (Object instance : instances) {
231                             INeutronSubnetAware service = (INeutronSubnetAware) instance;
232                             int status = service.canCreateSubnet(test);
233                             if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
234                                 return Response.status(status).build();
235                             }
236                         }
237                     } else {
238                         throw new ServiceUnavailableException(NO_PROVIDERS);
239                     }
240                 } else {
241                     throw new ServiceUnavailableException(NO_PROVIDER_LIST);
242                 }
243             }
244
245             /*
246              * now, each element of the bulk request can be added to the cache
247              */
248             for (NeutronSubnet test : input.getBulk()) {
249                 subnetInterface.addSubnet(test);
250                 if (instances != null) {
251                     for (Object instance : instances) {
252                         INeutronSubnetAware service = (INeutronSubnetAware) instance;
253                         service.neutronSubnetCreated(test);
254                     }
255                 }
256             }
257         }
258         return Response.status(HttpURLConnection.HTTP_CREATED).entity(input).build();
259     }
260
261     /**
262      * Updates a Subnet */
263
264     @Path("{subnetUUID}")
265     @PUT
266     @Produces({ MediaType.APPLICATION_JSON })
267     @Consumes({ MediaType.APPLICATION_JSON })
268     //@TypeHint(OpenStackSubnets.class)
269     @StatusCodes({
270             @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
271             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
272     public Response updateSubnet(
273             @PathParam("subnetUUID") String subnetUUID, final NeutronSubnetRequest input
274             ) {
275         INeutronSubnetCRUD subnetInterface = getNeutronInterfaces(false).getSubnetInterface();
276
277         /*
278          * note: what we get appears to not be a delta, but rather a
279          * complete updated object.  So, that needs to be sent down to
280          * folks to check 
281          */
282
283         NeutronSubnet updatedObject = input.getSingleton();
284
285         Object[] instances = NeutronUtil.getInstances(INeutronSubnetAware.class, this);
286         if (instances != null) {
287             if (instances.length > 0) {
288                 for (Object instance : instances) {
289                     INeutronSubnetAware service = (INeutronSubnetAware) instance;
290                     NeutronSubnet original = subnetInterface.getSubnet(subnetUUID);
291                     int status = service.canUpdateSubnet(updatedObject, original);
292                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
293                         return Response.status(status).build();
294                     }
295                 }
296             } else {
297                 throw new ServiceUnavailableException(NO_PROVIDERS);
298             }
299         } else {
300             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
301         }
302
303         /*
304          * update the object and return it
305          */
306         subnetInterface.updateSubnet(subnetUUID, updatedObject);
307         if (instances != null) {
308             for (Object instance : instances) {
309                 INeutronSubnetAware service = (INeutronSubnetAware) instance;
310                 service.neutronSubnetUpdated(updatedObject);
311             }
312         }
313         return Response.status(HttpURLConnection.HTTP_OK).entity(
314                 new NeutronSubnetRequest(subnetInterface.getSubnet(subnetUUID))).build();
315     }
316
317     /**
318      * Deletes a Subnet */
319
320     @Path("{subnetUUID}")
321     @DELETE
322     @StatusCodes({
323             @ResponseCode(code = HttpURLConnection.HTTP_NO_CONTENT, condition = "No Content"),
324             @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
325     public Response deleteSubnet(
326             @PathParam("subnetUUID") String subnetUUID) {
327         INeutronSubnetCRUD subnetInterface = getNeutronInterfaces(false).getSubnetInterface();
328
329         NeutronSubnet singleton = subnetInterface.getSubnet(subnetUUID);
330         Object[] instances = NeutronUtil.getInstances(INeutronSubnetAware.class, this);
331         if (instances != null) {
332             if (instances.length > 0) {
333                 for (Object instance : instances) {
334                     INeutronSubnetAware service = (INeutronSubnetAware) instance;
335                     int status = service.canDeleteSubnet(singleton);
336                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
337                         return Response.status(status).build();
338                     }
339                 }
340             } else {
341                 throw new ServiceUnavailableException(NO_PROVIDERS);
342             }
343         } else {
344             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
345         }
346
347         /*
348          * remove it and return 204 status
349          */
350         subnetInterface.removeSubnet(subnetUUID);
351         if (instances != null) {
352             for (Object instance : instances) {
353                 INeutronSubnetAware service = (INeutronSubnetAware) instance;
354                 service.neutronSubnetDeleted(singleton);
355             }
356         }
357         return Response.status(HttpURLConnection.HTTP_NO_CONTENT).build();
358     }
359 }