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.ArrayList;
11 import java.util.HashSet;
12 import java.util.List;
15 import javax.ws.rs.Consumes;
16 import javax.ws.rs.DELETE;
17 import javax.ws.rs.GET;
18 import javax.ws.rs.POST;
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.xml.bind.JAXBElement;
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.northbound.commons.RestMessages;
33 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
34 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
35 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
36 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
37 import org.opendaylight.controller.sal.authorization.Privilege;
38 import org.opendaylight.controller.sal.utils.ServiceHelper;
39 import org.opendaylight.controller.sal.utils.Status;
40 import org.opendaylight.controller.switchmanager.ISwitchManager;
41 import org.opendaylight.controller.switchmanager.SubnetConfig;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 public class SubnetsNorthboundJAXRS {
47 protected static final Logger logger = LoggerFactory.getLogger(SubnetsNorthboundJAXRS.class);
49 private String username;
52 public void setSecurityContext(SecurityContext context) {
53 username = context.getUserPrincipal().getName();
56 protected String getUserName() {
61 * List all the subnets in a given container
63 * @param containerName
64 * container in which we want to query the subnets
66 * @return a List of SubnetConfig
68 @Path("/{containerName}")
70 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
71 @StatusCodes({ @ResponseCode(code = 404, condition = "The containerName passed was not found") })
72 @TypeHint(SubnetConfigs.class)
73 public SubnetConfigs listSubnets(@PathParam("containerName") String containerName) {
74 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
75 throw new UnauthorizedException("User is not authorized to perform this operation on container "
78 ISwitchManager switchManager = null;
79 switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
80 if (switchManager == null) {
81 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
83 return new SubnetConfigs(switchManager.getSubnetsConfigList());
87 * List the configuration of a subnet in a given container
89 * @param containerName
90 * container in which we want to query the subnet
92 * of the subnet being queried
94 * @return a SubnetConfig
96 @Path("/{containerName}/{subnetName}")
98 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
100 @ResponseCode(code = 404, condition = "The containerName passed was not found"),
101 @ResponseCode(code = 404, condition = "Subnet does not exist") })
102 @TypeHint(SubnetConfig.class)
103 public SubnetConfig listSubnet(
104 @PathParam("containerName") String containerName,
105 @PathParam("subnetName") String subnetName) {
107 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
108 throw new UnauthorizedException("User is not authorized to perform this operation on container "
111 ISwitchManager switchManager = null;
112 switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
113 if (switchManager == null) {
114 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
116 SubnetConfig res = switchManager.getSubnetConfig(subnetName);
118 throw new ResourceNotFoundException(RestMessages.NOSUBNET.toString());
125 * Add a subnet to a container
127 * @param containerName
128 * container in which we want to add/update the subnet
130 * that has to be added
132 * pair default gateway IP/mask that identify the subnet being
136 @Path("/{containerName}/{subnetName}")
139 @ResponseCode(code = 404, condition = "Invalid Data passed"),
140 @ResponseCode(code = 201, condition = "Subnet added"),
141 @ResponseCode(code = 500, condition = "Addition of subnet failed") })
142 public Response addSubnet(
143 @PathParam("containerName") String containerName,
144 @PathParam("subnetName") String subnetName, @QueryParam("subnet") String subnet) {
146 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
147 throw new UnauthorizedException("User is not authorized to perform this operation on container "
150 if (subnetName == null) {
151 throw new ResourceNotFoundException(RestMessages.INVALIDDATA.toString());
153 if (subnet == null) {
154 throw new ResourceNotFoundException(RestMessages.INVALIDDATA.toString());
156 ISwitchManager switchManager = null;
157 switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
158 if (switchManager == null) {
159 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
162 SubnetConfig cfgObject = new SubnetConfig(subnetName, subnet, new ArrayList<String>(0));
163 Status status = switchManager.addSubnet(cfgObject);
164 if (status.isSuccess()) {
165 return Response.status(Response.Status.CREATED).build();
167 throw new InternalServerErrorException(status.getDescription());
171 * Delete a subnet from a container
173 * @param containerName
174 * container in which we want to delete the subnet by name
176 * of the subnet to be remove.
179 @Path("/{containerName}/{subnetName}")
182 @ResponseCode(code = 404, condition = "The containerName passed was not found"),
183 @ResponseCode(code = 500, condition = "Removal of subnet failed") })
184 public Response removeSubnet(
185 @PathParam("containerName") String containerName,
186 @PathParam("subnetName") String subnetName) {
187 if (subnetName == null) {
188 throw new ResourceNotFoundException(RestMessages.INVALIDDATA.toString());
191 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
192 throw new UnauthorizedException("User is not authorized to perform this operation on container "
196 ISwitchManager switchManager = null;
197 switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
198 if (switchManager == null) {
199 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
201 Status status = switchManager.removeSubnet(subnetName);
202 if (status.isSuccess()) {
203 return Response.status(Response.Status.OK).build();
205 throw new InternalServerErrorException(status.getDescription());
209 * Modify a subnet. For now only changing the port list is allowed.
211 * @param containerName
212 * Name of the Container
214 * Name of the SubnetConfig to be modified
215 * @param subnetConfigData
216 * the {@link SubnetConfig} structure in JSON passed as a POST
218 * @return If the operation is successful or not
220 @Path("/{containerName}/{subnetName}/modify")
222 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
224 @ResponseCode(code = 202, condition = "Operation successful"),
225 @ResponseCode(code = 400, condition = "Invalid request, i.e., requested changing the subnet name"),
226 @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
227 @ResponseCode(code = 500, condition = "Internal server error") })
228 public Response modifySubnet(@PathParam("containerName") String containerName,
229 @PathParam("subnetName") String name,
230 @TypeHint(SubnetConfig.class) JAXBElement<SubnetConfig> subnetConfigData) {
232 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
233 throw new UnauthorizedException("User is not authorized to perform this operation on container "
237 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
239 if (switchManager == null) {
240 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
243 SubnetConfig subnetConf = subnetConfigData.getValue();
244 SubnetConfig existingConf = switchManager.getSubnetConfig(name);
246 boolean successful = true;
248 // make sure that the name matches an existing subnet and we're not
249 // changing the name or subnet IP/mask
250 if (existingConf == null) {
251 // don't have a subnet by that name
252 return Response.status(Response.Status.NOT_FOUND).build();
254 } else if (!existingConf.getName().equals(subnetConf.getName())
255 || !existingConf.getSubnet().equals(subnetConf.getSubnet())) {
256 // can't change the name of a subnet
257 return Response.status(Response.Status.BAD_REQUEST).build();
260 // create a set for fast lookups
261 Set<String> newPorts = new HashSet<String>(subnetConf.getNodePorts());
263 // go through the current ports and (1) remove ports that aren't
264 // there anymore and (2) remove ports that are still there from the
265 // set of ports to add
266 for (String s : existingConf.getNodePorts()) {
267 if (newPorts.contains(s)) {
270 Status st = switchManager.removePortsFromSubnet(name, s);
271 successful = successful && st.isSuccess();
275 // add any remaining ports
276 for (String s : newPorts) {
277 Status st = switchManager.addPortsToSubnet(name, s);
278 successful = successful && st.isSuccess();
283 return Response.status(Response.Status.ACCEPTED).build();
285 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
291 * Add ports to a subnet
293 * @param containerName
294 * Name of the Container
296 * Name of the SubnetConfig to be modified
297 * @param subnetConfigData
298 * the {@link SubnetConfig} structure in JSON passed as a POST
300 * @return If the operation is successful or not
302 @Path("/{containerName}/{subnetName}/add")
304 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
306 @ResponseCode(code = 202, condition = "Operation successful"),
307 @ResponseCode(code = 400, condition = "Invalid request"),
308 @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
309 @ResponseCode(code = 500, condition = "Internal server error") })
310 public Response addNodePorts(
311 @PathParam("containerName") String containerName,
312 @PathParam("subnetName") String name,
313 @TypeHint(SubnetConfig.class) JAXBElement<SubnetConfig> subnetConfigData) {
315 SubnetConfig subnetConf = subnetConfigData.getValue();
316 return addOrDeletePorts(containerName, name, subnetConf, "add");
321 * Delete ports from a subnet
323 * @param containerName
324 * Name of the Container
326 * Name of the SubnetConfig to be modified
327 * @param subnetConfigData
328 * the {@link SubnetConfig} structure in JSON passed as a POST
330 * @return If the operation is successful or not
332 @Path("/{containerName}/{subnetName}/delete")
334 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
336 @ResponseCode(code = 202, condition = "Operation successful"),
337 @ResponseCode(code = 400, condition = "Invalid request"),
338 @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
339 @ResponseCode(code = 500, condition = "Internal server error") })
340 public Response deleteNodePorts(
341 @PathParam("containerName") String containerName,
342 @PathParam("subnetName") String name,
343 @TypeHint(SubnetConfig.class) JAXBElement<SubnetConfig> subnetConfigData) {
345 SubnetConfig subnetConf = subnetConfigData.getValue();
346 return addOrDeletePorts(containerName, name, subnetConf, "delete");
351 * Add/Delete ports to/from a subnet
353 * @param containerName
354 * Name of the Container
356 * Name of the SubnetConfig to be modified
357 * @param subnetConfig
358 * the {@link SubnetConfig} structure
361 * @return If the operation is successful or not
363 private Response addOrDeletePorts(String containerName, String name, SubnetConfig subnetConf, String action) {
365 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
366 throw new UnauthorizedException("User is not authorized to perform this operation on container "
370 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
372 if (switchManager == null) {
373 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
376 SubnetConfig existingConf = switchManager.getSubnetConfig(name);
378 // make sure that the name matches an existing subnet and we're not
379 // changing the name or subnet IP/mask
380 if (existingConf == null) {
381 // don't have a subnet by that name
382 return Response.status(Response.Status.NOT_FOUND).build();
383 } else if (!existingConf.getName().equals(subnetConf.getName())
384 || !existingConf.getSubnet().equals(subnetConf.getSubnet())) {
385 // can't change the name of a subnet
386 return Response.status(Response.Status.BAD_REQUEST).build();
389 boolean successful = true;
390 List<String> ports = subnetConf.getNodePorts();
392 if (action.equals("add")) {
394 ports.removeAll(existingConf.getNodePorts());
395 for (String port : ports) {
396 st = switchManager.addPortsToSubnet(name, port);
397 successful = successful && st.isSuccess();
399 } else if (action.equals("delete")) {
400 // delete existing ports
401 ports.retainAll(existingConf.getNodePorts());
402 for (String port : ports) {
403 st = switchManager.removePortsFromSubnet(name, port);
404 successful = successful && st.isSuccess();
407 return Response.status(Response.Status.BAD_REQUEST).build();
411 return Response.status(Response.Status.ACCEPTED).build();
413 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();