/*
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.controller.controllermanager.northbound;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.codehaus.enunciate.jaxrs.TypeHint;
import org.opendaylight.controller.configuration.IConfigurationService;
import org.opendaylight.controller.containermanager.IContainerManager;
import org.opendaylight.controller.northbound.commons.RestMessages;
import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.core.Property;
import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.ServiceHelper;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.switchmanager.ISwitchManager;
/**
* The class provides Northbound REST APIs to manager the controller. Currently
* it supports getting controller property(ies), setting a property, and
* removing a property
*
*/
@Path("/")
public class ControllerManagerNorthbound {
private String username;
@Context
public void setSecurityContext(SecurityContext context) {
if (context != null && context.getUserPrincipal() != null) {
username = context.getUserPrincipal().getName();
}
}
protected String getUserName() {
return username;
}
private ISwitchManager getISwitchManagerService(String containerName) {
ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
this);
if (switchManager == null) {
throw new ServiceUnavailableException("Switch Manager " + RestMessages.SERVICEUNAVAILABLE.toString());
}
return switchManager;
}
/**
* Retrieve a property or all properties for the controller in the network
*
* @param containerName
* Name of the Container (Eg. 'default')
* @param propertyName
* Name of the Property specified by
* {@link org.opendaylight.controller.sal.core.Property} and its
* extended classes
*
* Example:
*
* Request URL:
* http://localhost:8080/controller/nb/v2/controllermanager/default/properties/?propertyName=macAddress
*
* Response Body in XML:
*
*
*
*
* 3e:04:ef:11:13:80
*
*
*
*
* Response Body in JSON:
* { "controllerProperties":
* {"properties":
* { "macAddress":
* { "value": "3e:04:ef:11:13:80" }
* }
* }
* }
*
*/
@Path("/{containerName}/properties/")
@GET
@TypeHint(Property.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
@ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
@ResponseCode(code = 404, condition = "The containerName or property is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
public ControllerProperties getControllerProperties(@PathParam("containerName") String containerName,
@QueryParam("propertyName") String propertyName) {
if (!isValidContainer(containerName)) {
throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
}
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container "
+ containerName);
}
ISwitchManager switchManager = getISwitchManagerService(containerName);
if (propertyName == null) {
Map propertyMap = switchManager.getControllerProperties();
Set properties = new HashSet(propertyMap.values());
return new ControllerProperties(properties);
}
Set properties = new HashSet();
Property property = switchManager.getControllerProperty(propertyName);
if (property == null) {
throw new ResourceNotFoundException("Unable to find property with name: " + propertyName);
}
properties.add(property);
return new ControllerProperties(properties);
}
/**
* Add a controller property to the controller. This method overrides
* previously set property values if the property already exist.
*
* @param containerName
* Name of the Container (Eg. 'default')
* @param propertyName
* Name of the Property specified by
* {@link org.opendaylight.controller.sal.core.Property} and its
* extended classes
* @param propertyValue
* Value of the Property specified by
* {@link org.opendaylight.controller.sal.core.Property} and its
* extended classes
* @return Response as dictated by the HTTP Response Status code
*
* Example:
*
* Request URL:
* http://localhost:8080/controller/nb/v2/controllermanager/default/properties/description/defaultController
*/
@Path("/{containerName}/properties/{propertyName}/{propertyValue}")
@PUT
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@StatusCodes({ @ResponseCode(code = 201, condition = "Operation successful"),
@ResponseCode(code = 400, condition = "Invalid property parameters"),
@ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
@ResponseCode(code = 404, condition = "The containerName or property is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
public Response setControllerProperty(@Context UriInfo uriInfo, @PathParam("containerName") String containerName,
@PathParam("propertyName") String propertyName, @PathParam("propertyValue") String propertyValue) {
if (!isValidContainer(containerName)) {
throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
}
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container "
+ containerName);
}
ISwitchManager switchManager = getISwitchManagerService(containerName);
Property prop = switchManager.createProperty(propertyName, propertyValue);
if (prop == null) {
throw new BadRequestException("Property with name " + propertyName + " cannot be created.");
}
Status status = switchManager.setControllerProperty(prop);
if (status.isSuccess()) {
NorthboundUtils.auditlog("Controller Property", username, "updated", propertyName);
return Response.created(uriInfo.getRequestUri()).build();
}
return NorthboundUtils.getResponse(status);
}
/**
* Delete a property of the controller
*
* @param containerName
* Name of the Container (Eg. 'default')
* @param propertyName
* Name of the Property specified by
* {@link org.opendaylight.controller.sal.core.Property} and its
* extended classes
* @return Response as dictated by the HTTP Response Status code
*
* Example:
*
* Request URL:
* http://localhost:8080/controller/nb/v2/controllermanager/default/properties/description
*/
@Path("/{containerName}/properties/{propertyName}")
@DELETE
@StatusCodes({ @ResponseCode(code = 204, condition = "Property removed successfully"),
@ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
@ResponseCode(code = 404, condition = "The containerName is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
public Response removeControllerProperty(@PathParam("containerName") String containerName,
@PathParam("propertyName") String propertyName) {
if (!isValidContainer(containerName)) {
throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
}
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container "
+ containerName);
}
ISwitchManager switchManager = getISwitchManagerService(containerName);
Status status = switchManager.removeControllerProperty(propertyName);
if (status.isSuccess()) {
NorthboundUtils.auditlog("Controller Property", username, "removed", propertyName);
return Response.noContent().build();
}
return NorthboundUtils.getResponse(status);
}
/**
* Save controller configuration
*
* Request URL:
* http://localhost:8080/controller/nb/v2/controllermanager/configuration
*
* Request body is empty
*/
@Path("/configuration")
@PUT
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@StatusCodes({
@ResponseCode(code = 204, condition = "Operation successful"),
@ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
@ResponseCode(code = 503, condition = "Configuration service is unavailable.")
})
public Response saveConfiguration() {
if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation");
}
IConfigurationService configService = (IConfigurationService)
ServiceHelper.getGlobalInstance(IConfigurationService.class, this);
if (configService == null) {
throw new ServiceUnavailableException("Configuration Service " +
RestMessages.SERVICEUNAVAILABLE.toString());
}
Status status = configService.saveConfigurations();
if (status.isSuccess()) {
NorthboundUtils.auditlog("Controller Configuration", username,
"save", "configuration");
return Response.noContent().build();
}
return NorthboundUtils.getResponse(status);
}
private boolean isValidContainer(String containerName) {
if (containerName.equals(GlobalConstants.DEFAULT.toString())) {
return true;
}
IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance(
IContainerManager.class, this);
if (containerManager == null) {
throw new ServiceUnavailableException("Container Manager " + RestMessages.SERVICEUNAVAILABLE.toString());
}
if (containerManager.getContainerNames().contains(containerName)) {
return true;
}
return false;
}
}