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.HashSet;
13 import javax.ws.rs.Consumes;
14 import javax.ws.rs.DELETE;
15 import javax.ws.rs.GET;
16 import javax.ws.rs.POST;
17 import javax.ws.rs.Path;
18 import javax.ws.rs.PathParam;
19 import javax.ws.rs.Produces;
20 import javax.ws.rs.QueryParam;
21 import javax.ws.rs.core.Context;
22 import javax.ws.rs.core.MediaType;
23 import javax.ws.rs.core.Response;
24 import javax.ws.rs.core.SecurityContext;
25 import javax.xml.bind.JAXBElement;
27 import org.codehaus.enunciate.jaxrs.ResponseCode;
28 import org.codehaus.enunciate.jaxrs.StatusCodes;
29 import org.codehaus.enunciate.jaxrs.TypeHint;
30 import org.opendaylight.controller.northbound.commons.RestMessages;
31 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
32 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
33 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
34 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
35 import org.opendaylight.controller.sal.authorization.Privilege;
36 import org.opendaylight.controller.sal.utils.ServiceHelper;
37 import org.opendaylight.controller.sal.utils.Status;
38 import org.opendaylight.controller.switchmanager.ISwitchManager;
39 import org.opendaylight.controller.switchmanager.SubnetConfig;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 public class SubnetsNorthboundJAXRS {
45 protected static final Logger logger = LoggerFactory.getLogger(SubnetsNorthboundJAXRS.class);
47 private String username;
50 public void setSecurityContext(SecurityContext context) {
51 username = context.getUserPrincipal().getName();
54 protected String getUserName() {
59 * List all the subnets in a given container
61 * @param containerName
62 * container in which we want to query the subnets
64 * @return a List of SubnetConfig
66 @Path("/{containerName}")
68 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
69 @StatusCodes({ @ResponseCode(code = 404, condition = "The containerName passed was not found") })
70 @TypeHint(SubnetConfigs.class)
71 public SubnetConfigs listSubnets(@PathParam("containerName") String containerName) {
72 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
73 throw new UnauthorizedException("User is not authorized to perform this operation on container "
76 ISwitchManager switchManager = null;
77 switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
78 if (switchManager == null) {
79 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
81 return new SubnetConfigs(switchManager.getSubnetsConfigList());
85 * List the configuration of a subnet in a given container
87 * @param containerName
88 * container in which we want to query the subnet
90 * of the subnet being queried
92 * @return a SubnetConfig
94 @Path("/{containerName}/{subnetName}")
96 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
98 @ResponseCode(code = 404, condition = "The containerName passed was not found"),
99 @ResponseCode(code = 404, condition = "Subnet does not exist") })
100 @TypeHint(SubnetConfig.class)
101 public SubnetConfig listSubnet(
102 @PathParam("containerName") String containerName,
103 @PathParam("subnetName") String subnetName) {
105 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
106 throw new UnauthorizedException("User is not authorized to perform this operation on container "
109 ISwitchManager switchManager = null;
110 switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
111 if (switchManager == null) {
112 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
114 SubnetConfig res = switchManager.getSubnetConfig(subnetName);
116 throw new ResourceNotFoundException(RestMessages.NOSUBNET.toString());
123 * Add a subnet to a container
125 * @param containerName
126 * container in which we want to add/update the subnet
128 * that has to be added
130 * pair default gateway IP/mask that identify the subnet being
134 @Path("/{containerName}/{subnetName}")
137 @ResponseCode(code = 404, condition = "Invalid Data passed"),
138 @ResponseCode(code = 201, condition = "Subnet added"),
139 @ResponseCode(code = 500, condition = "Addition of subnet failed") })
140 public Response addSubnet(
141 @PathParam("containerName") String containerName,
142 @PathParam("subnetName") String subnetName, @QueryParam("subnet") String subnet) {
144 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
145 throw new UnauthorizedException("User is not authorized to perform this operation on container "
148 if (subnetName == null) {
149 throw new ResourceNotFoundException(RestMessages.INVALIDDATA.toString());
151 if (subnet == null) {
152 throw new ResourceNotFoundException(RestMessages.INVALIDDATA.toString());
154 ISwitchManager switchManager = null;
155 switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
156 if (switchManager == null) {
157 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
160 SubnetConfig cfgObject = new SubnetConfig(subnetName, subnet, new HashSet<String>(0));
161 Status status = switchManager.addSubnet(cfgObject);
162 if (status.isSuccess()) {
163 NorthboundUtils.auditlog("Subnet Gateway", username, "added", subnetName, containerName);
164 return Response.status(Response.Status.CREATED).build();
166 throw new InternalServerErrorException(status.getDescription());
170 * Delete a subnet from a container
172 * @param containerName
173 * container in which we want to delete the subnet by name
175 * of the subnet to be remove.
178 @Path("/{containerName}/{subnetName}")
181 @ResponseCode(code = 404, condition = "The containerName passed was not found"),
182 @ResponseCode(code = 500, condition = "Removal of subnet failed") })
183 public Response removeSubnet(
184 @PathParam("containerName") String containerName,
185 @PathParam("subnetName") String subnetName) {
186 if (subnetName == null) {
187 throw new ResourceNotFoundException(RestMessages.INVALIDDATA.toString());
190 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
191 throw new UnauthorizedException("User is not authorized to perform this operation on container "
195 ISwitchManager switchManager = null;
196 switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
197 if (switchManager == null) {
198 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
200 Status status = switchManager.removeSubnet(subnetName);
201 if (status.isSuccess()) {
202 NorthboundUtils.auditlog("Subnet Gateway", username, "removed", subnetName, containerName);
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();
280 NorthboundUtils.auditlog("Subnet Gateway", username, "added", s +" to "+name, containerName);
286 return Response.status(Response.Status.ACCEPTED).build();
288 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
294 * Add ports to a subnet
296 * @param containerName
297 * Name of the Container
299 * Name of the SubnetConfig to be modified
300 * @param subnetConfigData
301 * the {@link SubnetConfig} structure in JSON passed as a POST
303 * @return If the operation is successful or not
305 @Path("/{containerName}/{subnetName}/add")
307 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
309 @ResponseCode(code = 202, condition = "Operation successful"),
310 @ResponseCode(code = 400, condition = "Invalid request"),
311 @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
312 @ResponseCode(code = 500, condition = "Internal server error") })
313 public Response addNodePorts(
314 @PathParam("containerName") String containerName,
315 @PathParam("subnetName") String name,
316 @TypeHint(SubnetConfig.class) JAXBElement<SubnetConfig> subnetConfigData) {
318 SubnetConfig subnetConf = subnetConfigData.getValue();
319 return addOrDeletePorts(containerName, name, subnetConf, "add");
324 * Delete ports from a subnet
326 * @param containerName
327 * Name of the Container
329 * Name of the SubnetConfig to be modified
330 * @param subnetConfigData
331 * the {@link SubnetConfig} structure in JSON passed as a POST
333 * @return If the operation is successful or not
335 @Path("/{containerName}/{subnetName}/delete")
337 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
339 @ResponseCode(code = 202, condition = "Operation successful"),
340 @ResponseCode(code = 400, condition = "Invalid request"),
341 @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
342 @ResponseCode(code = 500, condition = "Internal server error") })
343 public Response deleteNodePorts(
344 @PathParam("containerName") String containerName,
345 @PathParam("subnetName") String name,
346 @TypeHint(SubnetConfig.class) JAXBElement<SubnetConfig> subnetConfigData) {
348 SubnetConfig subnetConf = subnetConfigData.getValue();
349 return addOrDeletePorts(containerName, name, subnetConf, "delete");
354 * Add/Delete ports to/from a subnet
356 * @param containerName
357 * Name of the Container
359 * Name of the SubnetConfig to be modified
360 * @param subnetConfig
361 * the {@link SubnetConfig} structure
364 * @return If the operation is successful or not
366 private Response addOrDeletePorts(String containerName, String name, SubnetConfig subnetConf, String action) {
368 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
369 throw new UnauthorizedException("User is not authorized to perform this operation on container "
373 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
375 if (switchManager == null) {
376 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
379 SubnetConfig existingConf = switchManager.getSubnetConfig(name);
381 // make sure that the name matches an existing subnet and we're not
382 // changing the name or subnet IP/mask
383 if (existingConf == null) {
384 // don't have a subnet by that name
385 return Response.status(Response.Status.NOT_FOUND).build();
386 } else if (!existingConf.getName().equals(subnetConf.getName())
387 || !existingConf.getSubnet().equals(subnetConf.getSubnet())) {
388 // can't change the name of a subnet
389 return Response.status(Response.Status.BAD_REQUEST).build();
392 boolean successful = true;
393 Set<String> ports = subnetConf.getNodePorts();
395 if (action.equals("add")) {
397 ports.removeAll(existingConf.getNodePorts());
398 for (String port : ports) {
399 st = switchManager.addPortsToSubnet(name, port);
400 successful = successful && st.isSuccess();
402 NorthboundUtils.auditlog("Subnet Gateway", username, "added", st +" to "+name, containerName);
405 } else if (action.equals("delete")) {
406 // delete existing ports
407 ports.retainAll(existingConf.getNodePorts());
408 for (String port : ports) {
409 st = switchManager.removePortsFromSubnet(name, port);
410 successful = successful && st.isSuccess();
412 NorthboundUtils.auditlog("Subnet Gateway", username, "removed", st +" from "+name, containerName);
416 return Response.status(Response.Status.BAD_REQUEST).build();
420 return Response.status(Response.Status.ACCEPTED).build();
422 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();