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;
11 import java.util.List;
14 import javax.ws.rs.Consumes;
15 import javax.ws.rs.DELETE;
16 import javax.ws.rs.GET;
17 import javax.ws.rs.POST;
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.core.Context;
23 import javax.ws.rs.core.MediaType;
24 import javax.ws.rs.core.Response;
25 import javax.ws.rs.core.SecurityContext;
26 import javax.ws.rs.core.UriInfo;
28 import org.codehaus.enunciate.jaxrs.ResponseCode;
29 import org.codehaus.enunciate.jaxrs.StatusCodes;
30 import org.codehaus.enunciate.jaxrs.TypeHint;
31 import org.opendaylight.controller.containermanager.IContainerManager;
32 import org.opendaylight.controller.northbound.commons.RestMessages;
33 import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
34 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
35 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
36 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
37 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
38 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
39 import org.opendaylight.controller.sal.authorization.Privilege;
40 import org.opendaylight.controller.sal.core.NodeConnector;
41 import org.opendaylight.controller.sal.utils.ServiceHelper;
42 import org.opendaylight.controller.sal.utils.Status;
43 import org.opendaylight.controller.switchmanager.ISwitchManager;
44 import org.opendaylight.controller.switchmanager.SubnetConfig;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
49 * This class provides REST APIs to manage subnets.
53 * Authentication scheme : <b>HTTP Basic</b><br>
54 * Authentication realm : <b>opendaylight</b><br>
55 * Transport : <b>HTTP and HTTPS</b><br>
57 * HTTPS Authentication is disabled by default.
62 public class SubnetsNorthbound {
63 protected static final Logger logger = LoggerFactory.getLogger(SubnetsNorthbound.class);
65 private String username;
68 public void setSecurityContext(SecurityContext context) {
69 if (context != null && context.getUserPrincipal() != null) {
70 username = context.getUserPrincipal().getName();
74 protected String getUserName() {
78 private void handleContainerDoesNotExist(String containerName) {
79 IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance(
80 IContainerManager.class, this);
81 if (containerManager == null) {
82 throw new ServiceUnavailableException("Container " + RestMessages.NOCONTAINER.toString());
85 List<String> containerNames = containerManager.getContainerNames();
86 for (String cName : containerNames) {
87 if (cName.trim().equalsIgnoreCase(containerName.trim())) {
92 throw new ResourceNotFoundException(containerName + " " + RestMessages.NOCONTAINER.toString());
95 private void handleNameMismatch(String name, String nameinURL) {
96 if (name == null || nameinURL == null) {
97 throw new BadRequestException(RestMessages.INVALIDDATA.toString() + " : Name is null");
100 if (name.equals(nameinURL)) {
103 throw new ResourceConflictException(RestMessages.INVALIDDATA.toString()
104 + " : Name in URL does not match the name in request body");
108 * List all the subnets in a given container
110 * @param containerName
111 * container in which we want to query the subnets
113 * @return a List of SubnetConfig
118 * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnets
121 * <subnetConfig>
122 * <name>marketingdepartment</name>
123 * <subnet>30.31.54.254/24</subnet>
124 * </subnetConfig>
125 * <subnetConfig>
126 * <name>salesdepartment</name>
127 * <subnet>20.18.1.254/16</subnet>
128 * <nodeConnectors>0F|11@OF|00:00:00:aa:bb:cc:dd:ee>/nodeConnectors>
129 * <nodeConnectors>0F|13@OF|00:00:00:aa:bb:cc:dd:ee>/nodeConnectors>
130 * </subnetConfig>
134 * "name":"marketingdepartment",
135 * "subnet":"30.31.54.254/24",
138 * "name":"salesdepartment",
139 * "subnet":"20.18.1.254/16",
140 * "nodeConnectors":["0F|11@OF|00:00:00:aa:bb:cc:dd:ee", "0F|13@OF|00:00:00:aa:bb:cc:dd:ee"]
144 @Path("/{containerName}/subnets")
146 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
147 @StatusCodes({ @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
148 @ResponseCode(code = 404, condition = "The containerName passed was not found"),
149 @ResponseCode(code = 503, condition = "Service unavailable") })
150 @TypeHint(SubnetConfigs.class)
151 public SubnetConfigs listSubnets(@PathParam("containerName") String containerName) {
153 handleContainerDoesNotExist(containerName);
154 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
155 throw new UnauthorizedException("User is not authorized to perform this operation on container "
158 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
160 if (switchManager == null) {
161 throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
163 return new SubnetConfigs(switchManager.getSubnetsConfigList());
167 * List the configuration of a subnet in a given container
169 * @param containerName
170 * container in which we want to query the subnet
172 * of the subnet being queried
174 * @return SubnetConfig
179 * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/marketingdepartment
182 * <subnetConfig>
183 * <name>marketingdepartment</name>
184 * <subnet>30.0.0.1/24</subnet>
185 * <nodeConnectors>0F|1@OF|00:00:11:22:33:44:55:66>/nodePorts>
186 * <nodeConnectors>0F|3@OF|00:00:11:22:33:44:55:66>/nodePorts>
187 * </subnetConfig>
191 * "name":"marketingdepartment",
192 * "subnet":"30.0.0.1/24",
193 * "nodeConnectors":["0F|1@OF|00:00:11:22:33:44:55:66", "0F|3@OF|00:00:11:22:33:44:55:66"]
197 @Path("/{containerName}/subnet/{subnetName}")
199 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
200 @StatusCodes({ @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
201 @ResponseCode(code = 404, condition = "The containerName or subnetName passed was not found"),
202 @ResponseCode(code = 503, condition = "Service unavailable") })
203 @TypeHint(SubnetConfig.class)
204 public SubnetConfig listSubnet(@PathParam("containerName") String containerName,
205 @PathParam("subnetName") String subnetName) {
207 handleContainerDoesNotExist(containerName);
209 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
210 throw new UnauthorizedException("User is not authorized to perform this operation on container "
213 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
215 if (switchManager == null) {
216 throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
218 SubnetConfig res = switchManager.getSubnetConfig(subnetName);
220 throw new ResourceNotFoundException(RestMessages.NOSUBNET.toString());
226 * Add a subnet into the specified container context, node connectors are
229 * @param containerName
230 * name of the container context in which the subnet needs to be
233 * name of new subnet to be added
234 * @param subnetConfigData
235 * the {@link SubnetConfig} structure in request body
237 * @return Response as dictated by the HTTP Response Status code
242 * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/salesdepartment
245 * <subnetConfig>
246 * <name>salesdepartment</name>
247 * <subnet>172.173.174.254/24</subnet>
248 * <nodeConnectors>0F|22@OF|00:00:11:22:33:44:55:66>/nodeConnectors>
249 * <nodeConnectors>0F|39@OF|00:00:ab:cd:33:44:55:66>/nodeConnectors>
250 * </subnetConfig>
254 * "name":"salesdepartment",
255 * "subnet":"172.173.174.254/24"
256 * "nodeConnectors":["0F|22@OF|00:00:11:22:33:44:55:66", "0F|39@OF|00:00:ab:cd:33:44:55:66"]
261 @Path("/{containerName}/subnet/{subnetName}")
263 @StatusCodes({ @ResponseCode(code = 201, condition = "Subnet created successfully"),
264 @ResponseCode(code = 400, condition = "Invalid data passed"),
265 @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
266 @ResponseCode(code = 409, condition = "Subnet name in url conflicts with name in request body"),
267 @ResponseCode(code = 404, condition = "Container name passed was not found or subnet config is null"),
268 @ResponseCode(code = 500, condition = "Internal Server Error: Addition of subnet failed"),
269 @ResponseCode(code = 503, condition = "Service unavailable") })
270 public Response addSubnet(@PathParam("containerName") String containerName,
271 @PathParam("subnetName") String subnetName, @TypeHint(SubnetConfig.class) SubnetConfig subnetConfigData) {
273 handleContainerDoesNotExist(containerName);
275 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
276 throw new UnauthorizedException("User is not authorized to perform this operation on container "
279 SubnetConfig cfgObject = subnetConfigData;
280 handleNameMismatch(cfgObject.getName(), subnetName);
282 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
284 if (switchManager == null) {
285 throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
287 Status status = switchManager.addSubnet(cfgObject);
288 if (status.isSuccess()) {
289 NorthboundUtils.auditlog("Subnet Gateway", username, "added", subnetName, containerName);
290 if (subnetConfigData.getNodeConnectors() != null) {
291 for (NodeConnector port : subnetConfigData.getNodeConnectors()) {
292 NorthboundUtils.auditlog("Port", getUserName(), "added",
293 NorthboundUtils.getPortName(port, switchManager) + " to Subnet Gateway " + subnetName,
297 return Response.status(Response.Status.CREATED).build();
299 return NorthboundUtils.getResponse(status);
303 * Delete a subnet from the specified container context
305 * @param containerName
306 * name of the container in which subnet needs to be removed
308 * name of new subnet to be deleted
309 * @return Response as dictated by the HTTP Response Status code
313 * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/engdepartment
317 @Path("/{containerName}/subnet/{subnetName}")
319 @StatusCodes({ @ResponseCode(code = 204, condition = "No Content"),
320 @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
321 @ResponseCode(code = 404, condition = "The containerName passed was not found"),
322 @ResponseCode(code = 500, condition = "Internal Server Error : Removal of subnet failed"),
323 @ResponseCode(code = 503, condition = "Service unavailable") })
324 public Response removeSubnet(@PathParam("containerName") String containerName,
325 @PathParam("subnetName") String subnetName) {
327 handleContainerDoesNotExist(containerName);
329 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
330 throw new UnauthorizedException("User is not authorized to perform this operation on container "
334 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
336 if (switchManager == null) {
337 throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
339 Status status = switchManager.removeSubnet(subnetName);
340 if (status.isSuccess()) {
341 NorthboundUtils.auditlog("Subnet Gateway", username, "removed", subnetName, containerName);
342 return Response.status(Response.Status.NO_CONTENT).build();
344 return NorthboundUtils.getResponse(status);
348 * Modify a subnet. Replace the existing subnet with the new specified one.
349 * For now only port list modification is allowed. If the respective subnet
350 * configuration does not exist this call is equivalent to a subnet
353 * @param containerName
354 * Name of the Container context
356 * Name of the subnet to be modified
357 * @param subnetConfigData
358 * the {@link SubnetConfig} structure in request body parameter
359 * @return Response as dictated by the HTTP Response Status code
364 * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/salesdepartment
367 * <subnetConfig>
368 * <name>salesdepartment</name>
369 * <subnet>172.173.174.254/24</subnet>
370 * <nodeConnectors>0F|22@OF|00:00:11:22:33:44:55:66>/nodeConnectors>
371 * <nodeConnectors>0F|39@OF|00:00:ab:cd:33:44:55:66>/nodeConnectors>
372 * </subnetConfig>
376 * "name":"salesdepartment",
377 * "subnet":"172.173.174.254/24"
378 * "nodeConnectors":["0F|22@OF|00:00:11:22:33:44:55:66", "0F|39@OF|00:00:ab:cd:33:44:55:66"]
382 @Path("/{containerName}/subnet/{subnetName}")
384 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
385 @StatusCodes({ @ResponseCode(code = 200, condition = "Configuration replaced successfully"),
386 @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
387 @ResponseCode(code = 409, condition = "Subnet name in url conflicts with name in request body"),
388 @ResponseCode(code = 404, condition = "The containerName or subnetName is not found"),
389 @ResponseCode(code = 500, condition = "Internal server error: Modify subnet failed"),
390 @ResponseCode(code = 503, condition = "Service unavailable") })
391 public Response modifySubnet(@Context UriInfo uriInfo, @PathParam("containerName") String containerName,
392 @PathParam("subnetName") String subnetName, @TypeHint(SubnetConfig.class) SubnetConfig subnetConfigData) {
394 handleContainerDoesNotExist(containerName);
396 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
397 throw new UnauthorizedException("User is not authorized to perform this operation on container "
400 handleNameMismatch(subnetConfigData.getName(), subnetName);
402 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
404 if (switchManager == null) {
405 throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
408 // Need to check this until Status does not return a CREATED status code
409 SubnetConfig existingConf = switchManager.getSubnetConfig(subnetName);
411 Status status = switchManager.modifySubnet(subnetConfigData);
413 if (status.isSuccess()) {
414 if (existingConf == null) {
415 NorthboundUtils.auditlog("Subnet Gateway", username, "added", subnetName, containerName);
416 if (subnetConfigData.getNodeConnectors() != null) {
417 for (NodeConnector port : subnetConfigData.getNodeConnectors()) {
418 NorthboundUtils.auditlog("Port", getUserName(), "added",
419 NorthboundUtils.getPortName(port, switchManager) + " to Subnet Gateway" + subnetName,
423 return Response.created(uriInfo.getRequestUri()).build();
425 Set<NodeConnector> existingNCList = existingConf.getNodeConnectors();
427 if (existingNCList == null) {
428 existingNCList = new HashSet<NodeConnector>(0);
430 if (subnetConfigData.getNodeConnectors() != null) {
431 for (NodeConnector port : subnetConfigData.getNodeConnectors()) {
432 if (!existingNCList.contains(port)) {
433 NorthboundUtils.auditlog("Port", getUserName(), "added",
434 NorthboundUtils.getPortName(port, switchManager) + " to Subnet Gateway "
435 + subnetName, containerName);
439 for (NodeConnector port : existingNCList) {
440 if (!subnetConfigData.getNodeConnectors().contains(port)) {
442 .auditlog("Port", getUserName(), "removed",
443 NorthboundUtils.getPortName(port, switchManager) + " from Subnet Gateway "
444 + subnetName, containerName);
449 return NorthboundUtils.getResponse(status);