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