Merge commit 'refs/changes/43/1843/1' of https://git.opendaylight.org/gerrit/affinity
[affinity.git] / analytics / northbound / src / main / java / org / opendaylight / affinity / analytics / northbound / AnalyticsNorthbound.java
1 /*
2  * Copyright (c) 2013 Plexxi, Inc. and others.  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.affinity.analytics.northbound;
10
11 import java.lang.Long;
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.GET;
18 import javax.ws.rs.Path;
19 import javax.ws.rs.PathParam;
20 import javax.ws.rs.Produces;
21 import javax.ws.rs.core.Context;
22 import javax.ws.rs.core.MediaType;
23 import javax.ws.rs.core.SecurityContext;
24
25 import org.codehaus.enunciate.jaxrs.ResponseCode;
26 import org.codehaus.enunciate.jaxrs.StatusCodes;
27 import org.codehaus.enunciate.jaxrs.TypeHint;
28
29 import org.opendaylight.affinity.affinity.AffinityLink;
30 import org.opendaylight.affinity.affinity.IAffinityManager;
31 import org.opendaylight.affinity.analytics.IAnalyticsManager;
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.*;
37 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
38 import org.opendaylight.controller.sal.authorization.Privilege;
39 import org.opendaylight.controller.sal.core.Host;
40 import org.opendaylight.controller.sal.utils.GlobalConstants;
41 import org.opendaylight.controller.sal.utils.ServiceHelper;
42 import org.opendaylight.controller.switchmanager.ISwitchManager;
43
44 /**
45  * Northbound APIs that returns various Analytics exposed by the Southbound
46  * plugins such as Openflow.
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 @Path("/")
62 public class AnalyticsNorthbound {
63
64     private String username;
65
66     @Context
67     public void setSecurityContext(SecurityContext context) {
68         username = context.getUserPrincipal().getName();
69     }
70
71     protected String getUserName() {
72         return username;
73     }
74
75     private IAnalyticsManager getAnalyticsService(String containerName) {
76         IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance(IContainerManager.class, this);
77         if (containerManager == null) {
78             throw new ServiceUnavailableException("Container " + RestMessages.SERVICEUNAVAILABLE.toString());
79         }
80
81         boolean found = false;
82         List<String> containerNames = containerManager.getContainerNames();
83         for (String cName : containerNames) {
84             if (cName.trim().equalsIgnoreCase(containerName.trim())) {
85                 found = true;
86             }
87         }
88
89         if (found == false) {
90             throw new ResourceNotFoundException(containerName + " " + RestMessages.NOCONTAINER.toString());
91         }
92
93         IAnalyticsManager analyticsManager = (IAnalyticsManager) ServiceHelper.getInstance(IAnalyticsManager.class, containerName, this);
94         if (analyticsManager == null) {
95             throw new ServiceUnavailableException("Analytics " + RestMessages.SERVICEUNAVAILABLE.toString());
96         }
97         return analyticsManager;
98     }
99
100     /**
101      * Returns Host Statistics for a (src, dst) pair
102      *
103      * @param containerName
104      *            Name of the Container. The Container name for the base
105      *            controller is "default".
106      * @param dataLayerAddr
107      *            DataLayerAddress for the host
108      * @param networkAddr
109      *            NetworkAddress for the host
110      * @return Host Statistics for a given Node.
111      */
112     @Path("/{containerName}/hoststats/{srcNetworkAddr}/{dstNetworkAddr}")
113     @GET
114     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
115     @TypeHint(HostStatistics.class)
116     @StatusCodes({
117         @ResponseCode(code = 200, condition = "Operation successful"),
118         @ResponseCode(code = 404, condition = "The containerName is not found"),
119         @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
120     public HostStatistics getHostStatistics(
121         @PathParam("containerName") String containerName,
122         @PathParam("srcNetworkAddr") String srcNetworkAddr,
123         @PathParam("dstNetworkAddr") String dstNetworkAddr) {
124         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
125             throw new UnauthorizedException("User is not authorized to perform this operation on container " + containerName);
126         }
127         handleDefaultDisabled(containerName);
128
129         IAnalyticsManager analyticsManager = getAnalyticsService(containerName);
130         if (analyticsManager == null) {
131             throw new ServiceUnavailableException("Analytics " + RestMessages.SERVICEUNAVAILABLE.toString());
132         }
133
134         Host srcHost = handleHostAvailability(containerName, srcNetworkAddr);
135         Host dstHost = handleHostAvailability(containerName, dstNetworkAddr);
136         long byteCount = analyticsManager.getByteCountBetweenHosts(srcHost, dstHost);
137         double bitRate = analyticsManager.getBitRateBetweenHosts(srcHost, dstHost);
138
139         return new HostStatistics(srcHost, dstHost, byteCount, bitRate);
140     }
141
142     /**
143      * Returns the affinity link statistics for a given link.
144      *
145      * @param containerName
146      *            Name of the Container. The Container name for the base
147      *            controller is "default".
148      * @param linkName
149      *            AffinityLink name.
150      * @return List of Affinity Link Statistics for a given link.
151      */
152     @Path("/{containerName}/affinitylinkstats/{linkName}")
153     @GET
154     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
155     @TypeHint(HostStatistics.class)
156     @StatusCodes({
157         @ResponseCode(code = 200, condition = "Operation successful"),
158         @ResponseCode(code = 404, condition = "The containerName is not found"),
159         @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
160     public AffinityLinkStatistics getAffinityLinkStatistics(
161         @PathParam("containerName") String containerName,
162         @PathParam("linkName") String affinityLinkName) {
163         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
164             throw new UnauthorizedException("User is not authorized to perform this operation on container " + containerName);
165         }
166         handleDefaultDisabled(containerName);
167
168         IAnalyticsManager analyticsManager = getAnalyticsService(containerName);
169         if (analyticsManager == null) {
170             throw new ServiceUnavailableException("Analytics " + RestMessages.SERVICEUNAVAILABLE.toString());
171         }
172
173         AffinityLink al = handleAffinityLinkAvailability(containerName, affinityLinkName);
174         long byteCount = analyticsManager.getByteCountOnAffinityLink(al);
175         double bitRate = analyticsManager.getBitRateOnAffinityLink(al);
176
177         return new AffinityLinkStatistics(al, byteCount, bitRate);
178     }
179
180     /**
181      * Returns TODO:
182      *
183      * @param containerName
184      *            Name of the Container. The Container name for the base
185      *            controller is "default".
186      * @param TODO:
187      * @return TODO:
188      */
189     @Path("/{containerName}/prefixstats/{ip}/{mask}/")
190     @GET
191     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
192     //    @TypeHint(Long.class)
193     @StatusCodes({
194         @ResponseCode(code = 200, condition = "Operation successful"),
195         @ResponseCode(code = 404, condition = "The containerName is not found"),
196         @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
197     public PrefixStatistics getPrefixMaskStatistics(
198         @PathParam("containerName") String containerName,
199         @PathParam("ip") String ip,
200         @PathParam("mask") String mask) {
201         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
202             throw new UnauthorizedException("User is not authorized to perform this operation on container " + containerName);
203         }
204         handleDefaultDisabled(containerName);
205
206         IAnalyticsManager analyticsManager = getAnalyticsService(containerName);
207         if (analyticsManager == null) {
208             throw new ServiceUnavailableException("Analytics " + RestMessages.SERVICEUNAVAILABLE.toString());
209         }
210
211         long byteCount = analyticsManager.getByteCountIntoPrefix(ip + "/" + mask);
212         return new PrefixStatistics(byteCount);
213     }
214
215     private void handleDefaultDisabled(String containerName) {
216         IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance(IContainerManager.class, this);
217         if (containerManager == null) {
218             throw new InternalServerErrorException(RestMessages.INTERNALERROR.toString());
219         }
220
221         if (containerName.equals(GlobalConstants.DEFAULT.toString()) && containerManager.hasNonDefaultContainer()) {
222             throw new ResourceConflictException(RestMessages.DEFAULTDISABLED.toString());
223         }
224     }
225
226     private AffinityLink handleAffinityLinkAvailability(String containerName, String linkName) {
227
228         IAffinityManager affinityManager = (IAffinityManager) ServiceHelper.getInstance(IAffinityManager.class, containerName, this);
229         if (affinityManager == null) {
230             throw new ServiceUnavailableException("Affinity manager " + RestMessages.SERVICEUNAVAILABLE.toString());
231         }
232
233         AffinityLink al = affinityManager.getAffinityLink(linkName);
234         if (al == null) {
235             throw new ResourceNotFoundException(linkName + " : AffinityLink does not exist");
236         }
237
238         return al;
239     }
240
241
242     private Host handleHostAvailability(String containerName, String networkAddr) {
243
244         IfIptoHost hostTracker = (IfIptoHost) ServiceHelper.getInstance(IfIptoHost.class, containerName, this);
245         if (hostTracker == null) {
246             throw new ServiceUnavailableException("Host tracker " + RestMessages.SERVICEUNAVAILABLE.toString());
247         }
248
249         Set<HostNodeConnector> allHosts = hostTracker.getAllHosts();
250         if (allHosts == null) {
251             throw new ResourceNotFoundException(networkAddr + " : " + RestMessages.NOHOST.toString());
252         }
253
254         Host host = null;
255         try {
256             InetAddress networkAddress = InetAddress.getByName(networkAddr);
257             for (Host h : allHosts) {
258                 if (h.getNetworkAddress().equals(networkAddress)) {
259                     host = h;
260                     break;
261                 }
262             }
263         } catch (UnknownHostException e) {
264         }
265
266         if (host == null) {
267             throw new ResourceNotFoundException(networkAddr + " : " + RestMessages.NOHOST.toString());
268         }
269
270         return host;
271     }
272 }