197ebabf9133d43f7b81f5360f46b7d3138b1f9e
[controller.git] / opendaylight / northbound / statistics / src / main / java / org / opendaylight / controller / statistics / northbound / StatisticsNorthbound.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, 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.controller.statistics.northbound;
10
11 import java.util.ArrayList;
12 import java.util.List;
13
14 import javax.ws.rs.GET;
15 import javax.ws.rs.Path;
16 import javax.ws.rs.PathParam;
17 import javax.ws.rs.Produces;
18 import javax.ws.rs.core.Context;
19 import javax.ws.rs.core.MediaType;
20 import javax.ws.rs.core.SecurityContext;
21
22 import org.codehaus.enunciate.jaxrs.ResponseCode;
23 import org.codehaus.enunciate.jaxrs.StatusCodes;
24 import org.codehaus.enunciate.jaxrs.TypeHint;
25 import org.opendaylight.controller.containermanager.IContainerManager;
26
27 import org.opendaylight.controller.northbound.commons.RestMessages;
28 import org.opendaylight.controller.northbound.commons.exception.*;
29 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
30 import org.opendaylight.controller.sal.authorization.Privilege;
31 import org.opendaylight.controller.sal.core.Node;
32 import org.opendaylight.controller.sal.reader.FlowOnNode;
33 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
34 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
35 import org.opendaylight.controller.sal.utils.GlobalConstants;
36 import org.opendaylight.controller.sal.utils.ServiceHelper;
37 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
38 import org.opendaylight.controller.switchmanager.ISwitchManager;
39
40 /**
41  * Northbound APIs that returns various Statistics exposed by the Southbound
42  * plugins such as Openflow.
43  *
44  * <br>
45  * <br>
46  * Authentication scheme : <b>HTTP Basic</b><br>
47  * Authentication realm : <b>opendaylight</b><br>
48  * Transport : <b>HTTP and HTTPS</b><br>
49  * <br>
50  * HTTPS Authentication is disabled by default. Administrator can enable it in
51  * tomcat-server.xml after adding a proper keystore / SSL certificate from a
52  * trusted authority.<br>
53  * More info :
54  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
55  *
56  */
57 @Path("/")
58 public class StatisticsNorthbound {
59
60     private String username;
61
62     @Context
63     public void setSecurityContext(SecurityContext context) {
64         username = context.getUserPrincipal().getName();
65     }
66
67     protected String getUserName() {
68         return username;
69     }
70
71     private IStatisticsManager getStatisticsService(String containerName) {
72         IContainerManager containerManager = (IContainerManager) ServiceHelper
73                 .getGlobalInstance(IContainerManager.class, this);
74         if (containerManager == null) {
75             throw new ServiceUnavailableException("Container "
76                     + RestMessages.SERVICEUNAVAILABLE.toString());
77         }
78
79         boolean found = false;
80         List<String> containerNames = containerManager.getContainerNames();
81         for (String cName : containerNames) {
82             if (cName.trim().equalsIgnoreCase(containerName.trim())) {
83                 found = true;
84             }
85         }
86
87         if (found == false) {
88             throw new ResourceNotFoundException(containerName + " "
89                     + RestMessages.NOCONTAINER.toString());
90         }
91
92         IStatisticsManager statsManager = (IStatisticsManager) ServiceHelper
93                 .getInstance(IStatisticsManager.class, containerName, this);
94
95         if (statsManager == null) {
96             throw new ServiceUnavailableException("Statistics "
97                     + RestMessages.SERVICEUNAVAILABLE.toString());
98         }
99
100         return statsManager;
101     }
102
103     /**
104      * Returns a list of all Flow Statistics from all the Nodes.
105      *
106      * @param containerName
107      *            Name of the Container. The Container name for the base
108      *            controller is "default".
109      * @return List of FlowStatistics from all the Nodes
110      */
111
112     @Path("/{containerName}/flowstats")
113     @GET
114     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
115     @TypeHint(AllFlowStatistics.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 AllFlowStatistics getFlowStatistics(
121             @PathParam("containerName") String containerName) {
122         if (!NorthboundUtils.isAuthorized(
123                 getUserName(), containerName, Privilege.READ, this)) {
124             throw new UnauthorizedException(
125                     "User is not authorized to perform this operation on container "
126                             + containerName);
127         }
128         IStatisticsManager statisticsManager = getStatisticsService(containerName);
129         if (statisticsManager == null) {
130             throw new ServiceUnavailableException("Statistics "
131                     + RestMessages.SERVICEUNAVAILABLE.toString());
132         }
133
134         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
135                 .getInstance(ISwitchManager.class, containerName, this);
136         if (switchManager == null) {
137             throw new ServiceUnavailableException("Switch manager "
138                     + RestMessages.SERVICEUNAVAILABLE.toString());
139         }
140
141         List<FlowStatistics> statistics = new ArrayList<FlowStatistics>();
142         for (Node node : switchManager.getNodes()) {
143             List<FlowOnNode> flowStats = new ArrayList<FlowOnNode>();
144
145             List<FlowOnNode> flows = statisticsManager.getFlows(node);
146             for (FlowOnNode flowOnSwitch : flows) {
147                 flowStats.add(flowOnSwitch);
148             }
149             FlowStatistics stat = new FlowStatistics(node, flowStats);
150             statistics.add(stat);
151         }
152         return new AllFlowStatistics(statistics);
153     }
154
155     /**
156      * Returns a list of Flow Statistics for a given Node.
157      *
158      * @param containerName
159      *            Name of the Container. The Container name for the base
160      *            controller is "default".
161      * @param nodeType
162      *            Node Type as specifid by Node class
163      * @param nodeId
164      *            Node Identifier
165      * @return List of Flow Statistics for a given Node.
166      */
167     @Path("/{containerName}/flowstats/{nodeType}/{nodeId}")
168     @GET
169     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
170     @TypeHint(FlowStatistics.class)
171     @StatusCodes({
172         @ResponseCode(code = 200, condition = "Operation successful"),
173         @ResponseCode(code = 404, condition = "The containerName is not found"),
174         @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
175     public FlowStatistics getFlowStatistics(
176             @PathParam("containerName") String containerName,
177             @PathParam("nodeType") String nodeType,
178             @PathParam("nodeId") String nodeId) {
179         if (!NorthboundUtils.isAuthorized(
180                 getUserName(), containerName, Privilege.READ, this)) {
181             throw new UnauthorizedException(
182                     "User is not authorized to perform this operation on container "
183                             + containerName);
184         }
185         handleDefaultDisabled(containerName);
186
187         IStatisticsManager statisticsManager = getStatisticsService(containerName);
188         if (statisticsManager == null) {
189             throw new ServiceUnavailableException("Statistics "
190                     + RestMessages.SERVICEUNAVAILABLE.toString());
191         }
192
193         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
194                 .getInstance(ISwitchManager.class, containerName, this);
195         if (switchManager == null) {
196             throw new ServiceUnavailableException("Switch manager "
197                     + RestMessages.SERVICEUNAVAILABLE.toString());
198         }
199
200         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
201         return new FlowStatistics(node, statisticsManager.getFlows(node));
202     }
203
204     /**
205      * Returns a list of all the Port Statistics across all the NodeConnectors
206      * on all the Nodes.
207      *
208      * @param containerName
209      *            Name of the Container. The Container name for the base
210      *            controller is "default".
211      * @return List of all the Port Statistics across all the NodeConnectors on
212      *         all the Nodes.
213      */
214
215     @Path("/{containerName}/portstats")
216     @GET
217     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
218     @TypeHint(AllPortStatistics.class)
219     @StatusCodes({
220         @ResponseCode(code = 200, condition = "Operation successful"),
221         @ResponseCode(code = 404, condition = "The containerName is not found"),
222         @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
223     public AllPortStatistics getPortStatistics(
224             @PathParam("containerName") String containerName) {
225
226         if (!NorthboundUtils.isAuthorized(
227                 getUserName(), containerName, Privilege.READ, this)) {
228             throw new UnauthorizedException(
229                     "User is not authorized to perform this operation on container "
230                             + containerName);
231         }
232         IStatisticsManager statisticsManager = getStatisticsService(containerName);
233         if (statisticsManager == null) {
234             throw new ServiceUnavailableException("Statistics "
235                     + RestMessages.SERVICEUNAVAILABLE.toString());
236         }
237
238         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
239                 .getInstance(ISwitchManager.class, containerName, this);
240         if (switchManager == null) {
241             throw new ServiceUnavailableException("Switch manager "
242                     + RestMessages.SERVICEUNAVAILABLE.toString());
243         }
244
245         List<PortStatistics> statistics = new ArrayList<PortStatistics>();
246         for (Node node : switchManager.getNodes()) {
247             List<NodeConnectorStatistics> stat = statisticsManager
248                     .getNodeConnectorStatistics(node);
249             PortStatistics portStat = new PortStatistics(node, stat);
250             statistics.add(portStat);
251         }
252         return new AllPortStatistics(statistics);
253     }
254
255     /**
256      * Returns a list of all the Port Statistics across all the NodeConnectors
257      * in a given Node.
258      *
259      * @param containerName
260      *            Name of the Container. The Container name for the base
261      *            controller is "default".
262      * @param nodeType
263      *            Node Type as specifid by Node class
264      * @param Node
265      *            Identifier
266      * @return Returns a list of all the Port Statistics across all the
267      *         NodeConnectors in a given Node.
268      */
269     @Path("/{containerName}/portstats/{nodeType}/{nodeId}")
270     @GET
271     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
272     @TypeHint(PortStatistics.class)
273     @StatusCodes({
274         @ResponseCode(code = 200, condition = "Operation successful"),
275         @ResponseCode(code = 404, condition = "The containerName is not found"),
276         @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
277     public PortStatistics getPortStatistics(
278             @PathParam("containerName") String containerName,
279             @PathParam("nodeType") String nodeType,
280             @PathParam("nodeId") String nodeId) {
281
282         if (!NorthboundUtils.isAuthorized(
283                 getUserName(), containerName, Privilege.READ, this)) {
284             throw new UnauthorizedException(
285                     "User is not authorized to perform this operation on container "
286                             + containerName);
287         }
288         handleDefaultDisabled(containerName);
289
290         IStatisticsManager statisticsManager = getStatisticsService(containerName);
291         if (statisticsManager == null) {
292             throw new ServiceUnavailableException("Statistics "
293                     + RestMessages.SERVICEUNAVAILABLE.toString());
294         }
295
296         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
297                 .getInstance(ISwitchManager.class, containerName, this);
298         if (switchManager == null) {
299             throw new ServiceUnavailableException("Switch manager "
300                     + RestMessages.SERVICEUNAVAILABLE.toString());
301         }
302
303         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
304         return new PortStatistics(node,
305                 statisticsManager.getNodeConnectorStatistics(node));
306     }
307
308     /**
309      * Returns a list of all the Table Statistics on all Nodes.
310      *
311      * @param containerName
312      *            Name of the Container. The Container name for the base
313      *            controller is "default".
314      *
315      * @return Returns a list of all the Table Statistics in a given Node.
316      */
317     @Path("/{containerName}/tablestats")
318     @GET
319     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
320     @TypeHint(TableStatistics.class)
321     @StatusCodes({
322         @ResponseCode(code = 200, condition = "Operation successful"),
323         @ResponseCode(code = 404, condition = "The containerName is not found"),
324         @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
325     public AllTableStatistics getTableStatistics(
326             @PathParam("containerName") String containerName) {
327
328         if (!NorthboundUtils.isAuthorized(
329                 getUserName(), containerName, Privilege.READ, this)) {
330             throw new UnauthorizedException(
331                     "User is not authorized to perform this operation on container "
332                             + containerName);
333         }
334         handleDefaultDisabled(containerName);
335
336         IStatisticsManager statisticsManager = getStatisticsService(containerName);
337         if (statisticsManager == null) {
338             throw new ServiceUnavailableException("Statistics "
339                     + RestMessages.SERVICEUNAVAILABLE.toString());
340         }
341
342         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
343                 .getInstance(ISwitchManager.class, containerName, this);
344         if (switchManager == null) {
345             throw new ServiceUnavailableException("Switch manager "
346                     + RestMessages.SERVICEUNAVAILABLE.toString());
347         }
348
349         List<TableStatistics> statistics = new ArrayList<TableStatistics>();
350         for (Node node : switchManager.getNodes()) {
351             List<NodeTableStatistics> stat = statisticsManager
352                     .getNodeTableStatistics(node);
353             TableStatistics tableStat = new TableStatistics(node, stat);
354             statistics.add(tableStat);
355         }
356         return new AllTableStatistics(statistics);
357     }
358
359     /**
360      * Returns a list of all the Table Statistics on all Nodes.
361      *
362      * @param containerName
363      *            Name of the Container. The Container name for the base
364      *            controller is "default".
365      * @param nodeType
366      *            Node Type as specifid by Node class
367      * @param Node
368      *            Identifier
369      * @return Returns a list of all the Table Statistics in a given Node.
370      */
371     @Path("/{containerName}/tablestats/{nodeType}/{nodeId}")
372     @GET
373     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
374     @TypeHint(TableStatistics.class)
375     @StatusCodes({
376         @ResponseCode(code = 200, condition = "Operation successful"),
377         @ResponseCode(code = 404, condition = "The containerName is not found"),
378         @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
379     public TableStatistics getTableStatistics(
380             @PathParam("containerName") String containerName,
381             @PathParam("nodeType") String nodeType,
382             @PathParam("nodeId") String nodeId) {
383
384         if (!NorthboundUtils.isAuthorized(
385                 getUserName(), containerName, Privilege.READ, this)) {
386             throw new UnauthorizedException(
387                     "User is not authorized to perform this operation on container "
388                             + containerName);
389         }
390         handleDefaultDisabled(containerName);
391
392         IStatisticsManager statisticsManager = getStatisticsService(containerName);
393         if (statisticsManager == null) {
394             throw new ServiceUnavailableException("Statistics "
395                     + RestMessages.SERVICEUNAVAILABLE.toString());
396         }
397
398         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
399                 .getInstance(ISwitchManager.class, containerName, this);
400         if (switchManager == null) {
401             throw new ServiceUnavailableException("Switch manager "
402                     + RestMessages.SERVICEUNAVAILABLE.toString());
403         }
404
405         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
406         return new TableStatistics(node,
407                 statisticsManager.getNodeTableStatistics(node));
408     }
409
410     private void handleDefaultDisabled(String containerName) {
411         IContainerManager containerManager = (IContainerManager) ServiceHelper
412                 .getGlobalInstance(IContainerManager.class, this);
413         if (containerManager == null) {
414             throw new InternalServerErrorException(
415                     RestMessages.INTERNALERROR.toString());
416         }
417         if (containerName.equals(GlobalConstants.DEFAULT.toString())
418                 && containerManager.hasNonDefaultContainer()) {
419             throw new ResourceConflictException(
420                     RestMessages.DEFAULTDISABLED.toString());
421         }
422     }
423
424     private Node handleNodeAvailability(String containerName, String nodeType,
425             String nodeId) {
426
427         Node node = Node.fromString(nodeType, nodeId);
428         if (node == null) {
429             throw new ResourceNotFoundException(nodeId + " : "
430                     + RestMessages.NONODE.toString());
431         }
432
433         ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
434                 ISwitchManager.class, containerName, this);
435
436         if (sm == null) {
437             throw new ServiceUnavailableException("Switch Manager "
438                     + RestMessages.SERVICEUNAVAILABLE.toString());
439         }
440
441         if (!sm.getNodes().contains(node)) {
442             throw new ResourceNotFoundException(node.toString() + " : "
443                     + RestMessages.NONODE.toString());
444         }
445         return node;
446     }
447
448 }