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
8 package org.opendaylight.controller.subnets.northbound;
10 import java.util.List;
11 import javax.ws.rs.Consumes;
12 import javax.ws.rs.DELETE;
13 import javax.ws.rs.GET;
14 import javax.ws.rs.POST;
15 import javax.ws.rs.PUT;
16 import javax.ws.rs.Path;
17 import javax.ws.rs.PathParam;
18 import javax.ws.rs.Produces;
19 import javax.ws.rs.core.Context;
20 import javax.ws.rs.core.MediaType;
21 import javax.ws.rs.core.Response;
22 import javax.ws.rs.core.SecurityContext;
23 import javax.ws.rs.core.UriInfo;
25 import org.codehaus.enunciate.jaxrs.ResponseCode;
26 import org.codehaus.enunciate.jaxrs.StatusCodes;
27 import org.codehaus.enunciate.jaxrs.TypeHint;
28 import org.opendaylight.controller.containermanager.IContainerManager;
29 import org.opendaylight.controller.northbound.commons.RestMessages;
30 import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
31 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
32 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
33 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
34 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
35 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
36 import org.opendaylight.controller.sal.authorization.Privilege;
37 import org.opendaylight.controller.sal.utils.ServiceHelper;
38 import org.opendaylight.controller.sal.utils.Status;
39 import org.opendaylight.controller.switchmanager.ISwitchManager;
40 import org.opendaylight.controller.switchmanager.SubnetConfig;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * This class provides REST APIs to manage subnets.
49 * Authentication scheme : <b>HTTP Basic</b><br>
50 * Authentication realm : <b>opendaylight</b><br>
51 * Transport : <b>HTTP and HTTPS</b><br>
53 * HTTPS Authentication is disabled by default.
58 public class SubnetsNorthbound {
59 protected static final Logger logger = LoggerFactory.getLogger(SubnetsNorthbound.class);
61 private String username;
64 public void setSecurityContext(SecurityContext context) {
65 if (context != null && context.getUserPrincipal() != null) {
66 username = context.getUserPrincipal().getName();
70 protected String getUserName() {
74 private void handleContainerDoesNotExist(String containerName) {
75 IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance(
76 IContainerManager.class, this);
77 if (containerManager == null) {
78 throw new ServiceUnavailableException("Container " + RestMessages.NOCONTAINER.toString());
81 List<String> containerNames = containerManager.getContainerNames();
82 for (String cName : containerNames) {
83 if (cName.trim().equalsIgnoreCase(containerName.trim())) {
88 throw new ResourceNotFoundException(containerName + " " + RestMessages.NOCONTAINER.toString());
91 private void handleNameMismatch(String name, String nameinURL) {
92 if (name == null || nameinURL == null) {
93 throw new BadRequestException(RestMessages.INVALIDDATA.toString() + " : Name is null");
96 if (name.equals(nameinURL)) {
99 throw new ResourceConflictException(RestMessages.INVALIDDATA.toString()
100 + " : Name in URL does not match the name in request body");
104 * List all the subnets in a given container
106 * @param containerName
107 * container in which we want to query the subnets
109 * @return a List of SubnetConfig
114 * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnets
117 * <subnetConfig>
118 * <name>marketingdepartment</name>
119 * <subnet>30.31.54.254/24</subnet>
120 * </subnetConfig>
121 * <subnetConfig>
122 * <name>salesdepartment</name>
123 * <subnet>20.18.1.254/16</subnet>
124 * <nodeConnectors>0F|11@OF|00:00:00:aa:bb:cc:dd:ee>/nodeConnectors>
125 * <nodeConnectors>0F|13@OF|00:00:00:aa:bb:cc:dd:ee>/nodeConnectors>
126 * </subnetConfig>
130 * "name":"marketingdepartment",
131 * "subnet":"30.31.54.254/24",
134 * "name":"salesdepartment",
135 * "subnet":"20.18.1.254/16",
136 * "nodeConnectors":["0F|11@OF|00:00:00:aa:bb:cc:dd:ee", "0F|13@OF|00:00:00:aa:bb:cc:dd:ee"]
140 @Path("/{containerName}/subnets")
142 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
143 @StatusCodes({ @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
144 @ResponseCode(code = 404, condition = "The containerName passed was not found"),
145 @ResponseCode(code = 503, condition = "Service unavailable") })
146 @TypeHint(SubnetConfigs.class)
147 public SubnetConfigs listSubnets(@PathParam("containerName") String containerName) {
149 handleContainerDoesNotExist(containerName);
150 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
151 throw new UnauthorizedException("User is not authorized to perform this operation on container "
154 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
155 if (switchManager == null) {
156 throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
158 return new SubnetConfigs(switchManager.getSubnetsConfigList());
162 * List the configuration of a subnet in a given container
164 * @param containerName
165 * container in which we want to query the subnet
167 * of the subnet being queried
169 * @return SubnetConfig
174 * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/marketingdepartment
177 * <subnetConfig>
178 * <name>marketingdepartment</name>
179 * <subnet>30.0.0.1/24</subnet>
180 * <nodeConnectors>0F|1@OF|00:00:11:22:33:44:55:66>/nodePorts>
181 * <nodeConnectors>0F|3@OF|00:00:11:22:33:44:55:66>/nodePorts>
182 * </subnetConfig>
186 * "name":"marketingdepartment",
187 * "subnet":"30.0.0.1/24",
188 * "nodeConnectors":["0F|1@OF|00:00:11:22:33:44:55:66", "0F|3@OF|00:00:11:22:33:44:55:66"]
192 @Path("/{containerName}/subnet/{subnetName}")
194 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
195 @StatusCodes({ @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
196 @ResponseCode(code = 404, condition = "The containerName or subnetName passed was not found"),
197 @ResponseCode(code = 503, condition = "Service unavailable") })
198 @TypeHint(SubnetConfig.class)
199 public SubnetConfig listSubnet(@PathParam("containerName") String containerName,
200 @PathParam("subnetName") String subnetName) {
202 handleContainerDoesNotExist(containerName);
204 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
205 throw new UnauthorizedException("User is not authorized to perform this operation on container "
208 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
209 if (switchManager == null) {
210 throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
212 SubnetConfig res = switchManager.getSubnetConfig(subnetName);
214 throw new ResourceNotFoundException(RestMessages.NOSUBNET.toString());
220 * Add a subnet into the specified container context, node connectors are optional
222 * @param containerName
223 * name of the container context in which the subnet needs to be added
225 * name of new subnet to be added
226 * @param subnetConfigData
227 * the {@link SubnetConfig} structure in request body
229 * @return Response as dictated by the HTTP Response Status code
234 * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/salesdepartment
237 * <subnetConfig>
238 * <name>salesdepartment</name>
239 * <subnet>172.173.174.254/24</subnet>
240 * <nodeConnectors>0F|22@OF|00:00:11:22:33:44:55:66>/nodeConnectors>
241 * <nodeConnectors>0F|39@OF|00:00:ab:cd:33:44:55:66>/nodeConnectors>
242 * </subnetConfig>
246 * "name":"salesdepartment",
247 * "subnet":"172.173.174.254/24"
248 * "nodeConnectors":["0F|22@OF|00:00:11:22:33:44:55:66", "0F|39@OF|00:00:ab:cd:33:44:55:66"]
253 @Path("/{containerName}/subnet/{subnetName}")
255 @StatusCodes({ @ResponseCode(code = 201, condition = "Subnet created successfully"),
256 @ResponseCode(code = 400, condition = "Invalid data passed"),
257 @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
258 @ResponseCode(code = 409, condition = "Subnet name in url conflicts with name in request body"),
259 @ResponseCode(code = 404, condition = "Container name passed was not found or subnet config is null"),
260 @ResponseCode(code = 500, condition = "Internal Server Error: Addition of subnet failed"),
261 @ResponseCode(code = 503, condition = "Service unavailable") })
262 public Response addSubnet(@PathParam("containerName") String containerName,
263 @PathParam("subnetName") String subnetName,
264 @TypeHint(SubnetConfig.class) SubnetConfig subnetConfigData) {
266 handleContainerDoesNotExist(containerName);
268 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
269 throw new UnauthorizedException("User is not authorized to perform this operation on container "
272 SubnetConfig cfgObject = subnetConfigData;
273 handleNameMismatch(cfgObject.getName(), subnetName);
275 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
276 if (switchManager == null) {
277 throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
279 Status status = switchManager.addSubnet(cfgObject);
280 if (status.isSuccess()) {
281 NorthboundUtils.auditlog("Subnet Gateway", username, "added", subnetName, containerName);
282 return Response.status(Response.Status.CREATED).build();
284 return NorthboundUtils.getResponse(status);
288 * Delete a subnet from the specified container context
290 * @param containerName
291 * name of the container in which subnet needs to be removed
293 * name of new subnet to be deleted
294 * @return Response as dictated by the HTTP Response Status code
298 * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/engdepartment
302 @Path("/{containerName}/subnet/{subnetName}")
304 @StatusCodes({ @ResponseCode(code = 204, condition = "No Content"),
305 @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
306 @ResponseCode(code = 404, condition = "The containerName passed was not found"),
307 @ResponseCode(code = 500, condition = "Internal Server Error : Removal of subnet failed"),
308 @ResponseCode(code = 503, condition = "Service unavailable") })
309 public Response removeSubnet(@PathParam("containerName") String containerName,
310 @PathParam("subnetName") String subnetName) {
312 handleContainerDoesNotExist(containerName);
314 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
315 throw new UnauthorizedException("User is not authorized to perform this operation on container "
319 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
320 if (switchManager == null) {
321 throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
323 Status status = switchManager.removeSubnet(subnetName);
324 if (status.isSuccess()) {
325 NorthboundUtils.auditlog("Subnet Gateway", username, "removed", subnetName, containerName);
326 return Response.status(Response.Status.NO_CONTENT).build();
328 return NorthboundUtils.getResponse(status);
332 * Modify a subnet. Replace the existing subnet with the new specified one.
333 * For now only port list modification is allowed. If the respective subnet
334 * configuration does not exist this call is equivalent to a subnet
337 * @param containerName
338 * Name of the Container context
340 * Name of the subnet to be modified
341 * @param subnetConfigData
342 * the {@link SubnetConfig} structure in request body parameter
343 * @return Response as dictated by the HTTP Response Status code
348 * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/salesdepartment
351 * <subnetConfig>
352 * <name>salesdepartment</name>
353 * <subnet>172.173.174.254/24</subnet>
354 * <nodeConnectors>0F|22@OF|00:00:11:22:33:44:55:66>/nodeConnectors>
355 * <nodeConnectors>0F|39@OF|00:00:ab:cd:33:44:55:66>/nodeConnectors>
356 * </subnetConfig>
360 * "name":"salesdepartment",
361 * "subnet":"172.173.174.254/24"
362 * "nodeConnectors":["0F|22@OF|00:00:11:22:33:44:55:66", "0F|39@OF|00:00:ab:cd:33:44:55:66"]
366 @Path("/{containerName}/subnet/{subnetName}")
368 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
369 @StatusCodes({ @ResponseCode(code = 200, condition = "Configuration replaced successfully"),
370 @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
371 @ResponseCode(code = 409, condition = "Subnet name in url conflicts with name in request body"),
372 @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
373 @ResponseCode(code = 500, condition = "Internal server error: Modify subnet failed"),
374 @ResponseCode(code = 503, condition = "Service unavailable") })
375 public Response modifySubnet(@Context UriInfo uriInfo, @PathParam("containerName") String containerName,
376 @PathParam("subnetName") String subnetName, @TypeHint(SubnetConfig.class) SubnetConfig subnetConfigData) {
378 handleContainerDoesNotExist(containerName);
380 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
381 throw new UnauthorizedException("User is not authorized to perform this operation on container "
384 handleNameMismatch(subnetConfigData.getName(), subnetName);
386 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
388 if (switchManager == null) {
389 throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
392 // Need to check this until Status does not return a CREATED status code
393 SubnetConfig existingConf = switchManager.getSubnetConfig(subnetName);
395 Status status = switchManager.modifySubnet(subnetConfigData);
397 if (status.isSuccess()) {
398 if (existingConf == null) {
399 NorthboundUtils.auditlog("Subnet Gateway", username, "created", subnetName, containerName);
400 return Response.created(uriInfo.getRequestUri()).build();
402 NorthboundUtils.auditlog("Subnet Gateway", username, "modified", subnetName, containerName);
405 return NorthboundUtils.getResponse(status);