BUG 2302 : odl-clustering-test-app should not be part of the odl-restconf-all feature set
[controller.git] / opendaylight / northbound / controllermanager / src / main / java / org / opendaylight / controller / controllermanager / northbound / ControllerManagerNorthbound.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.controllermanager.northbound;
10
11 import java.util.HashSet;
12 import java.util.Map;
13 import java.util.Set;
14
15 import javax.ws.rs.Consumes;
16 import javax.ws.rs.DELETE;
17 import javax.ws.rs.GET;
18 import javax.ws.rs.PUT;
19 import javax.ws.rs.Path;
20 import javax.ws.rs.PathParam;
21 import javax.ws.rs.Produces;
22 import javax.ws.rs.QueryParam;
23 import javax.ws.rs.core.Context;
24 import javax.ws.rs.core.MediaType;
25 import javax.ws.rs.core.Response;
26 import javax.ws.rs.core.SecurityContext;
27 import javax.ws.rs.core.UriInfo;
28 import javax.ws.rs.ext.ContextResolver;
29
30 import org.codehaus.enunciate.jaxrs.ResponseCode;
31 import org.codehaus.enunciate.jaxrs.StatusCodes;
32 import org.codehaus.enunciate.jaxrs.TypeHint;
33 import org.opendaylight.controller.configuration.IConfigurationService;
34 import org.opendaylight.controller.containermanager.IContainerManager;
35 import org.opendaylight.controller.northbound.commons.RestMessages;
36 import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
37 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
38 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
39 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
40 import org.opendaylight.controller.northbound.commons.query.QueryContext;
41 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
42 import org.opendaylight.controller.sal.authorization.Privilege;
43 import org.opendaylight.controller.sal.core.Property;
44 import org.opendaylight.controller.sal.utils.GlobalConstants;
45 import org.opendaylight.controller.sal.utils.ServiceHelper;
46 import org.opendaylight.controller.sal.utils.Status;
47 import org.opendaylight.controller.switchmanager.ISwitchManager;
48
49 /**
50  * The class provides Northbound REST APIs to manager the controller. Currently
51  * it supports getting controller property(ies), setting a property, and
52  * removing a property
53  *
54  */
55
56 @Path("/")
57 public class ControllerManagerNorthbound {
58
59     private String username;
60     private QueryContext queryContext;
61
62     @Context
63     public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
64       if (queryCtxResolver != null) {
65         queryContext = queryCtxResolver.getContext(QueryContext.class);
66       }
67     }
68
69     @Context
70     public void setSecurityContext(SecurityContext context) {
71         if (context != null && context.getUserPrincipal() != null) {
72             username = context.getUserPrincipal().getName();
73         }
74     }
75
76     protected String getUserName() {
77         return username;
78     }
79
80     private ISwitchManager getISwitchManagerService(String containerName) {
81         ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
82                 this);
83
84         if (switchManager == null) {
85             throw new ServiceUnavailableException("Switch Manager " + RestMessages.SERVICEUNAVAILABLE.toString());
86         }
87
88         return switchManager;
89     }
90
91     /**
92      * Retrieve a property or all properties for the controller in the network
93      *
94      * @param containerName
95      *            Name of the Container (Eg. 'default')
96      * @param propertyName
97      *            Name of the Property specified by
98      *            {@link org.opendaylight.controller.sal.core.Property} and its
99      *            extended classes
100      *
101      *            Example:
102      *
103      *            Request URL:
104      *            http://localhost:8080/controller/nb/v2/controllermanager/default/properties/?propertyName=macAddress
105      *
106      *            Response Body in XML:
107      *            <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
108      *            <controllerProperties>
109      *                  <properties>
110      *                           <macAddress>
111      *                                   <value>3e:04:ef:11:13:80</value>
112      *                          </macAddress>
113      *                   </properties>
114      *            </controllerProperties>
115      *
116      *            Response Body in JSON:
117      *            { "controllerProperties":
118      *                  {"properties":
119      *                          { "macAddress":
120      *                                  { "value": "3e:04:ef:11:13:80" }
121      *                           }
122      *                   }
123      *            }
124      *
125      */
126     @Path("/{containerName}/properties/")
127     @GET
128     @TypeHint(Property.class)
129     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
130     @StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
131             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
132             @ResponseCode(code = 404, condition = "The containerName or property is not found"),
133             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
134     public ControllerProperties getControllerProperties(@PathParam("containerName") String containerName,
135             @QueryParam("propertyName") String propertyName,
136             @QueryParam("_q") String queryString) {
137
138         if (!isValidContainer(containerName)) {
139             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
140         }
141
142         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
143             throw new UnauthorizedException("User is not authorized to perform this operation on container "
144                     + containerName);
145         }
146
147         ISwitchManager switchManager = getISwitchManagerService(containerName);
148
149         if (propertyName == null) {
150             Map<String, Property> propertyMap = switchManager.getControllerProperties();
151             Set<Property> properties = new HashSet<Property>(propertyMap.values());
152             return new ControllerProperties(properties);
153         }
154
155         Set<Property> properties = new HashSet<Property>();
156         Property property = switchManager.getControllerProperty(propertyName);
157         if (property == null) {
158             throw new ResourceNotFoundException("Unable to find property with name: " + propertyName);
159         }
160         properties.add(property);
161         ControllerProperties result = new ControllerProperties(properties);
162         if (queryString != null) {
163             queryContext.createQuery(queryString, ControllerProperties.class)
164                 .filter(result, Property.class);
165         }
166         return result;
167
168     }
169
170     /**
171      * Add a controller property to the controller. This method overrides
172      * previously set property values if the property already exist.
173      *
174      * @param containerName
175      *            Name of the Container (Eg. 'default')
176      * @param propertyName
177      *            Name of the Property specified by
178      *            {@link org.opendaylight.controller.sal.core.Property} and its
179      *            extended classes
180      * @param propertyValue
181      *            Value of the Property specified by
182      *            {@link org.opendaylight.controller.sal.core.Property} and its
183      *            extended classes
184      * @return Response as dictated by the HTTP Response Status code
185      *
186      *         Example:
187      *
188      *         Request URL:
189      *         http://localhost:8080/controller/nb/v2/controllermanager/default/properties/description/defaultController
190      */
191     @Path("/{containerName}/properties/{propertyName}/{propertyValue}")
192     @PUT
193     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
194     @StatusCodes({ @ResponseCode(code = 201, condition = "Operation successful"),
195             @ResponseCode(code = 400, condition = "Invalid property parameters"),
196             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
197             @ResponseCode(code = 404, condition = "The containerName or property is not found"),
198             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
199     public Response setControllerProperty(@Context UriInfo uriInfo, @PathParam("containerName") String containerName,
200             @PathParam("propertyName") String propertyName, @PathParam("propertyValue") String propertyValue) {
201
202         if (!isValidContainer(containerName)) {
203             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
204         }
205
206         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
207             throw new UnauthorizedException("User is not authorized to perform this operation on container "
208                     + containerName);
209         }
210
211         ISwitchManager switchManager = getISwitchManagerService(containerName);
212
213         Property prop = switchManager.createProperty(propertyName, propertyValue);
214         if (prop == null) {
215             throw new BadRequestException("Property with name " + propertyName + " cannot be created.");
216         }
217
218         Status status = switchManager.setControllerProperty(prop);
219
220         if (status.isSuccess()) {
221             NorthboundUtils.auditlog("Controller Property", username, "updated", propertyName);
222             return Response.created(uriInfo.getRequestUri()).build();
223         }
224         return NorthboundUtils.getResponse(status);
225     }
226
227     /**
228      * Delete a property of the controller
229      *
230      * @param containerName
231      *            Name of the Container (Eg. 'default')
232      * @param propertyName
233      *            Name of the Property specified by
234      *            {@link org.opendaylight.controller.sal.core.Property} and its
235      *            extended classes
236      * @return Response as dictated by the HTTP Response Status code
237      *
238      *         Example:
239      *
240      *         Request URL:
241      *         http://localhost:8080/controller/nb/v2/controllermanager/default/properties/description
242      */
243     @Path("/{containerName}/properties/{propertyName}")
244     @DELETE
245     @StatusCodes({ @ResponseCode(code = 204, condition = "Property removed successfully"),
246             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
247             @ResponseCode(code = 404, condition = "The containerName is not found"),
248             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
249     public Response removeControllerProperty(@PathParam("containerName") String containerName,
250             @PathParam("propertyName") String propertyName) {
251
252         if (!isValidContainer(containerName)) {
253             throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
254         }
255
256         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
257             throw new UnauthorizedException("User is not authorized to perform this operation on container "
258                     + containerName);
259         }
260
261         ISwitchManager switchManager = getISwitchManagerService(containerName);
262
263         Status status = switchManager.removeControllerProperty(propertyName);
264
265         if (status.isSuccess()) {
266             NorthboundUtils.auditlog("Controller Property", username, "removed", propertyName);
267
268             return Response.noContent().build();
269         }
270         return NorthboundUtils.getResponse(status);
271     }
272
273     /**
274      * Save controller configuration
275      *
276      * Request URL:
277      *  http://localhost:8080/controller/nb/v2/controllermanager/configuration
278      *
279      * Request body is empty
280      */
281     @Path("/configuration")
282     @PUT
283     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
284     @StatusCodes({
285             @ResponseCode(code = 204, condition = "Operation successful"),
286             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
287             @ResponseCode(code = 503, condition = "Configuration service is unavailable.")
288     })
289     public Response saveConfiguration() {
290
291         if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
292             throw new UnauthorizedException("User is not authorized to perform this operation");
293         }
294
295         IConfigurationService configService = (IConfigurationService)
296                 ServiceHelper.getGlobalInstance(IConfigurationService.class, this);
297
298         if (configService == null) {
299             throw new ServiceUnavailableException("Configuration Service " +
300                     RestMessages.SERVICEUNAVAILABLE.toString());
301         }
302         Status status = configService.saveConfigurations();
303         if (status.isSuccess()) {
304             NorthboundUtils.auditlog("Controller Configuration", username,
305                     "save", "configuration");
306             return Response.noContent().build();
307         }
308         return NorthboundUtils.getResponse(status);
309     }
310
311     private boolean isValidContainer(String containerName) {
312         if (containerName.equals(GlobalConstants.DEFAULT.toString())) {
313             return true;
314         }
315         IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance(
316                 IContainerManager.class, this);
317         if (containerManager == null) {
318             throw new ServiceUnavailableException("Container Manager " + RestMessages.SERVICEUNAVAILABLE.toString());
319         }
320         if (containerManager.getContainerNames().contains(containerName)) {
321             return true;
322         }
323         return false;
324     }
325
326 }