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.controllermanager.northbound;
11 import java.util.HashSet;
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;
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;
50 * The class provides Northbound REST APIs to manager the controller. Currently
51 * it supports getting controller property(ies), setting a property, and
57 public class ControllerManagerNorthbound {
59 private String username;
60 private QueryContext queryContext;
63 public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
64 if (queryCtxResolver != null) {
65 queryContext = queryCtxResolver.getContext(QueryContext.class);
70 public void setSecurityContext(SecurityContext context) {
71 if (context != null && context.getUserPrincipal() != null) {
72 username = context.getUserPrincipal().getName();
76 protected String getUserName() {
80 private ISwitchManager getISwitchManagerService(String containerName) {
81 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
84 if (switchManager == null) {
85 throw new ServiceUnavailableException("Switch Manager " + RestMessages.SERVICEUNAVAILABLE.toString());
92 * Retrieve a property or all properties for the controller in the network
94 * @param containerName
95 * Name of the Container (Eg. 'default')
97 * Name of the Property specified by
98 * {@link org.opendaylight.controller.sal.core.Property} and its
104 * http://localhost:8080/controller/nb/v2/controllermanager/default/properties/?propertyName=macAddress
106 * Response Body in XML:
107 * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
108 * <controllerProperties>
111 * <value>3e:04:ef:11:13:80</value>
114 * </controllerProperties>
116 * Response Body in JSON:
117 * { "controllerProperties":
120 * { "value": "3e:04:ef:11:13:80" }
126 @Path("/{containerName}/properties/")
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) {
138 if (!isValidContainer(containerName)) {
139 throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
142 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
143 throw new UnauthorizedException("User is not authorized to perform this operation on container "
147 ISwitchManager switchManager = getISwitchManagerService(containerName);
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);
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);
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);
171 * Add a controller property to the controller. This method overrides
172 * previously set property values if the property already exist.
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
180 * @param propertyValue
181 * Value of the Property specified by
182 * {@link org.opendaylight.controller.sal.core.Property} and its
184 * @return Response as dictated by the HTTP Response Status code
189 * http://localhost:8080/controller/nb/v2/controllermanager/default/properties/description/defaultController
191 @Path("/{containerName}/properties/{propertyName}/{propertyValue}")
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) {
202 if (!isValidContainer(containerName)) {
203 throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
206 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
207 throw new UnauthorizedException("User is not authorized to perform this operation on container "
211 ISwitchManager switchManager = getISwitchManagerService(containerName);
213 Property prop = switchManager.createProperty(propertyName, propertyValue);
215 throw new BadRequestException("Property with name " + propertyName + " cannot be created.");
218 Status status = switchManager.setControllerProperty(prop);
220 if (status.isSuccess()) {
221 NorthboundUtils.auditlog("Controller Property", username, "updated", propertyName);
222 return Response.created(uriInfo.getRequestUri()).build();
224 return NorthboundUtils.getResponse(status);
228 * Delete a property of the controller
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
236 * @return Response as dictated by the HTTP Response Status code
241 * http://localhost:8080/controller/nb/v2/controllermanager/default/properties/description
243 @Path("/{containerName}/properties/{propertyName}")
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) {
252 if (!isValidContainer(containerName)) {
253 throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
256 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
257 throw new UnauthorizedException("User is not authorized to perform this operation on container "
261 ISwitchManager switchManager = getISwitchManagerService(containerName);
263 Status status = switchManager.removeControllerProperty(propertyName);
265 if (status.isSuccess()) {
266 NorthboundUtils.auditlog("Controller Property", username, "removed", propertyName);
268 return Response.noContent().build();
270 return NorthboundUtils.getResponse(status);
274 * Save controller configuration
277 * http://localhost:8080/controller/nb/v2/controllermanager/configuration
279 * Request body is empty
281 @Path("/configuration")
283 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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.")
289 public Response saveConfiguration() {
291 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
292 throw new UnauthorizedException("User is not authorized to perform this operation");
295 IConfigurationService configService = (IConfigurationService)
296 ServiceHelper.getGlobalInstance(IConfigurationService.class, this);
298 if (configService == null) {
299 throw new ServiceUnavailableException("Configuration Service " +
300 RestMessages.SERVICEUNAVAILABLE.toString());
302 Status status = configService.saveConfigurations();
303 if (status.isSuccess()) {
304 NorthboundUtils.auditlog("Controller Configuration", username,
305 "save", "configuration");
306 return Response.noContent().build();
308 return NorthboundUtils.getResponse(status);
311 private boolean isValidContainer(String containerName) {
312 if (containerName.equals(GlobalConstants.DEFAULT.toString())) {
315 IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance(
316 IContainerManager.class, this);
317 if (containerManager == null) {
318 throw new ServiceUnavailableException("Container Manager " + RestMessages.SERVICEUNAVAILABLE.toString());
320 if (containerManager.getContainerNames().contains(containerName)) {