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