23e9b0448c0e58f210013f2e23c0411ba07af22e
[neutron.git] / northbound-api / src / main / java / org / opendaylight / neutron / northbound / api / NeutronPortsNorthbound.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.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
17
18 import javax.ws.rs.Consumes;
19 import javax.ws.rs.DELETE;
20 import javax.ws.rs.DefaultValue;
21 import javax.ws.rs.GET;
22 import javax.ws.rs.POST;
23 import javax.ws.rs.PUT;
24 import javax.ws.rs.Path;
25 import javax.ws.rs.PathParam;
26 import javax.ws.rs.Produces;
27 import javax.ws.rs.QueryParam;
28 import javax.ws.rs.core.Context;
29 import javax.ws.rs.core.MediaType;
30 import javax.ws.rs.core.Response;
31 import javax.ws.rs.core.UriInfo;
32
33 import org.codehaus.enunciate.jaxrs.ResponseCode;
34 import org.codehaus.enunciate.jaxrs.StatusCodes;
35 import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
36 import org.opendaylight.neutron.spi.INeutronPortAware;
37 import org.opendaylight.neutron.spi.INeutronPortCRUD;
38 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
39 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
40 import org.opendaylight.neutron.spi.NeutronPort;
41 import org.opendaylight.neutron.spi.NeutronSubnet;
42 import org.opendaylight.neutron.spi.Neutron_IPs;
43
44 /**
45  * Neutron Northbound REST APIs.<br>
46  * This class provides REST APIs for managing neutron port objects
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("/ports")
63 public class NeutronPortsNorthbound {
64
65     private static final int HTTP_OK_BOTTOM = 200;
66     private static final int HTTP_OK_TOP = 299;
67     private static final String INTERFACE_NAME = "Port CRUD Interface";
68     private static final String UUID_NO_EXIST = "Port UUID does not exist.";
69     private static final String UUID_EXISTS = "Port UUID already exists.";
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     private static final String NET_UUID_MATCH = "Network UUID must match that of subnet";
73
74     private static final String MAC_REGEX="^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$";
75
76     private NeutronPort extractFields(NeutronPort o, List<String> fields) {
77         return o.extractFields(fields);
78     }
79
80     private NeutronCRUDInterfaces getNeutronInterfaces(boolean needNetworks, boolean needSubnets) {
81         NeutronCRUDInterfaces answer = new NeutronCRUDInterfaces().fetchINeutronPortCRUD(this);
82         if (answer.getPortInterface() == null) {
83             throw new ServiceUnavailableException(INTERFACE_NAME
84                 + RestMessages.SERVICEUNAVAILABLE.toString());
85         }
86         if (needNetworks) {
87             answer = answer.fetchINeutronNetworkCRUD( this);
88             if (answer.getNetworkInterface() == null) {
89                 throw new ServiceUnavailableException("Network CRUD Interface "
90                         + RestMessages.SERVICEUNAVAILABLE.toString());
91             }
92         }
93         if (needSubnets) {
94             answer = answer.fetchINeutronSubnetCRUD( this);
95             if (answer.getSubnetInterface() == null) {
96                 throw new ServiceUnavailableException("Subnet CRUD Interface "
97                         + RestMessages.SERVICEUNAVAILABLE.toString());
98             }
99         }
100         return answer;
101     }
102
103     @Context
104     UriInfo uriInfo;
105
106     /**
107      * Returns a list of all Ports */
108
109     @GET
110     @Produces({ MediaType.APPLICATION_JSON })
111     //@TypeHint(OpenStackPorts.class)
112     @StatusCodes({
113         @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
114         @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
115         @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
116         @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
117     public Response listPorts(
118             // return fields
119             @QueryParam("fields") List<String> fields,
120             // note: openstack isn't clear about filtering on lists, so we aren't handling them
121             @QueryParam("id") String queryID,
122             @QueryParam("network_id") String queryNetworkID,
123             @QueryParam("name") String queryName,
124             @QueryParam("admin_state_up") String queryAdminStateUp,
125             @QueryParam("status") String queryStatus,
126             @QueryParam("mac_address") String queryMACAddress,
127             @QueryParam("device_id") String queryDeviceID,
128             @QueryParam("device_owner") String queryDeviceOwner,
129             @QueryParam("tenant_id") String queryTenantID,
130             // linkTitle
131             @QueryParam("limit") Integer limit,
132             @QueryParam("marker") String marker,
133             @DefaultValue("false") @QueryParam("page_reverse") Boolean pageReverse
134             // sorting not supported
135             ) {
136         INeutronPortCRUD portInterface = getNeutronInterfaces(false, false).getPortInterface();
137         List<NeutronPort> allPorts = portInterface.getAllPorts();
138         List<NeutronPort> ans = new ArrayList<NeutronPort>();
139         Iterator<NeutronPort> i = allPorts.iterator();
140         while (i.hasNext()) {
141             NeutronPort oSS = i.next();
142             if ((queryID == null || queryID.equals(oSS.getID())) &&
143                     (queryNetworkID == null || queryNetworkID.equals(oSS.getNetworkUUID())) &&
144                     (queryName == null || queryName.equals(oSS.getName())) &&
145                     (queryAdminStateUp == null || queryAdminStateUp.equals(oSS.getAdminStateUp())) &&
146                     (queryStatus == null || queryStatus.equals(oSS.getStatus())) &&
147                     (queryMACAddress == null || queryMACAddress.equals(oSS.getMacAddress())) &&
148                     (queryDeviceID == null || queryDeviceID.equals(oSS.getDeviceID())) &&
149                     (queryDeviceOwner == null || queryDeviceOwner.equals(oSS.getDeviceOwner())) &&
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
159         if (limit != null && ans.size() > 1) {
160             // Return a paginated request
161             NeutronPortRequest request = (NeutronPortRequest) PaginatedRequestFactory.createRequest(limit,
162                     marker, pageReverse, uriInfo, ans, NeutronPort.class);
163             return Response.status(HttpURLConnection.HTTP_OK).entity(request).build();
164         }
165
166         return Response.status(HttpURLConnection.HTTP_OK).entity(
167                 new NeutronPortRequest(ans)).build();
168     }
169
170     /**
171      * Returns a specific Port */
172
173     @Path("{portUUID}")
174     @GET
175     @Produces({ MediaType.APPLICATION_JSON })
176     //@TypeHint(OpenStackPorts.class)
177     @StatusCodes({
178         @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
179         @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
180         @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
181         @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
182         @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
183     public Response showPort(
184             @PathParam("portUUID") String portUUID,
185             // return fields
186             @QueryParam("fields") List<String> fields ) {
187         INeutronPortCRUD portInterface = getNeutronInterfaces(false, false).getPortInterface();
188         if (!portInterface.portExists(portUUID)) {
189             throw new ResourceNotFoundException(UUID_NO_EXIST);
190         }
191         if (fields.size() > 0) {
192             NeutronPort ans = portInterface.getPort(portUUID);
193             return Response.status(HttpURLConnection.HTTP_OK).entity(
194                     new NeutronPortRequest(extractFields(ans, fields))).build();
195         } else {
196             return Response.status(HttpURLConnection.HTTP_OK).entity(
197                     new NeutronPortRequest(portInterface.getPort(portUUID))).build();
198         }
199     }
200
201     /**
202      * Creates new Ports */
203
204     @POST
205     @Produces({ MediaType.APPLICATION_JSON })
206     @Consumes({ MediaType.APPLICATION_JSON })
207     //@TypeHint(OpenStackPorts.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_FORBIDDEN, condition = "Forbidden"),
213         @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
214         @ResponseCode(code = HttpURLConnection.HTTP_CONFLICT, condition = "Conflict"),
215         @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
216         @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "MAC generation failure"),
217         @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
218     public Response createPorts(final NeutronPortRequest input) {
219         NeutronCRUDInterfaces interfaces = getNeutronInterfaces(true, true);
220         INeutronPortCRUD portInterface = interfaces.getPortInterface();
221         INeutronNetworkCRUD networkInterface = interfaces.getNetworkInterface();
222         INeutronSubnetCRUD subnetInterface = interfaces.getSubnetInterface();
223         if (input.isSingleton()) {
224             NeutronPort singleton = input.getSingleton();
225
226             /*
227              * the port must be part of an existing network, must not already exist,
228              * have a valid MAC and the MAC not be in use
229              */
230             if (singleton.getNetworkUUID() == null) {
231                 throw new BadRequestException("network UUID musy be specified");
232             }
233             if (portInterface.portExists(singleton.getID())) {
234                 throw new BadRequestException(UUID_EXISTS);
235             }
236             if (!networkInterface.networkExists(singleton.getNetworkUUID())) {
237                 throw new ResourceNotFoundException("network UUID does not exist.");
238             }
239             if (singleton.getMacAddress() == null ||
240                     !singleton.getMacAddress().matches(MAC_REGEX)) {
241                 throw new BadRequestException("MAC address not properly formatted");
242             }
243             if (portInterface.macInUse(singleton.getMacAddress())) {
244                 throw new ResourceConflictException("MAC Address is in use.");
245             }
246             /*
247              * if fixed IPs are specified, each one has to have an existing subnet ID
248              * that is in the same scoping network as the port.  In addition, if an IP
249              * address is specified it has to be a valid address for the subnet and not
250              * already in use
251              */
252             List<Neutron_IPs> fixedIPs = singleton.getFixedIPs();
253             if (fixedIPs != null && fixedIPs.size() > 0) {
254                 Iterator<Neutron_IPs> fixedIPIterator = fixedIPs.iterator();
255                 while (fixedIPIterator.hasNext()) {
256                     Neutron_IPs ip = fixedIPIterator.next();
257                     if (ip.getSubnetUUID() == null) {
258                         throw new BadRequestException("subnet UUID not specified");
259                     }
260                     NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
261                     if (subnet == null) {
262                         throw new BadRequestException("subnet UUID must exist");
263                     }
264                     if (!singleton.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
265                         throw new BadRequestException(NET_UUID_MATCH);
266                     }
267                     if (ip.getIpAddress() != null) {
268                         if (!subnet.isValidIP(ip.getIpAddress())) {
269                             throw new BadRequestException("IP address is not valid");
270                         }
271                         if (subnet.isIPInUse(ip.getIpAddress())) {
272                             throw new ResourceConflictException("IP address is in use.");
273                         }
274                     }
275                 }
276             }
277
278             Object[] instances = NeutronUtil.getInstances(INeutronPortAware.class, this);
279             if (instances != null) {
280                 if (instances.length > 0) {
281                     for (Object instance : instances) {
282                         INeutronPortAware service = (INeutronPortAware) instance;
283                         int status = service.canCreatePort(singleton);
284                         if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
285                             return Response.status(status).build();
286                         }
287                     }
288                 } else {
289                     throw new ServiceUnavailableException(NO_PROVIDERS);
290                 }
291             } else {
292                 throw new ServiceUnavailableException(NO_PROVIDER_LIST);
293             }
294
295             // add the port to the cache
296             portInterface.addPort(singleton);
297             if (instances != null) {
298                 for (Object instance : instances) {
299                     INeutronPortAware service = (INeutronPortAware) instance;
300                     service.neutronPortCreated(singleton);
301                 }
302             }
303         } else {
304             List<NeutronPort> bulk = input.getBulk();
305             Iterator<NeutronPort> i = bulk.iterator();
306             HashMap<String, NeutronPort> testMap = new HashMap<String, NeutronPort>();
307             Object[] instances = NeutronUtil.getInstances(INeutronPortAware.class, this);
308             while (i.hasNext()) {
309                 NeutronPort test = i.next();
310
311                 /*
312                  * the port must be part of an existing network, must not already exist,
313                  * have a valid MAC and the MAC not be in use.  Further the bulk request
314                  * can't already contain a new port with the same UUID
315                  */
316                 if (portInterface.portExists(test.getID())) {
317                     throw new BadRequestException(UUID_EXISTS);
318                 }
319                 if (testMap.containsKey(test.getID())) {
320                     throw new BadRequestException(UUID_EXISTS);
321                 }
322                 for (NeutronPort check : testMap.values()) {
323                     if (test.getMacAddress().equalsIgnoreCase(check.getMacAddress())) {
324                         throw new ResourceConflictException("MAC address already allocated");
325                     }
326                     for (Neutron_IPs test_fixedIP : test.getFixedIPs()) {
327                         for (Neutron_IPs check_fixedIP : check.getFixedIPs()) {
328                             if (test_fixedIP.getSubnetUUID().equals(check_fixedIP.getSubnetUUID()) &&
329                                 (test_fixedIP.getIpAddress().equals(check_fixedIP.getIpAddress()))) {
330                                 throw new ResourceConflictException("IP address already allocated");
331                             }
332                         }
333                     }
334                 }
335                 testMap.put(test.getID(), test);
336                 if (!networkInterface.networkExists(test.getNetworkUUID())) {
337                     throw new ResourceNotFoundException("network UUID does not exist.");
338                 }
339                 if (!test.getMacAddress().matches(MAC_REGEX)) {
340                     throw new BadRequestException("MAC address not properly formatted");
341                 }
342                 if (portInterface.macInUse(test.getMacAddress())) {
343                     throw new ResourceConflictException("MAC address in use");
344                 }
345
346                 /*
347                  * if fixed IPs are specified, each one has to have an existing subnet ID
348                  * that is in the same scoping network as the port.  In addition, if an IP
349                  * address is specified it has to be a valid address for the subnet and not
350                  * already in use (or be the gateway IP address of the subnet)
351                  */
352                 List<Neutron_IPs> fixedIPs = test.getFixedIPs();
353                 if (fixedIPs != null && fixedIPs.size() > 0) {
354                     Iterator<Neutron_IPs> fixedIPIterator = fixedIPs.iterator();
355                     while (fixedIPIterator.hasNext()) {
356                         Neutron_IPs ip = fixedIPIterator.next();
357                         if (ip.getSubnetUUID() == null) {
358                             throw new BadRequestException("subnet UUID must be specified");
359                         }
360                         if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
361                             throw new BadRequestException("subnet UUID doesn't exists");
362                         }
363                         NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
364                         if (!test.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
365                             throw new BadRequestException(NET_UUID_MATCH);
366                         }
367                         if (ip.getIpAddress() != null) {
368                             if (!subnet.isValidIP(ip.getIpAddress())) {
369                                 throw new BadRequestException("ip address not valid");
370                             }
371                             //TODO: need to add consideration for a fixed IP being assigned the same address as a allocated IP in the
372                             //same bulk create
373                             if (subnet.isIPInUse(ip.getIpAddress())) {
374                                 throw new ResourceConflictException("IP address in use");
375                             }
376                         }
377                     }
378                 }
379                 if (instances != null) {
380                     if (instances.length > 0) {
381                         for (Object instance : instances) {
382                             INeutronPortAware service = (INeutronPortAware) instance;
383                             int status = service.canCreatePort(test);
384                             if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
385                                 return Response.status(status).build();
386                             }
387                         }
388                     } else {
389                         throw new ServiceUnavailableException(NO_PROVIDERS);
390                     }
391                 } else {
392                     throw new ServiceUnavailableException(NO_PROVIDER_LIST);
393                 }
394             }
395
396             //once everything has passed, then we can add to the cache
397             i = bulk.iterator();
398             while (i.hasNext()) {
399                 NeutronPort test = i.next();
400                 portInterface.addPort(test);
401                 if (instances != null) {
402                     for (Object instance : instances) {
403                         INeutronPortAware service = (INeutronPortAware) instance;
404                         service.neutronPortCreated(test);
405                     }
406                 }
407             }
408         }
409         return Response.status(HttpURLConnection.HTTP_CREATED).entity(input).build();
410     }
411
412     /**
413      * Updates a Port */
414
415     @Path("{portUUID}")
416     @PUT
417     @Produces({ MediaType.APPLICATION_JSON })
418     @Consumes({ MediaType.APPLICATION_JSON })
419     //@TypeHint(OpenStackPorts.class)
420     @StatusCodes({
421         @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
422         @ResponseCode(code = HttpURLConnection.HTTP_BAD_REQUEST, condition = "Bad Request"),
423         @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
424         @ResponseCode(code = HttpURLConnection.HTTP_FORBIDDEN, condition = "Forbidden"),
425         @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
426         @ResponseCode(code = HttpURLConnection.HTTP_CONFLICT, condition = "Conflict"),
427         @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
428         @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
429     public Response updatePort(
430             @PathParam("portUUID") String portUUID,
431             NeutronPortRequest input
432             ) {
433         NeutronCRUDInterfaces interfaces = getNeutronInterfaces(false, true);
434         INeutronPortCRUD portInterface = interfaces.getPortInterface();
435         INeutronSubnetCRUD subnetInterface = interfaces.getSubnetInterface();
436
437         // port has to exist and only a single delta is supported
438         if (!portInterface.portExists(portUUID)) {
439             throw new ResourceNotFoundException(UUID_NO_EXIST);
440         }
441         NeutronPort target = portInterface.getPort(portUUID);
442         if (!input.isSingleton()) {
443             throw new BadRequestException("only singleton edit suported");
444         }
445         NeutronPort singleton = input.getSingleton();
446         NeutronPort original = portInterface.getPort(portUUID);
447
448         // deltas restricted by Neutron
449         if (singleton.getID() != null || singleton.getTenantID() != null ||
450                 singleton.getStatus() != null) {
451             throw new BadRequestException("attribute change blocked by Neutron");
452         }
453
454         Object[] instances = NeutronUtil.getInstances(INeutronPortAware.class, this);
455         if (instances != null) {
456             if (instances.length > 0) {
457                 for (Object instance : instances) {
458                     INeutronPortAware service = (INeutronPortAware) instance;
459                     int status = service.canUpdatePort(singleton, original);
460                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
461                         return Response.status(status).build();
462                     }
463                 }
464             } else {
465                 throw new ServiceUnavailableException(NO_PROVIDERS);
466             }
467         } else {
468             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
469         }
470
471         // Verify the new fixed ips are valid
472         List<Neutron_IPs> fixedIPs = singleton.getFixedIPs();
473         if (fixedIPs != null && fixedIPs.size() > 0) {
474             Iterator<Neutron_IPs> fixedIPIterator = fixedIPs.iterator();
475             while (fixedIPIterator.hasNext()) {
476                 Neutron_IPs ip = fixedIPIterator.next();
477                 if (ip.getSubnetUUID() == null) {
478                     throw new BadRequestException("subnet UUID must be specified");
479                 }
480                 if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
481                     throw new BadRequestException("subnet UUID doesn't exist.");
482                 }
483                 NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
484                 if (!target.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
485                     throw new BadRequestException(NET_UUID_MATCH);
486                 }
487                 if (ip.getIpAddress() != null) {
488                     if (!subnet.isValidIP(ip.getIpAddress())) {
489                         throw new BadRequestException("invalid IP address");
490                     }
491                     if (subnet.isIPInUse(ip.getIpAddress())) {
492                         throw new ResourceConflictException("IP address in use");
493                     }
494                 }
495             }
496         }
497
498         //        TODO: Support change of security groups
499         // update the port and return the modified object
500         portInterface.updatePort(portUUID, singleton);
501         NeutronPort updatedPort = portInterface.getPort(portUUID);
502         if (instances != null) {
503             for (Object instance : instances) {
504                 INeutronPortAware service = (INeutronPortAware) instance;
505                 service.neutronPortUpdated(updatedPort);
506             }
507         }
508         return Response.status(HttpURLConnection.HTTP_OK).entity(
509                 new NeutronPortRequest(updatedPort)).build();
510
511     }
512
513     /**
514      * Deletes a Port */
515
516     @Path("{portUUID}")
517     @DELETE
518     @StatusCodes({
519         @ResponseCode(code = HttpURLConnection.HTTP_NO_CONTENT, condition = "No Content"),
520         @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
521         @ResponseCode(code = HttpURLConnection.HTTP_FORBIDDEN, condition = "Forbidden"),
522         @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
523         @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
524         @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
525     public Response deletePort(
526             @PathParam("portUUID") String portUUID) {
527         INeutronPortCRUD portInterface = getNeutronInterfaces(false, false).getPortInterface();
528
529         // port has to exist and not be owned by anyone.  then it can be removed from the cache
530         if (!portInterface.portExists(portUUID)) {
531             throw new ResourceNotFoundException(UUID_NO_EXIST);
532         }
533         NeutronPort port = portInterface.getPort(portUUID);
534         if (port.getDeviceID() != null ||
535                 port.getDeviceOwner() != null) {
536             Response.status(HttpURLConnection.HTTP_FORBIDDEN).build();
537         }
538         NeutronPort singleton = portInterface.getPort(portUUID);
539         Object[] instances = NeutronUtil.getInstances(INeutronPortAware.class, this);
540         if (instances != null) {
541             if (instances.length > 0) {
542                 for (Object instance : instances) {
543                     INeutronPortAware service = (INeutronPortAware) instance;
544                     int status = service.canDeletePort(singleton);
545                     if (status < HTTP_OK_BOTTOM || status > HTTP_OK_TOP) {
546                         return Response.status(status).build();
547                     }
548                 }
549             } else {
550                 throw new ServiceUnavailableException(NO_PROVIDERS);
551             }
552         } else {
553             throw new ServiceUnavailableException(NO_PROVIDER_LIST);
554         }
555         portInterface.removePort(portUUID);
556         if (instances != null) {
557             for (Object instance : instances) {
558                 INeutronPortAware service = (INeutronPortAware) instance;
559                 service.neutronPortDeleted(singleton);
560             }
561         }
562         return Response.status(HttpURLConnection.HTTP_NO_CONTENT).build();
563     }
564 }