2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.controller.hosttracker.northbound;
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.List;
15 import javax.ws.rs.Consumes;
16 import javax.ws.rs.DELETE;
17 import javax.ws.rs.DefaultValue;
18 import javax.ws.rs.GET;
19 import javax.ws.rs.POST;
20 import javax.ws.rs.Path;
21 import javax.ws.rs.PathParam;
22 import javax.ws.rs.Produces;
23 import javax.ws.rs.QueryParam;
24 import javax.ws.rs.core.Context;
25 import javax.ws.rs.core.MediaType;
26 import javax.ws.rs.core.Response;
27 import javax.ws.rs.core.SecurityContext;
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.UnauthorizedException;
41 import org.opendaylight.controller.northbound.commons.exception.UnsupportedMediaTypeException;
42 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
43 import org.opendaylight.controller.sal.authorization.Privilege;
44 import org.opendaylight.controller.sal.core.Node;
45 import org.opendaylight.controller.sal.core.NodeConnector;
46 import org.opendaylight.controller.sal.utils.GlobalConstants;
47 import org.opendaylight.controller.sal.utils.ServiceHelper;
48 import org.opendaylight.controller.sal.utils.Status;
49 import org.opendaylight.controller.sal.utils.StatusCode;
50 import org.opendaylight.controller.switchmanager.ISwitchManager;
53 * Host Tracker Northbound REST APIs.<br>
54 * This class provides REST APIs to track host location in a network. Host
55 * Location is represented by Host node connector which is essentially a logical
56 * entity that represents a Switch/Port. A host is represented by it's
57 * IP-address and mac-address.
61 * Authentication scheme : <b>HTTP Basic</b><br>
62 * Authentication realm : <b>opendaylight</b><br>
63 * Transport : <b>HTTP and HTTPS</b><br>
65 * HTTPS Authentication is disabled by default. Administrator can enable it in
66 * tomcat-server.xml after adding a proper keystore / SSL certificate from a
67 * trusted authority.<br>
69 * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
74 public class HostTrackerNorthbound {
76 private String username;
79 public void setSecurityContext(SecurityContext context) {
80 username = context.getUserPrincipal().getName();
83 protected String getUserName() {
87 private IfIptoHost getIfIpToHostService(String containerName) {
88 IContainerManager containerManager = (IContainerManager) ServiceHelper
89 .getGlobalInstance(IContainerManager.class, this);
90 if (containerManager == null) {
91 throw new ServiceUnavailableException("Container "
92 + RestMessages.SERVICEUNAVAILABLE.toString());
95 boolean found = false;
96 List<String> containerNames = containerManager.getContainerNames();
97 for (String cName : containerNames) {
98 if (cName.trim().equalsIgnoreCase(containerName.trim())) {
103 if (found == false) {
104 throw new ResourceNotFoundException(containerName + " "
105 + RestMessages.NOCONTAINER.toString());
108 IfIptoHost hostTracker = (IfIptoHost) ServiceHelper.getInstance(
109 IfIptoHost.class, containerName, this);
111 if (hostTracker == null) {
112 throw new ServiceUnavailableException("Host Tracker "
113 + RestMessages.SERVICEUNAVAILABLE.toString());
120 * Returns a list of all Hosts : both configured via PUT API and dynamically
121 * learnt on the network.
123 * @param containerName
124 * Name of the Container. The Container name for the base
125 * controller is "default".
126 * @return List of Active Hosts.
128 @Path("/{containerName}")
130 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
131 @TypeHint(Hosts.class)
133 @ResponseCode(code = 200, condition = "Operation successful"),
134 @ResponseCode(code = 404, condition = "The containerName is not found"),
135 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
136 public Hosts getActiveHosts(@PathParam("containerName") String containerName) {
138 if (!NorthboundUtils.isAuthorized(
139 getUserName(), containerName, Privilege.READ, this)) {
140 throw new UnauthorizedException(
141 "User is not authorized to perform this operation on container "
144 IfIptoHost hostTracker = getIfIpToHostService(containerName);
145 if (hostTracker == null) {
146 throw new ServiceUnavailableException("Host Tracker "
147 + RestMessages.SERVICEUNAVAILABLE.toString());
150 return new Hosts(hostTracker.getAllHosts());
154 * Returns a list of Hosts that are statically configured and are connected
155 * to a NodeConnector that is down.
157 * @param containerName
158 * Name of the Container. The Container name for the base
159 * controller is "default".
160 * @return List of inactive Hosts.
162 @Path("/{containerName}/inactive")
164 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
165 @TypeHint(Hosts.class)
167 @ResponseCode(code = 200, condition = "Operation successful"),
168 @ResponseCode(code = 404, condition = "The containerName is not found"),
169 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
170 public Hosts getInactiveHosts(
171 @PathParam("containerName") String containerName) {
172 if (!NorthboundUtils.isAuthorized(
173 getUserName(), containerName, Privilege.READ, this)) {
174 throw new UnauthorizedException(
175 "User is not authorized to perform this operation on container "
178 IfIptoHost hostTracker = getIfIpToHostService(containerName);
179 if (hostTracker == null) {
180 throw new ServiceUnavailableException("Host Tracker "
181 + RestMessages.SERVICEUNAVAILABLE.toString());
184 return new Hosts(hostTracker.getInactiveStaticHosts());
188 * Returns a host that matches the IP Address value passed as parameter.
190 * @param containerName
191 * Name of the Container. The Container name for the base
192 * controller is "default".
193 * @param networkAddress
194 * IP Address being looked up
195 * @return host that matches the IP Address
197 @Path("/{containerName}/{networkAddress}")
199 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
200 @TypeHint(HostNodeConnector.class)
202 @ResponseCode(code = 200, condition = "Operation successful"),
203 @ResponseCode(code = 404, condition = "The containerName is not found"),
204 @ResponseCode(code = 415, condition = "Invalid IP Address passed in networkAddress parameter"),
205 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
206 public HostNodeConnector getHostDetails(
207 @PathParam("containerName") String containerName,
208 @PathParam("networkAddress") String networkAddress) {
209 if (!NorthboundUtils.isAuthorized(
210 getUserName(), containerName, Privilege.READ, this)) {
211 throw new UnauthorizedException(
212 "User is not authorized to perform this operation on container "
215 IfIptoHost hostTracker = getIfIpToHostService(containerName);
216 if (hostTracker == null) {
217 throw new ServiceUnavailableException("Host Tracker "
218 + RestMessages.SERVICEUNAVAILABLE.toString());
223 ip = InetAddress.getByName(networkAddress);
224 } catch (UnknownHostException e) {
225 throw new UnsupportedMediaTypeException(networkAddress + " "
226 + RestMessages.INVALIDADDRESS.toString());
228 for (HostNodeConnector host : hostTracker.getAllHosts()) {
229 if (host.getNetworkAddress().equals(ip)) {
233 throw new ResourceNotFoundException(RestMessages.NOHOST.toString());
237 * Add a Static Host configuration
239 * @param containerName
240 * Name of the Container. The Container name for the base
241 * controller is "default".
242 * @param networkAddress
244 * @param dataLayerAddress
245 * Host L2 data-layer address.
247 * Node Type as specifid by Node class
249 * Node Identifier as specifid by Node class
250 * @param nodeConnectorType
251 * Port Type as specified by NodeConnector class
252 * @param nodeConnectorId
253 * Port Identifier as specified by NodeConnector class
256 * @return Response as dictated by the HTTP Response Status code
259 @Path("/{containerName}/{networkAddress}")
261 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
263 @ResponseCode(code = 201, condition = "Static host created successfully"),
264 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
265 @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
266 @ResponseCode(code = 415, condition = "Invalid IP Address passed in networkAddress parameter"),
267 @ResponseCode(code = 500, condition = "Failed to create Static Host entry. Failure Reason included in HTTP Error response"),
268 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
269 public Response addHost(@PathParam("containerName") String containerName,
270 @PathParam("networkAddress") String networkAddress,
271 @QueryParam("dataLayerAddress") String dataLayerAddress,
272 @QueryParam("nodeType") String nodeType,
273 @QueryParam("nodeId") String nodeId,
274 @QueryParam("nodeConnectorType") String nodeConnectorType,
275 @QueryParam("nodeConnectorId") String nodeConnectorId,
276 @DefaultValue("0") @QueryParam("vlan") String vlan) {
278 if (!NorthboundUtils.isAuthorized(
279 getUserName(), containerName, Privilege.WRITE, this)) {
280 throw new UnauthorizedException(
281 "User is not authorized to perform this operation on container "
284 handleDefaultDisabled(containerName);
286 IfIptoHost hostTracker = getIfIpToHostService(containerName);
287 if (hostTracker == null) {
288 throw new ServiceUnavailableException("Host Tracker "
289 + RestMessages.SERVICEUNAVAILABLE.toString());
292 Node node = handleNodeAvailability(containerName, nodeType, nodeId);
294 throw new InternalServerErrorException(
295 RestMessages.NONODE.toString());
299 InetAddress.getByName(networkAddress);
300 } catch (UnknownHostException e) {
301 throw new UnsupportedMediaTypeException(networkAddress + " "
302 + RestMessages.INVALIDADDRESS.toString());
304 NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType,
305 nodeConnectorId, node);
307 throw new ResourceNotFoundException(nodeConnectorType + "|"
308 + nodeConnectorId + " : " + RestMessages.NONODE.toString());
310 Status status = hostTracker.addStaticHost(networkAddress,
311 dataLayerAddress, nc, vlan);
312 if (status.isSuccess()) {
313 NorthboundUtils.auditlog("Static Host", username, "added", networkAddress, containerName);
314 return Response.status(Response.Status.CREATED).build();
315 } else if (status.getCode().equals(StatusCode.BADREQUEST)) {
316 throw new UnsupportedMediaTypeException(status.getDescription());
318 throw new InternalServerErrorException(status.getDescription());
322 * Delete a Static Host configuration
324 * @param containerName
325 * Name of the Container. The Container name for the base
326 * controller is "default".
327 * @param networkAddress
329 * @return Response as dictated by the HTTP Response code.
332 @Path("/{containerName}/{networkAddress}")
334 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
336 @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
337 @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
338 @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
339 @ResponseCode(code = 415, condition = "Invalid IP Address passed in networkAddress parameter"),
340 @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
341 @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
342 public Response deleteFlow(
343 @PathParam(value = "containerName") String containerName,
344 @PathParam(value = "networkAddress") String networkAddress) {
346 if (!NorthboundUtils.isAuthorized(
347 getUserName(), containerName, Privilege.WRITE, this)) {
348 throw new UnauthorizedException(
349 "User is not authorized to perform this operation on container "
352 handleDefaultDisabled(containerName);
353 IfIptoHost hostTracker = getIfIpToHostService(containerName);
354 if (hostTracker == null) {
355 throw new ServiceUnavailableException("Host Tracker "
356 + RestMessages.SERVICEUNAVAILABLE.toString());
360 InetAddress.getByName(networkAddress);
361 } catch (UnknownHostException e) {
362 throw new UnsupportedMediaTypeException(networkAddress + " "
363 + RestMessages.INVALIDADDRESS.toString());
366 Status status = hostTracker.removeStaticHost(networkAddress);
367 if (status.isSuccess()) {
368 NorthboundUtils.auditlog("Static Host", username, "removed", networkAddress, containerName);
369 return Response.ok().build();
371 throw new InternalServerErrorException(status.getDescription());
375 private void handleDefaultDisabled(String containerName) {
376 IContainerManager containerManager = (IContainerManager) ServiceHelper
377 .getGlobalInstance(IContainerManager.class, this);
378 if (containerManager == null) {
379 throw new InternalServerErrorException(
380 RestMessages.INTERNALERROR.toString());
382 if (containerName.equals(GlobalConstants.DEFAULT.toString())
383 && containerManager.hasNonDefaultContainer()) {
384 throw new ResourceConflictException(
385 RestMessages.DEFAULTDISABLED.toString());
389 private Node handleNodeAvailability(String containerName, String nodeType,
392 Node node = Node.fromString(nodeType, nodeId);
394 throw new ResourceNotFoundException(nodeId + " : "
395 + RestMessages.NONODE.toString());
398 ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
399 ISwitchManager.class, containerName, this);
402 throw new ServiceUnavailableException("Switch Manager "
403 + RestMessages.SERVICEUNAVAILABLE.toString());
406 if (!sm.getNodes().contains(node)) {
407 throw new ResourceNotFoundException(node.toString() + " : "
408 + RestMessages.NONODE.toString());