Controller to listen to expired flow removal message
[controller.git] / opendaylight / northbound / hosttracker / src / main / java / org / opendaylight / controller / hosttracker / northbound / HostTrackerNorthbound.java
1
2 /*
3  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9
10 package org.opendaylight.controller.hosttracker.northbound;
11
12 import java.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.List;
15 import java.util.Set;
16
17 import javax.servlet.http.HttpServletRequest;
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.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.MediaType;
28 import javax.ws.rs.core.Response;
29
30 import org.codehaus.enunciate.jaxrs.ResponseCode;
31 import org.codehaus.enunciate.jaxrs.StatusCodes;
32 import org.codehaus.enunciate.jaxrs.TypeHint;
33 import org.opendaylight.controller.containermanager.IContainerManager;
34 import org.opendaylight.controller.hosttracker.IfIptoHost;
35 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
36 import org.opendaylight.controller.northbound.commons.RestMessages;
37 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
38 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
39 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
40 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
41 import org.opendaylight.controller.northbound.commons.exception.UnsupportedMediaTypeException;
42 import org.opendaylight.controller.sal.core.Node;
43 import org.opendaylight.controller.sal.core.NodeConnector;
44 import org.opendaylight.controller.sal.utils.GlobalConstants;
45 import org.opendaylight.controller.sal.utils.ServiceHelper;
46 import org.opendaylight.controller.sal.utils.Status;
47 import org.opendaylight.controller.sal.utils.StatusCode;
48 import org.opendaylight.controller.switchmanager.ISwitchManager;
49
50 /**
51  * Host Tracker Northbound REST APIs.<br>
52  * This class provides REST APIs to track host location in a network. Host Location is represented by Host node connector 
53  * which is essentially a logical entity that represents a Switch/Port. A host is represented by it's IP-address 
54  * and mac-address.
55  *
56  * <br><br>
57  * Authentication scheme : <b>HTTP Basic</b><br>
58  * Authentication realm : <b>opendaylight</b><br>
59  * Transport : <b>HTTP and HTTPS</b><br>
60  * <br>
61  * HTTPS Authentication is disabled by default. Administrator can enable it in tomcat-server.xml after adding
62  * a proper keystore / SSL certificate from a trusted authority.<br>
63  * More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
64  *
65  */
66
67 @Path("/")
68 public class HostTrackerNorthbound {
69
70     private IfIptoHost getIfIpToHostService(String containerName) {
71         IContainerManager containerManager = (IContainerManager) ServiceHelper
72                 .getGlobalInstance(IContainerManager.class, this);
73         if (containerManager == null) {
74             throw new ServiceUnavailableException("Container "
75                     + RestMessages.SERVICEUNAVAILABLE.toString());
76         }
77
78         boolean found = false;
79         List<String> containerNames = containerManager.getContainerNames();
80         for (String cName : containerNames) {
81             if (cName.trim().equalsIgnoreCase(containerName.trim())) {
82                 found = true;
83             }
84         }
85
86         if (found == false) {
87             throw new ResourceNotFoundException(containerName + " "
88                     + RestMessages.NOCONTAINER.toString());
89         }
90
91         IfIptoHost hostTracker = (IfIptoHost) ServiceHelper.getInstance(
92                 IfIptoHost.class, containerName, this);
93
94         if (hostTracker == null) {
95             throw new ServiceUnavailableException("Host Tracker "
96                     + RestMessages.SERVICEUNAVAILABLE.toString());
97         }
98
99         return hostTracker;
100     }
101
102     /**
103      * Returns a list of all Hosts : both configured via PUT API and dynamically learnt on the network.
104      *
105      * @param containerName Name of the Container. The Container name for the base controller is "default".
106      * @return List of Active Hosts.
107      */
108     @Path("/{containerName}")
109     @GET
110     @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
111     @TypeHint(Hosts.class)
112     @StatusCodes( {
113             @ResponseCode(code = 200, condition = "Operation successful"),
114             @ResponseCode(code = 404, condition = "The containerName is not found"),
115             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
116     public Hosts getActiveHosts(
117             @PathParam("containerName") String containerName) {
118         IfIptoHost hostTracker = getIfIpToHostService(containerName);
119         if (hostTracker == null) {
120             throw new ServiceUnavailableException("Host Tracker "
121                     + RestMessages.SERVICEUNAVAILABLE.toString());
122         }
123
124         return new Hosts(hostTracker.getAllHosts());
125     }
126
127     /**
128      * Returns a list of Hosts that are statically configured and are connected to a NodeConnector that is down.
129      *
130      * @param containerName Name of the Container. The Container name for the base controller is "default".
131      * @return List of inactive Hosts.
132      */
133     @Path("/{containerName}/inactive")
134     @GET
135     @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
136     @TypeHint(Hosts.class)
137     @StatusCodes( {
138             @ResponseCode(code = 200, condition = "Operation successful"),
139             @ResponseCode(code = 404, condition = "The containerName is not found"),
140             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
141     public Hosts getInactiveHosts(
142             @PathParam("containerName") String containerName) {
143         IfIptoHost hostTracker = getIfIpToHostService(containerName);
144         if (hostTracker == null) {
145             throw new ServiceUnavailableException("Host Tracker "
146                     + RestMessages.SERVICEUNAVAILABLE.toString());
147         }
148
149         return new Hosts(hostTracker.getInactiveStaticHosts());
150     }
151
152     /**
153      * Returns a host that matches the IP Address value passed as parameter.
154      *
155      * @param containerName Name of the Container. The Container name for the base controller is "default".
156      * @param networkAddress IP Address being looked up
157      * @return host that matches the IP Address
158      */
159     @Path("/{containerName}/{networkAddress}")
160     @GET
161     @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
162     @TypeHint(HostNodeConnector.class)
163     @StatusCodes( {
164             @ResponseCode(code = 200, condition = "Operation successful"),
165             @ResponseCode(code = 404, condition = "The containerName is not found"),
166             @ResponseCode(code = 415, condition = "Invalid IP Address passed in networkAddress parameter"),
167             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
168     public HostNodeConnector getHostDetails(
169             @PathParam("containerName") String containerName,
170             @PathParam("networkAddress") String networkAddress) {
171         IfIptoHost hostTracker = getIfIpToHostService(containerName);
172         if (hostTracker == null) {
173             throw new ServiceUnavailableException("Host Tracker "
174                     + RestMessages.SERVICEUNAVAILABLE.toString());
175         }
176
177         InetAddress ip;
178         try {
179             ip = InetAddress.getByName(networkAddress);
180         } catch (UnknownHostException e) {
181             throw new UnsupportedMediaTypeException(networkAddress + " "
182                     + RestMessages.INVALIDADDRESS.toString());
183         }
184         for (HostNodeConnector host : hostTracker.getAllHosts()) {
185             if (host.getNetworkAddress().equals(ip)) {
186                 return host;
187             }
188         }
189         throw new ResourceNotFoundException(RestMessages.NOHOST.toString());
190     }
191
192     /**
193      * Add a Static Host configuration
194      *
195      * @param containerName Name of the Container. The Container name for the base controller is "default".
196      * @param networkAddress Host IP Address
197      * @param dataLayerAddress Host L2 data-layer address.
198      * @param nodeType Node Type as specifid by Node class
199      * @param nodeId Node Identifier as specifid by Node class
200      * @param nodeConnectorType Port Type as specified by NodeConnector class
201      * @param nodeConnectorId Port Identifier as specified by NodeConnector class
202      * @param vlan Vlan number
203      * @return Response as dictated by the HTTP Response Status code
204      */
205
206     @Path("/{containerName}/{networkAddress}")
207     @POST
208     @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
209     @StatusCodes( {
210             @ResponseCode(code = 201, condition = "Flow Config processed successfully"),
211             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
212             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
213             @ResponseCode(code = 415, condition = "Invalid IP Address passed in networkAddress parameter"),
214             @ResponseCode(code = 500, condition = "Failed to create Static Host entry. Failure Reason included in HTTP Error response"),
215             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
216     public Response addHost(@PathParam("containerName") String containerName,
217             @PathParam("networkAddress") String networkAddress,
218             @QueryParam("dataLayerAddress") String dataLayerAddress,
219             @QueryParam("nodeType") String nodeType,
220             @QueryParam("nodeId") String nodeId,
221             @QueryParam("nodeConnectorType") String nodeConnectorType,
222             @QueryParam("nodeConnectorId") String nodeConnectorId,
223             @DefaultValue("0") @QueryParam("vlan") String vlan) {
224
225         handleDefaultDisabled(containerName);
226
227         IfIptoHost hostTracker = getIfIpToHostService(containerName);
228         if (hostTracker == null) {
229             throw new ServiceUnavailableException("Host Tracker "
230                     + RestMessages.SERVICEUNAVAILABLE.toString());
231         }
232
233         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
234         if (node == null) {
235             throw new InternalServerErrorException(RestMessages.NONODE.
236                                                    toString());
237         }
238
239         try {
240             InetAddress.getByName(networkAddress);
241         } catch (UnknownHostException e) {
242             throw new UnsupportedMediaTypeException(networkAddress + " "
243                     + RestMessages.INVALIDADDRESS.toString());
244         }
245         NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType, nodeConnectorId,
246                                                           node);
247         if (nc == null) {
248             throw new ResourceNotFoundException(nodeConnectorType+"|"+nodeConnectorId + " : "
249                     + RestMessages.NONODE.toString());
250         }
251         Status status = hostTracker.addStaticHost(networkAddress,
252                                                dataLayerAddress,
253                                                nc, vlan);
254         if (status.isSuccess()) {
255             return Response.status(Response.Status.CREATED).build();
256         } else if (status.getCode().equals(StatusCode.BADREQUEST)) {
257             throw new UnsupportedMediaTypeException(status.getDescription());
258         }
259         throw new InternalServerErrorException(status.getDescription());
260     }
261
262     /**
263      * Delete a Static Host configuration
264      *
265      * @param containerName Name of the Container. The Container name for the base controller is "default".
266      * @param networkAddress   IP Address
267      * @return Response as dictated by the HTTP Response code.
268      */
269
270     @Path("/{containerName}/{networkAddress}")
271     @DELETE
272     @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
273     @StatusCodes( {
274             @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
275             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
276             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
277             @ResponseCode(code = 415, condition = "Invalid IP Address passed in networkAddress parameter"),
278             @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
279             @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
280     public Response deleteFlow(
281             @PathParam(value = "containerName") String containerName,
282             @PathParam(value = "networkAddress") String networkAddress) {
283
284         handleDefaultDisabled(containerName);
285         IfIptoHost hostTracker = getIfIpToHostService(containerName);
286         if (hostTracker == null) {
287             throw new ServiceUnavailableException("Host Tracker "
288                     + RestMessages.SERVICEUNAVAILABLE.toString());
289         }
290
291         try {
292             InetAddress.getByName(networkAddress);
293         } catch (UnknownHostException e) {
294             throw new UnsupportedMediaTypeException(networkAddress + " "
295                     + RestMessages.INVALIDADDRESS.toString());
296         }
297
298         Status status = hostTracker.removeStaticHost(networkAddress);
299         if (status.isSuccess()) {
300             return Response.ok().build();
301         }
302         throw new InternalServerErrorException(status.getDescription());
303
304     }
305
306     private void handleDefaultDisabled(String containerName) {
307         IContainerManager containerManager = (IContainerManager) ServiceHelper
308                 .getGlobalInstance(IContainerManager.class, this);
309         if (containerManager == null) {
310             throw new InternalServerErrorException(RestMessages.INTERNALERROR
311                     .toString());
312         }
313         if (containerName.equals(GlobalConstants.DEFAULT.toString())
314                 && containerManager.hasNonDefaultContainer()) {
315             throw new ResourceConflictException(RestMessages.DEFAULTDISABLED
316                     .toString());
317         }
318     }
319
320     private Node handleNodeAvailability(String containerName, String nodeType,
321                                         String nodeId) {
322
323         Node node = Node.fromString(nodeType, nodeId);
324         if (node == null) {
325             throw new ResourceNotFoundException(nodeId + " : "
326                     + RestMessages.NONODE.toString());
327         }
328
329         ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
330                 ISwitchManager.class, containerName, this);
331
332         if (sm == null) {
333             throw new ServiceUnavailableException("Switch Manager "
334                     + RestMessages.SERVICEUNAVAILABLE.toString());
335         }
336
337         if (!sm.getNodes().contains(node)) {
338             throw new ResourceNotFoundException(node.toString() + " : "
339                     + RestMessages.NONODE.toString());
340         }
341         return node;
342     }
343 }