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 return Response.status(Response.Status.CREATED).build();
165 throw new InternalServerErrorException(status.getDescription());
169 * Delete a subnet from a container
171 * @param containerName
172 * container in which we want to delete the subnet by name
174 * of the subnet to be remove.
177 @Path("/{containerName}/{subnetName}")
180 @ResponseCode(code = 404, condition = "The containerName passed was not found"),
181 @ResponseCode(code = 500, condition = "Removal of subnet failed") })
182 public Response removeSubnet(
183 @PathParam("containerName") String containerName,
184 @PathParam("subnetName") String subnetName) {
185 if (subnetName == null) {
186 throw new ResourceNotFoundException(RestMessages.INVALIDDATA.toString());
189 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
190 throw new UnauthorizedException("User is not authorized to perform this operation on container "
194 ISwitchManager switchManager = null;
195 switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
196 if (switchManager == null) {
197 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
199 Status status = switchManager.removeSubnet(subnetName);
200 if (status.isSuccess()) {
201 return Response.status(Response.Status.OK).build();
203 throw new InternalServerErrorException(status.getDescription());
207 * Modify a subnet. For now only changing the port list is allowed.
209 * @param containerName
210 * Name of the Container
212 * Name of the SubnetConfig to be modified
213 * @param subnetConfigData
214 * the {@link SubnetConfig} structure in JSON passed as a POST
216 * @return If the operation is successful or not
218 @Path("/{containerName}/{subnetName}/modify")
220 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
222 @ResponseCode(code = 202, condition = "Operation successful"),
223 @ResponseCode(code = 400, condition = "Invalid request, i.e., requested changing the subnet name"),
224 @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
225 @ResponseCode(code = 500, condition = "Internal server error") })
226 public Response modifySubnet(@PathParam("containerName") String containerName,
227 @PathParam("subnetName") String name,
228 @TypeHint(SubnetConfig.class) JAXBElement<SubnetConfig> subnetConfigData) {
230 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
231 throw new UnauthorizedException("User is not authorized to perform this operation on container "
235 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
237 if (switchManager == null) {
238 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
241 SubnetConfig subnetConf = subnetConfigData.getValue();
242 SubnetConfig existingConf = switchManager.getSubnetConfig(name);
244 boolean successful = true;
246 // make sure that the name matches an existing subnet and we're not
247 // changing the name or subnet IP/mask
248 if (existingConf == null) {
249 // don't have a subnet by that name
250 return Response.status(Response.Status.NOT_FOUND).build();
252 } else if (!existingConf.getName().equals(subnetConf.getName())
253 || !existingConf.getSubnet().equals(subnetConf.getSubnet())) {
254 // can't change the name of a subnet
255 return Response.status(Response.Status.BAD_REQUEST).build();
258 // create a set for fast lookups
259 Set<String> newPorts = new HashSet<String>(subnetConf.getNodePorts());
261 // go through the current ports and (1) remove ports that aren't
262 // there anymore and (2) remove ports that are still there from the
263 // set of ports to add
264 for (String s : existingConf.getNodePorts()) {
265 if (newPorts.contains(s)) {
268 Status st = switchManager.removePortsFromSubnet(name, s);
269 successful = successful && st.isSuccess();
273 // add any remaining ports
274 for (String s : newPorts) {
275 Status st = switchManager.addPortsToSubnet(name, s);
276 successful = successful && st.isSuccess();
281 return Response.status(Response.Status.ACCEPTED).build();
283 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
289 * Add ports to a subnet
291 * @param containerName
292 * Name of the Container
294 * Name of the SubnetConfig to be modified
295 * @param subnetConfigData
296 * the {@link SubnetConfig} structure in JSON passed as a POST
298 * @return If the operation is successful or not
300 @Path("/{containerName}/{subnetName}/add")
302 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
304 @ResponseCode(code = 202, condition = "Operation successful"),
305 @ResponseCode(code = 400, condition = "Invalid request"),
306 @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
307 @ResponseCode(code = 500, condition = "Internal server error") })
308 public Response addNodePorts(
309 @PathParam("containerName") String containerName,
310 @PathParam("subnetName") String name,
311 @TypeHint(SubnetConfig.class) JAXBElement<SubnetConfig> subnetConfigData) {
313 SubnetConfig subnetConf = subnetConfigData.getValue();
314 return addOrDeletePorts(containerName, name, subnetConf, "add");
319 * Delete ports from a subnet
321 * @param containerName
322 * Name of the Container
324 * Name of the SubnetConfig to be modified
325 * @param subnetConfigData
326 * the {@link SubnetConfig} structure in JSON passed as a POST
328 * @return If the operation is successful or not
330 @Path("/{containerName}/{subnetName}/delete")
332 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
334 @ResponseCode(code = 202, condition = "Operation successful"),
335 @ResponseCode(code = 400, condition = "Invalid request"),
336 @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
337 @ResponseCode(code = 500, condition = "Internal server error") })
338 public Response deleteNodePorts(
339 @PathParam("containerName") String containerName,
340 @PathParam("subnetName") String name,
341 @TypeHint(SubnetConfig.class) JAXBElement<SubnetConfig> subnetConfigData) {
343 SubnetConfig subnetConf = subnetConfigData.getValue();
344 return addOrDeletePorts(containerName, name, subnetConf, "delete");
349 * Add/Delete ports to/from a subnet
351 * @param containerName
352 * Name of the Container
354 * Name of the SubnetConfig to be modified
355 * @param subnetConfig
356 * the {@link SubnetConfig} structure
359 * @return If the operation is successful or not
361 private Response addOrDeletePorts(String containerName, String name, SubnetConfig subnetConf, String action) {
363 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
364 throw new UnauthorizedException("User is not authorized to perform this operation on container "
368 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
370 if (switchManager == null) {
371 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
374 SubnetConfig existingConf = switchManager.getSubnetConfig(name);
376 // make sure that the name matches an existing subnet and we're not
377 // changing the name or subnet IP/mask
378 if (existingConf == null) {
379 // don't have a subnet by that name
380 return Response.status(Response.Status.NOT_FOUND).build();
381 } else if (!existingConf.getName().equals(subnetConf.getName())
382 || !existingConf.getSubnet().equals(subnetConf.getSubnet())) {
383 // can't change the name of a subnet
384 return Response.status(Response.Status.BAD_REQUEST).build();
387 boolean successful = true;
388 Set<String> ports = subnetConf.getNodePorts();
390 if (action.equals("add")) {
392 ports.removeAll(existingConf.getNodePorts());
393 for (String port : ports) {
394 st = switchManager.addPortsToSubnet(name, port);
395 successful = successful && st.isSuccess();
397 } else if (action.equals("delete")) {
398 // delete existing ports
399 ports.retainAll(existingConf.getNodePorts());
400 for (String port : ports) {
401 st = switchManager.removePortsFromSubnet(name, port);
402 successful = successful && st.isSuccess();
405 return Response.status(Response.Status.BAD_REQUEST).build();
409 return Response.status(Response.Status.ACCEPTED).build();
411 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();