Remove superfulous class from neutron NB bundle.
[controller.git] / opendaylight / northbound / networkconfiguration / neutron / src / main / java / org / opendaylight / controller / networkconfig / neutron / northbound / NeutronPortsNorthbound.java
1 /*\r
2  * Copyright IBM Corporation, 2013.  All rights reserved.\r
3  *\r
4  * This program and the accompanying materials are made available under the\r
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
6  * and is available at http://www.eclipse.org/legal/epl-v10.html\r
7  */\r
8 \r
9 package org.opendaylight.controller.networkconfig.neutron.northbound;\r
10 \r
11 import java.util.ArrayList;\r
12 import java.util.HashMap;\r
13 import java.util.Iterator;\r
14 import java.util.List;\r
15 import javax.ws.rs.Consumes;\r
16 import javax.ws.rs.DELETE;\r
17 import javax.ws.rs.GET;\r
18 import javax.ws.rs.POST;\r
19 import javax.ws.rs.PUT;\r
20 import javax.ws.rs.Path;\r
21 import javax.ws.rs.PathParam;\r
22 import javax.ws.rs.Produces;\r
23 import javax.ws.rs.QueryParam;\r
24 import javax.ws.rs.core.MediaType;\r
25 import javax.ws.rs.core.Response;\r
26 \r
27 import org.codehaus.enunciate.jaxrs.ResponseCode;\r
28 import org.codehaus.enunciate.jaxrs.StatusCodes;\r
29 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;\r
30 import org.opendaylight.controller.networkconfig.neutron.INeutronPortAware;\r
31 import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;\r
32 import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetAware;\r
33 import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;\r
34 import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;\r
35 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;\r
36 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;\r
37 import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;\r
38 import org.opendaylight.controller.northbound.commons.RestMessages;\r
39 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;\r
40 import org.opendaylight.controller.sal.utils.ServiceHelper;\r
41 \r
42 /**\r
43  * Open DOVE Northbound REST APIs.<br>\r
44  * This class provides REST APIs for managing the open DOVE\r
45  *\r
46  * <br>\r
47  * <br>\r
48  * Authentication scheme : <b>HTTP Basic</b><br>\r
49  * Authentication realm : <b>opendaylight</b><br>\r
50  * Transport : <b>HTTP and HTTPS</b><br>\r
51  * <br>\r
52  * HTTPS Authentication is disabled by default. Administrator can enable it in\r
53  * tomcat-server.xml after adding a proper keystore / SSL certificate from a\r
54  * trusted authority.<br>\r
55  * More info :\r
56  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration\r
57  *\r
58  */\r
59 \r
60 @Path("/ports")\r
61 public class NeutronPortsNorthbound {\r
62 \r
63     private NeutronPort extractFields(NeutronPort o, List<String> fields) {\r
64         return o.extractFields(fields);\r
65     }\r
66 \r
67     /**\r
68      * Returns a list of all Ports */\r
69 \r
70     @GET\r
71     @Produces({ MediaType.APPLICATION_JSON })\r
72     //@TypeHint(OpenStackPorts.class)\r
73     @StatusCodes({\r
74             @ResponseCode(code = 200, condition = "Operation successful"),\r
75             @ResponseCode(code = 401, condition = "Unauthorized"),\r
76             @ResponseCode(code = 501, condition = "Not Implemented") })\r
77     public Response listPorts(\r
78             // return fields\r
79             @QueryParam("fields") List<String> fields,\r
80             // note: openstack isn't clear about filtering on lists, so we aren't handling them\r
81             @QueryParam("id") String queryID,\r
82             @QueryParam("network_id") String queryNetworkID,\r
83             @QueryParam("name") String queryName,\r
84             @QueryParam("admin_state_up") String queryAdminStateUp,\r
85             @QueryParam("status") String queryStatus,\r
86             @QueryParam("mac_address") String queryMACAddress,\r
87             @QueryParam("device_id") String queryDeviceID,\r
88             @QueryParam("device_owner") String queryDeviceOwner,\r
89             @QueryParam("tenant_id") String queryTenantID,\r
90             // pagination\r
91             @QueryParam("limit") String limit,\r
92             @QueryParam("marker") String marker,\r
93             @QueryParam("page_reverse") String pageReverse\r
94             // sorting not supported\r
95             ) {\r
96         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);\r
97         if (portInterface == null) {\r
98             throw new ServiceUnavailableException("Port CRUD Interface "\r
99                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
100         }\r
101         List<NeutronPort> allPorts = portInterface.getAllPorts();\r
102         List<NeutronPort> ans = new ArrayList<NeutronPort>();\r
103         Iterator<NeutronPort> i = allPorts.iterator();\r
104         while (i.hasNext()) {\r
105             NeutronPort oSS = i.next();\r
106             if ((queryID == null || queryID.equals(oSS.getID())) &&\r
107                     (queryNetworkID == null || queryNetworkID.equals(oSS.getNetworkUUID())) &&\r
108                     (queryName == null || queryName.equals(oSS.getName())) &&\r
109                     (queryAdminStateUp == null || queryAdminStateUp.equals(oSS.getAdminStateUp())) &&\r
110                     (queryStatus == null || queryStatus.equals(oSS.getStatus())) &&\r
111                     (queryMACAddress == null || queryMACAddress.equals(oSS.getMacAddress())) &&\r
112                     (queryDeviceID == null || queryDeviceID.equals(oSS.getDeviceID())) &&\r
113                     (queryDeviceOwner == null || queryDeviceOwner.equals(oSS.getDeviceOwner())) &&\r
114                     (queryTenantID == null || queryTenantID.equals(oSS.getTenantID()))) {\r
115                 if (fields.size() > 0)\r
116                     ans.add(extractFields(oSS,fields));\r
117                 else\r
118                     ans.add(oSS);\r
119             }\r
120         }\r
121         //TODO: apply pagination to results\r
122         return Response.status(200).entity(\r
123                 new NeutronPortRequest(ans)).build();\r
124     }\r
125 \r
126     /**\r
127      * Returns a specific Port */\r
128 \r
129     @Path("{portUUID}")\r
130     @GET\r
131     @Produces({ MediaType.APPLICATION_JSON })\r
132     //@TypeHint(OpenStackPorts.class)\r
133     @StatusCodes({\r
134             @ResponseCode(code = 200, condition = "Operation successful"),\r
135             @ResponseCode(code = 401, condition = "Unauthorized"),\r
136             @ResponseCode(code = 404, condition = "Not Found"),\r
137             @ResponseCode(code = 501, condition = "Not Implemented") })\r
138     public Response showPort(\r
139             @PathParam("portUUID") String portUUID,\r
140             // return fields\r
141             @QueryParam("fields") List<String> fields ) {\r
142         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);\r
143         if (portInterface == null) {\r
144             throw new ServiceUnavailableException("Port CRUD Interface "\r
145                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
146         }\r
147         if (!portInterface.portExists(portUUID))\r
148             return Response.status(404).build();\r
149         if (fields.size() > 0) {\r
150             NeutronPort ans = portInterface.getPort(portUUID);\r
151             return Response.status(200).entity(\r
152                     new NeutronPortRequest(extractFields(ans, fields))).build();\r
153         } else\r
154             return Response.status(200).entity(\r
155                     new NeutronPortRequest(portInterface.getPort(portUUID))).build();\r
156     }\r
157 \r
158     /**\r
159      * Creates new Ports */\r
160 \r
161     @POST\r
162     @Produces({ MediaType.APPLICATION_JSON })\r
163     @Consumes({ MediaType.APPLICATION_JSON })\r
164     //@TypeHint(OpenStackPorts.class)\r
165     @StatusCodes({\r
166             @ResponseCode(code = 201, condition = "Created"),\r
167             @ResponseCode(code = 400, condition = "Bad Request"),\r
168             @ResponseCode(code = 401, condition = "Unauthorized"),\r
169             @ResponseCode(code = 403, condition = "Forbidden"),\r
170             @ResponseCode(code = 404, condition = "Not Found"),\r
171             @ResponseCode(code = 409, condition = "Conflict"),\r
172             @ResponseCode(code = 501, condition = "Not Implemented"),\r
173             @ResponseCode(code = 503, condition = "MAC generation failure") })\r
174     public Response createPorts(final NeutronPortRequest input) {\r
175         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);\r
176         if (portInterface == null) {\r
177             throw new ServiceUnavailableException("Port CRUD Interface "\r
178                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
179         }\r
180         INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);\r
181         if (networkInterface == null) {\r
182             throw new ServiceUnavailableException("Network CRUD Interface "\r
183                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
184         }\r
185         INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);\r
186         if (subnetInterface == null) {\r
187             throw new ServiceUnavailableException("Subnet CRUD Interface "\r
188                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
189         }\r
190         if (input.isSingleton()) {\r
191             NeutronPort singleton = input.getSingleton();\r
192 \r
193             /*\r
194              * the port must be part of an existing network, must not already exist,\r
195              * have a valid MAC and the MAC not be in use\r
196              */\r
197             if (singleton.getNetworkUUID() == null)\r
198                 return Response.status(400).build();\r
199             if (portInterface.portExists(singleton.getID()))\r
200                 return Response.status(400).build();\r
201             if (!networkInterface.networkExists(singleton.getNetworkUUID()))\r
202                 return Response.status(404).build();\r
203             if (singleton.getMacAddress() == null ||\r
204                     !singleton.getMacAddress().matches("^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$"))\r
205                 return Response.status(400).build();\r
206             if (portInterface.macInUse(singleton.getMacAddress()))\r
207                 return Response.status(409).build();\r
208             Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);\r
209             if (instances != null) {\r
210                 for (Object instance : instances) {\r
211                     INeutronPortAware service = (INeutronPortAware) instance;\r
212                     int status = service.canCreatePort(singleton);\r
213                     if (status < 200 || status > 299)\r
214                         return Response.status(status).build();\r
215                 }\r
216             }\r
217             /*\r
218              * if fixed IPs are specified, each one has to have an existing subnet ID\r
219              * that is in the same scoping network as the port.  In addition, if an IP\r
220              * address is specified it has to be a valid address for the subnet and not\r
221              * already in use\r
222              */\r
223             List<Neutron_IPs> fixedIPs = singleton.getFixedIPs();\r
224             if (fixedIPs != null && fixedIPs.size() > 0) {\r
225                 Iterator<Neutron_IPs> fixedIPIterator = fixedIPs.iterator();\r
226                 while (fixedIPIterator.hasNext()) {\r
227                     Neutron_IPs ip = fixedIPIterator.next();\r
228                     if (ip.getSubnetUUID() == null)\r
229                         return Response.status(400).build();\r
230                     if (!subnetInterface.subnetExists(ip.getSubnetUUID()))\r
231                         return Response.status(400).build();\r
232                     NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());\r
233                     if (!singleton.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID()))\r
234                         return Response.status(400).build();\r
235                     if (ip.getIpAddress() != null) {\r
236                         if (!subnet.isValidIP(ip.getIpAddress()))\r
237                             return Response.status(400).build();\r
238                         if (subnet.isIPInUse(ip.getIpAddress()))\r
239                             return Response.status(409).build();\r
240                     }\r
241                 }\r
242             }\r
243 \r
244             // add the port to the cache\r
245             portInterface.addPort(singleton);\r
246             if (instances != null) {\r
247                 for (Object instance : instances) {\r
248                     INeutronPortAware service = (INeutronPortAware) instance;\r
249                     service.neutronPortCreated(singleton);\r
250                 }\r
251             }\r
252         } else {\r
253             List<NeutronPort> bulk = input.getBulk();\r
254             Iterator<NeutronPort> i = bulk.iterator();\r
255             HashMap<String, NeutronPort> testMap = new HashMap<String, NeutronPort>();\r
256             Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);\r
257             while (i.hasNext()) {\r
258                 NeutronPort test = i.next();\r
259 \r
260                 /*\r
261                  * the port must be part of an existing network, must not already exist,\r
262                  * have a valid MAC and the MAC not be in use.  Further the bulk request\r
263                  * can't already contain a new port with the same UUID\r
264                  */\r
265                 if (portInterface.portExists(test.getID()))\r
266                     return Response.status(400).build();\r
267                 if (testMap.containsKey(test.getID()))\r
268                     return Response.status(400).build();\r
269                 for (NeutronPort check : testMap.values()) {\r
270                     if (test.getMacAddress().equalsIgnoreCase(check.getMacAddress()))\r
271                         return Response.status(409).build();\r
272                     for (Neutron_IPs test_fixedIP : test.getFixedIPs()) {\r
273                         for (Neutron_IPs check_fixedIP : check.getFixedIPs()) {\r
274                             if (test_fixedIP.getIpAddress().equals(check_fixedIP.getIpAddress()))\r
275                                 return Response.status(409).build();\r
276                         }\r
277                     }\r
278                 }\r
279                 testMap.put(test.getID(), test);\r
280                 if (!networkInterface.networkExists(test.getNetworkUUID()))\r
281                     return Response.status(404).build();\r
282                 if (!test.getMacAddress().matches("^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$"))\r
283                     return Response.status(400).build();\r
284                 if (portInterface.macInUse(test.getMacAddress()))\r
285                     return Response.status(409).build();\r
286                 if (instances != null) {\r
287                     for (Object instance : instances) {\r
288                         INeutronPortAware service = (INeutronPortAware) instance;\r
289                         int status = service.canCreatePort(test);\r
290                         if (status < 200 || status > 299)\r
291                             return Response.status(status).build();\r
292                     }\r
293                 }\r
294                 /*\r
295                  * if fixed IPs are specified, each one has to have an existing subnet ID\r
296                  * that is in the same scoping network as the port.  In addition, if an IP\r
297                  * address is specified it has to be a valid address for the subnet and not\r
298                  * already in use (or be the gateway IP address of the subnet)\r
299                  */\r
300                 List<Neutron_IPs> fixedIPs = test.getFixedIPs();\r
301                 if (fixedIPs != null && fixedIPs.size() > 0) {\r
302                     Iterator<Neutron_IPs> fixedIPIterator = fixedIPs.iterator();\r
303                     while (fixedIPIterator.hasNext()) {\r
304                         Neutron_IPs ip = fixedIPIterator.next();\r
305                         if (ip.getSubnetUUID() == null)\r
306                             return Response.status(400).build();\r
307                         if (!subnetInterface.subnetExists(ip.getSubnetUUID()))\r
308                             return Response.status(400).build();\r
309                         NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());\r
310                         if (!test.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID()))\r
311                             return Response.status(400).build();\r
312                         if (ip.getIpAddress() != null) {\r
313                             if (!subnet.isValidIP(ip.getIpAddress()))\r
314                                 return Response.status(400).build();\r
315                             //TODO: need to add consideration for a fixed IP being assigned the same address as a allocated IP in the\r
316                             //same bulk create\r
317                             if (subnet.isIPInUse(ip.getIpAddress()))\r
318                                 return Response.status(409).build();\r
319                         }\r
320                     }\r
321                 }\r
322             }\r
323 \r
324             //once everything has passed, then we can add to the cache\r
325             i = bulk.iterator();\r
326             while (i.hasNext()) {\r
327                 NeutronPort test = i.next();\r
328                 portInterface.addPort(test);\r
329                 if (instances != null) {\r
330                     for (Object instance : instances) {\r
331                         INeutronPortAware service = (INeutronPortAware) instance;\r
332                         service.neutronPortCreated(test);\r
333                     }\r
334                 }\r
335             }\r
336         }\r
337         return Response.status(201).entity(input).build();\r
338     }\r
339 \r
340     /**\r
341      * Updates a Port */\r
342 \r
343     @Path("{portUUID}")\r
344     @PUT\r
345     @Produces({ MediaType.APPLICATION_JSON })\r
346     @Consumes({ MediaType.APPLICATION_JSON })\r
347     //@TypeHint(OpenStackPorts.class)\r
348     @StatusCodes({\r
349             @ResponseCode(code = 200, condition = "Operation successful"),\r
350             @ResponseCode(code = 400, condition = "Bad Request"),\r
351             @ResponseCode(code = 401, condition = "Unauthorized"),\r
352             @ResponseCode(code = 403, condition = "Forbidden"),\r
353             @ResponseCode(code = 404, condition = "Not Found"),\r
354             @ResponseCode(code = 409, condition = "Conflict"),\r
355             @ResponseCode(code = 501, condition = "Not Implemented") })\r
356     public Response updatePort(\r
357             @PathParam("portUUID") String portUUID,\r
358             NeutronPortRequest input\r
359             ) {\r
360         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);\r
361         if (portInterface == null) {\r
362             throw new ServiceUnavailableException("Port CRUD Interface "\r
363                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
364         }\r
365         INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);\r
366         if (subnetInterface == null) {\r
367             throw new ServiceUnavailableException("Subnet CRUD Interface "\r
368                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
369         }\r
370 \r
371         // port has to exist and only a single delta is supported\r
372         if (!portInterface.portExists(portUUID))\r
373             return Response.status(404).build();\r
374         NeutronPort target = portInterface.getPort(portUUID);\r
375         if (!input.isSingleton())\r
376             return Response.status(400).build();\r
377         NeutronPort singleton = input.getSingleton();\r
378         NeutronPort original = portInterface.getPort(portUUID);\r
379 \r
380         // deltas restricted by Neutron\r
381         if (singleton.getID() != null || singleton.getTenantID() != null ||\r
382                 singleton.getStatus() != null)\r
383             return Response.status(400).build();\r
384 \r
385         Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);\r
386         if (instances != null) {\r
387             for (Object instance : instances) {\r
388                 INeutronPortAware service = (INeutronPortAware) instance;\r
389                 int status = service.canUpdatePort(singleton, original);\r
390                 if (status < 200 || status > 299)\r
391                     return Response.status(status).build();\r
392             }\r
393         }\r
394 \r
395         // Verify the new fixed ips are valid\r
396         List<Neutron_IPs> fixedIPs = singleton.getFixedIPs();\r
397         if (fixedIPs != null && fixedIPs.size() > 0) {\r
398             Iterator<Neutron_IPs> fixedIPIterator = fixedIPs.iterator();\r
399             while (fixedIPIterator.hasNext()) {\r
400                 Neutron_IPs ip = fixedIPIterator.next();\r
401                 if (ip.getSubnetUUID() == null)\r
402                     return Response.status(400).build();\r
403                 if (!subnetInterface.subnetExists(ip.getSubnetUUID()))\r
404                     return Response.status(400).build();\r
405                 NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());\r
406                 if (!target.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID()))\r
407                     return Response.status(400).build();\r
408                 if (ip.getIpAddress() != null) {\r
409                     if (!subnet.isValidIP(ip.getIpAddress()))\r
410                         return Response.status(400).build();\r
411                     if (subnet.isIPInUse(ip.getIpAddress()))\r
412                         return Response.status(409).build();\r
413                 }\r
414             }\r
415         }\r
416 \r
417 //        TODO: Support change of security groups\r
418         // update the port and return the modified object\r
419         portInterface.updatePort(portUUID, singleton);\r
420         NeutronPort updatedPort = portInterface.getPort(portUUID);\r
421         if (instances != null) {\r
422             for (Object instance : instances) {\r
423                 INeutronPortAware service = (INeutronPortAware) instance;\r
424                 service.neutronPortUpdated(updatedPort);\r
425             }\r
426         }\r
427         return Response.status(200).entity(\r
428                 new NeutronPortRequest(updatedPort)).build();\r
429 \r
430     }\r
431 \r
432     /**\r
433      * Deletes a Port */\r
434 \r
435     @Path("{portUUID}")\r
436     @DELETE\r
437     @StatusCodes({\r
438         @ResponseCode(code = 204, condition = "No Content"),\r
439         @ResponseCode(code = 401, condition = "Unauthorized"),\r
440         @ResponseCode(code = 403, condition = "Forbidden"),\r
441         @ResponseCode(code = 404, condition = "Not Found"),\r
442         @ResponseCode(code = 501, condition = "Not Implemented") })\r
443     public Response deletePort(\r
444             @PathParam("portUUID") String portUUID) {\r
445         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);\r
446         if (portInterface == null) {\r
447             throw new ServiceUnavailableException("Port CRUD Interface "\r
448                     + RestMessages.SERVICEUNAVAILABLE.toString());\r
449         }\r
450 \r
451         // port has to exist and not be owned by anyone.  then it can be removed from the cache\r
452         if (!portInterface.portExists(portUUID))\r
453             return Response.status(404).build();\r
454         NeutronPort port = portInterface.getPort(portUUID);\r
455         if (port.getDeviceID() != null ||\r
456                 port.getDeviceOwner() != null)\r
457             Response.status(403).build();\r
458         NeutronPort singleton = portInterface.getPort(portUUID);\r
459         Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);\r
460         if (instances != null) {\r
461             for (Object instance : instances) {\r
462                 INeutronPortAware service = (INeutronPortAware) instance;\r
463                 int status = service.canDeletePort(singleton);\r
464                 if (status < 200 || status > 299)\r
465                     return Response.status(status).build();\r
466             }\r
467         }\r
468         portInterface.removePort(portUUID);\r
469         if (instances != null) {\r
470             for (Object instance : instances) {\r
471                 INeutronPortAware service = (INeutronPortAware) instance;\r
472                 service.neutronPortDeleted(singleton);\r
473             }\r
474         }\r
475         return Response.status(204).build();\r
476     }\r
477 }\r