Authorization fixes for Northbound bundles
[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.utils.GlobalConstants;
35 import org.opendaylight.controller.sal.utils.ServiceHelper;
36 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
37 import org.opendaylight.controller.switchmanager.ISwitchManager;
38
39 /**
40  * Northbound APIs that returns various Statistics exposed by the Southbound
41  * plugins such as Openflow.
42  * 
43  * <br>
44  * <br>
45  * Authentication scheme : <b>HTTP Basic</b><br>
46  * Authentication realm : <b>opendaylight</b><br>
47  * Transport : <b>HTTP and HTTPS</b><br>
48  * <br>
49  * HTTPS Authentication is disabled by default. Administrator can enable it in
50  * tomcat-server.xml after adding a proper keystore / SSL certificate from a
51  * trusted authority.<br>
52  * More info :
53  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
54  * 
55  */
56 @Path("/")
57 public class StatisticsNorthbound {
58
59     private String username;
60
61     @Context
62     public void setSecurityContext(SecurityContext context) {
63         username = context.getUserPrincipal().getName();
64     }
65
66     protected String getUserName() {
67         return username;
68     }
69
70     private IStatisticsManager getStatisticsService(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         IStatisticsManager statsManager = (IStatisticsManager) ServiceHelper
92                 .getInstance(IStatisticsManager.class, containerName, this);
93
94         if (statsManager == null) {
95             throw new ServiceUnavailableException("Statistics "
96                     + RestMessages.SERVICEUNAVAILABLE.toString());
97         }
98
99         return statsManager;
100     }
101
102     /**
103      * Returns a list of all Flow Statistics from all the Nodes.
104      * 
105      * @param containerName
106      *            Name of the Container. The Container name for the base
107      *            controller is "default".
108      * @return List of FlowStatistics from all the Nodes
109      */
110
111     @Path("/{containerName}/flowstats")
112     @GET
113     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
114     @TypeHint(AllFlowStatistics.class)
115     @StatusCodes({
116             @ResponseCode(code = 200, condition = "Operation successful"),
117             @ResponseCode(code = 404, condition = "The containerName is not found"),
118             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
119     public AllFlowStatistics getFlowStatistics(
120             @PathParam("containerName") String containerName) {
121         if (!NorthboundUtils.isAuthorized(
122                 getUserName(), containerName, Privilege.READ, this)) {
123             throw new UnauthorizedException(
124                     "User is not authorized to perform this operation on container "
125                             + containerName);
126         }
127         IStatisticsManager statisticsManager = getStatisticsService(containerName);
128         if (statisticsManager == null) {
129             throw new ServiceUnavailableException("Statistics "
130                     + RestMessages.SERVICEUNAVAILABLE.toString());
131         }
132
133         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
134                 .getInstance(ISwitchManager.class, containerName, this);
135         if (switchManager == null) {
136             throw new ServiceUnavailableException("Switch manager "
137                     + RestMessages.SERVICEUNAVAILABLE.toString());
138         }
139
140         List<FlowStatistics> statistics = new ArrayList<FlowStatistics>();
141         for (Node node : switchManager.getNodes()) {
142             List<FlowOnNode> flowStats = new ArrayList<FlowOnNode>();
143
144             List<FlowOnNode> flows = statisticsManager.getFlows(node);
145             for (FlowOnNode flowOnSwitch : flows) {
146                 flowStats.add(flowOnSwitch);
147             }
148             FlowStatistics stat = new FlowStatistics(node, flowStats);
149             statistics.add(stat);
150         }
151         return new AllFlowStatistics(statistics);
152     }
153
154     /**
155      * Returns a list of Flow Statistics for a given Node.
156      * 
157      * @param containerName
158      *            Name of the Container. The Container name for the base
159      *            controller is "default".
160      * @param nodeType
161      *            Node Type as specifid by Node class
162      * @param nodeId
163      *            Node Identifier
164      * @return List of Flow Statistics for a given Node.
165      */
166     @Path("/{containerName}/flowstats/{nodeType}/{nodeId}")
167     @GET
168     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
169     @TypeHint(FlowStatistics.class)
170     @StatusCodes({
171             @ResponseCode(code = 200, condition = "Operation successful"),
172             @ResponseCode(code = 404, condition = "The containerName is not found"),
173             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
174     public FlowStatistics getFlowStatistics(
175             @PathParam("containerName") String containerName,
176             @PathParam("nodeType") String nodeType,
177             @PathParam("nodeId") String nodeId) {
178         if (!NorthboundUtils.isAuthorized(
179                 getUserName(), containerName, Privilege.READ, this)) {
180             throw new UnauthorizedException(
181                     "User is not authorized to perform this operation on container "
182                             + containerName);
183         }
184         handleDefaultDisabled(containerName);
185
186         IStatisticsManager statisticsManager = getStatisticsService(containerName);
187         if (statisticsManager == null) {
188             throw new ServiceUnavailableException("Statistics "
189                     + RestMessages.SERVICEUNAVAILABLE.toString());
190         }
191
192         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
193                 .getInstance(ISwitchManager.class, containerName, this);
194         if (switchManager == null) {
195             throw new ServiceUnavailableException("Switch manager "
196                     + RestMessages.SERVICEUNAVAILABLE.toString());
197         }
198
199         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
200         return new FlowStatistics(node, statisticsManager.getFlows(node));
201     }
202
203     /**
204      * Returns a list of all the Port Statistics across all the NodeConnectors
205      * on all the Nodes.
206      * 
207      * @param containerName
208      *            Name of the Container. The Container name for the base
209      *            controller is "default".
210      * @return List of all the Port Statistics across all the NodeConnectors on
211      *         all the Nodes.
212      */
213
214     @Path("/{containerName}/portstats")
215     @GET
216     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
217     @TypeHint(AllPortStatistics.class)
218     @StatusCodes({
219             @ResponseCode(code = 200, condition = "Operation successful"),
220             @ResponseCode(code = 404, condition = "The containerName is not found"),
221             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
222     public AllPortStatistics getPortStatistics(
223             @PathParam("containerName") String containerName) {
224
225         if (!NorthboundUtils.isAuthorized(
226                 getUserName(), containerName, Privilege.READ, this)) {
227             throw new UnauthorizedException(
228                     "User is not authorized to perform this operation on container "
229                             + containerName);
230         }
231         IStatisticsManager statisticsManager = getStatisticsService(containerName);
232         if (statisticsManager == null) {
233             throw new ServiceUnavailableException("Statistics "
234                     + RestMessages.SERVICEUNAVAILABLE.toString());
235         }
236
237         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
238                 .getInstance(ISwitchManager.class, containerName, this);
239         if (switchManager == null) {
240             throw new ServiceUnavailableException("Switch manager "
241                     + RestMessages.SERVICEUNAVAILABLE.toString());
242         }
243
244         List<PortStatistics> statistics = new ArrayList<PortStatistics>();
245         for (Node node : switchManager.getNodes()) {
246             List<NodeConnectorStatistics> stat = statisticsManager
247                     .getNodeConnectorStatistics(node);
248             PortStatistics portStat = new PortStatistics(node, stat);
249             statistics.add(portStat);
250         }
251         return new AllPortStatistics(statistics);
252     }
253
254     /**
255      * Returns a list of all the Port Statistics across all the NodeConnectors
256      * in a given Node.
257      * 
258      * @param containerName
259      *            Name of the Container. The Container name for the base
260      *            controller is "default".
261      * @param nodeType
262      *            Node Type as specifid by Node class
263      * @param Node
264      *            Identifier
265      * @return Returns a list of all the Port Statistics across all the
266      *         NodeConnectors in a given Node.
267      */
268     @Path("/{containerName}/portstats/{nodeType}/{nodeId}")
269     @GET
270     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
271     @TypeHint(PortStatistics.class)
272     @StatusCodes({
273             @ResponseCode(code = 200, condition = "Operation successful"),
274             @ResponseCode(code = 404, condition = "The containerName is not found"),
275             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
276     public PortStatistics getPortStatistics(
277             @PathParam("containerName") String containerName,
278             @PathParam("nodeType") String nodeType,
279             @PathParam("nodeId") String nodeId) {
280
281         if (!NorthboundUtils.isAuthorized(
282                 getUserName(), containerName, Privilege.READ, this)) {
283             throw new UnauthorizedException(
284                     "User is not authorized to perform this operation on container "
285                             + containerName);
286         }
287         handleDefaultDisabled(containerName);
288
289         IStatisticsManager statisticsManager = getStatisticsService(containerName);
290         if (statisticsManager == null) {
291             throw new ServiceUnavailableException("Statistics "
292                     + RestMessages.SERVICEUNAVAILABLE.toString());
293         }
294
295         ISwitchManager switchManager = (ISwitchManager) ServiceHelper
296                 .getInstance(ISwitchManager.class, containerName, this);
297         if (switchManager == null) {
298             throw new ServiceUnavailableException("Switch manager "
299                     + RestMessages.SERVICEUNAVAILABLE.toString());
300         }
301
302         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
303         return new PortStatistics(node,
304                 statisticsManager.getNodeConnectorStatistics(node));
305     }
306
307     private void handleDefaultDisabled(String containerName) {
308         IContainerManager containerManager = (IContainerManager) ServiceHelper
309                 .getGlobalInstance(IContainerManager.class, this);
310         if (containerManager == null) {
311             throw new InternalServerErrorException(
312                     RestMessages.INTERNALERROR.toString());
313         }
314         if (containerName.equals(GlobalConstants.DEFAULT.toString())
315                 && containerManager.hasNonDefaultContainer()) {
316             throw new ResourceConflictException(
317                     RestMessages.DEFAULTDISABLED.toString());
318         }
319     }
320
321     private Node handleNodeAvailability(String containerName, String nodeType,
322             String nodeId) {
323
324         Node node = Node.fromString(nodeType, nodeId);
325         if (node == null) {
326             throw new ResourceNotFoundException(nodeId + " : "
327                     + RestMessages.NONODE.toString());
328         }
329
330         ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
331                 ISwitchManager.class, containerName, this);
332
333         if (sm == null) {
334             throw new ServiceUnavailableException("Switch Manager "
335                     + RestMessages.SERVICEUNAVAILABLE.toString());
336         }
337
338         if (!sm.getNodes().contains(node)) {
339             throw new ResourceNotFoundException(node.toString() + " : "
340                     + RestMessages.NONODE.toString());
341         }
342         return node;
343     }
344
345 }