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
9 package org.opendaylight.controller.switchmanager.northbound;
11 import java.util.ArrayList;
12 import java.util.HashSet;
13 import java.util.List;
17 import javax.ws.rs.Consumes;
18 import javax.ws.rs.DELETE;
19 import javax.ws.rs.GET;
20 import javax.ws.rs.POST;
21 import javax.ws.rs.PUT;
22 import javax.ws.rs.Path;
23 import javax.ws.rs.PathParam;
24 import javax.ws.rs.Produces;
25 import javax.ws.rs.core.Context;
26 import javax.ws.rs.core.MediaType;
27 import javax.ws.rs.core.Response;
28 import javax.ws.rs.core.SecurityContext;
30 import org.codehaus.enunciate.jaxrs.ResponseCode;
31 import org.codehaus.enunciate.jaxrs.StatusCodes;
32 import org.codehaus.enunciate.jaxrs.TypeHint;
33 import org.opendaylight.controller.containermanager.IContainerManager;
34 import org.opendaylight.controller.northbound.commons.RestMessages;
35 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
36 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
37 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
38 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
39 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
40 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
41 import org.opendaylight.controller.sal.authorization.Privilege;
42 import org.opendaylight.controller.sal.core.Node;
43 import org.opendaylight.controller.sal.core.NodeConnector;
44 import org.opendaylight.controller.sal.core.Property;
45 import org.opendaylight.controller.sal.utils.GlobalConstants;
46 import org.opendaylight.controller.sal.utils.ServiceHelper;
47 import org.opendaylight.controller.sal.utils.Status;
48 import org.opendaylight.controller.switchmanager.ISwitchManager;
51 * The class provides Northbound REST APIs to access the nodes, node connectors
52 * and their properties.
57 public class SwitchNorthbound {
59 private String username;
62 public void setSecurityContext(SecurityContext context) {
63 username = context.getUserPrincipal().getName();
66 protected String getUserName() {
70 private ISwitchManager getIfSwitchManagerService(String containerName) {
71 IContainerManager containerManager = (IContainerManager) ServiceHelper
72 .getGlobalInstance(IContainerManager.class, this);
73 if (containerManager == null) {
74 throw new ServiceUnavailableException("Container "
75 + RestMessages.SERVICEUNAVAILABLE.toString());
78 boolean found = false;
79 List<String> containerNames = containerManager.getContainerNames();
80 for (String cName : containerNames) {
81 if (cName.trim().equalsIgnoreCase(containerName.trim())) {
88 throw new ResourceNotFoundException(containerName + " "
89 + RestMessages.NOCONTAINER.toString());
92 ISwitchManager switchManager = (ISwitchManager) ServiceHelper
93 .getInstance(ISwitchManager.class, containerName, this);
95 if (switchManager == null) {
96 throw new ServiceUnavailableException("Switch Manager "
97 + RestMessages.SERVICEUNAVAILABLE.toString());
100 return switchManager;
105 * Retrieve a list of all the nodes and their properties in the network
107 * @param containerName
108 * The container for which we want to retrieve the list
109 * @return A list of Pair each pair represents a
110 * {@link org.opendaylight.controller.sal.core.Node} and Set of
111 * {@link org.opendaylight.controller.sal.core.Property} attached to
114 @Path("/{containerName}/nodes")
116 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
117 @TypeHint(Nodes.class)
119 @ResponseCode(code = 200, condition = "Operation successful"),
120 @ResponseCode(code = 404, condition = "The containerName is not found"),
121 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
122 public Nodes getNodes(@PathParam("containerName") String containerName) {
124 if (!NorthboundUtils.isAuthorized(
125 getUserName(), containerName, Privilege.READ, this)) {
126 throw new UnauthorizedException(
127 "User is not authorized to perform this operation on container "
131 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
132 if (switchManager == null) {
133 throw new ServiceUnavailableException("Switch Manager "
134 + RestMessages.SERVICEUNAVAILABLE.toString());
137 List<NodeProperties> res = new ArrayList<NodeProperties>();
138 Set<Node> nodes = switchManager.getNodes();
143 for (Node node : nodes) {
144 Map<String, Property> propMap = switchManager.getNodeProps(node);
145 if (propMap == null) {
148 Set<Property> props = new HashSet<Property>(propMap.values());
150 NodeProperties nodeProps = new NodeProperties(node, props);
154 return new Nodes(res);
158 * Add a Name/Tier property to a node
160 * @param containerName
161 * Name of the Container
163 * Type of the node being programmed
165 * Node Identifier as specified by
166 * {@link org.opendaylight.controller.sal.core.Node}
168 * Name of the Property specified by
169 * {@link org.opendaylight.controller.sal.core.Property} and its
172 * Value of the Property specified by
173 * {@link org.opendaylight.controller.sal.core.Property} and its
175 * @return Response as dictated by the HTTP Response Status code
178 @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propName}/{propValue}")
180 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
181 @TypeHint(Response.class)
183 @ResponseCode(code = 200, condition = "Operation successful"),
184 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
185 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
186 public Response addNodeProperty(
187 @PathParam("containerName") String containerName,
188 @PathParam("nodeType") String nodeType,
189 @PathParam("nodeId") String nodeId,
190 @PathParam("propName") String propName,
191 @PathParam("propValue") String propValue) {
193 if (!NorthboundUtils.isAuthorized(
194 getUserName(), containerName, Privilege.WRITE, this)) {
195 throw new UnauthorizedException(
196 "User is not authorized to perform this operation on container "
199 handleDefaultDisabled(containerName);
201 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
202 if (switchManager == null) {
203 throw new ServiceUnavailableException("Switch Manager "
204 + RestMessages.SERVICEUNAVAILABLE.toString());
207 handleNodeAvailability(containerName, nodeType, nodeId);
208 Node node = Node.fromString(nodeType, nodeId);
210 Property prop = switchManager.createProperty(propName, propValue);
212 throw new ResourceNotFoundException(
213 RestMessages.INVALIDDATA.toString());
216 switchManager.setNodeProp(node, prop);
217 return Response.status(Response.Status.CREATED).build();
221 * Delete a property of a node
223 * @param containerName
224 * Name of the Container
226 * Type of the node being programmed
228 * Node Identifier as specified by
229 * {@link org.opendaylight.controller.sal.core.Node}
230 * @param propertyName
231 * Name of the Property specified by
232 * {@link org.opendaylight.controller.sal.core.Property} and its
234 * @return Response as dictated by the HTTP Response Status code
237 @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}")
239 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
241 @ResponseCode(code = 200, condition = "Operation successful"),
242 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
243 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
244 public Response deleteNodeProperty(
245 @PathParam("containerName") String containerName,
246 @PathParam("nodeType") String nodeType,
247 @PathParam("nodeId") String nodeId,
248 @PathParam("propertyName") String propertyName) {
250 if (!NorthboundUtils.isAuthorized(
251 getUserName(), containerName, Privilege.WRITE, this)) {
252 throw new UnauthorizedException(
253 "User is not authorized to perform this operation on container "
256 handleDefaultDisabled(containerName);
258 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
259 if (switchManager == null) {
260 throw new ServiceUnavailableException("Switch Manager "
261 + RestMessages.SERVICEUNAVAILABLE.toString());
264 handleNodeAvailability(containerName, nodeType, nodeId);
265 Node node = Node.fromString(nodeType, nodeId);
266 Status ret = switchManager.removeNodeProp(node, propertyName);
267 if (ret.isSuccess()) {
268 return Response.ok().build();
270 throw new ResourceNotFoundException(ret.getDescription());
275 * Retrieve a list of all the node connectors and their properties in a
278 * @param containerName
279 * The container for which we want to retrieve the list
281 * Type of the node being programmed
283 * Node Identifier as specified by
284 * {@link org.opendaylight.controller.sal.core.Node}
285 * @return A List of Pair each pair represents a
286 * {@link org.opendaylight.controller.sal.core.NodeConnector} and
288 * {@link org.opendaylight.controller.sal.core.Property} attached to
291 @Path("/{containerName}/node/{nodeType}/{nodeId}")
293 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
294 @TypeHint(NodeConnectors.class)
296 @ResponseCode(code = 200, condition = "Operation successful"),
297 @ResponseCode(code = 404, condition = "The containerName is not found"),
298 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
299 public NodeConnectors getNodeConnectors(
300 @PathParam("containerName") String containerName,
301 @PathParam("nodeType") String nodeType,
302 @PathParam("nodeId") String nodeId) {
304 if (!NorthboundUtils.isAuthorized(
305 getUserName(), containerName, Privilege.READ, this)) {
306 throw new UnauthorizedException(
307 "User is not authorized to perform this operation on container "
311 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
312 if (switchManager == null) {
313 throw new ServiceUnavailableException("Switch Manager "
314 + RestMessages.SERVICEUNAVAILABLE.toString());
317 handleNodeAvailability(containerName, nodeType, nodeId);
318 Node node = Node.fromString(nodeType, nodeId);
319 List<NodeConnectorProperties> res = new ArrayList<NodeConnectorProperties>();
320 Set<NodeConnector> ncs = switchManager.getNodeConnectors(node);
325 for (NodeConnector nc : ncs) {
326 Map<String, Property> propMap = switchManager
327 .getNodeConnectorProps(nc);
328 if (propMap == null) {
331 Set<Property> props = new HashSet<Property>(propMap.values());
332 NodeConnectorProperties ncProps = new NodeConnectorProperties(nc,
337 return new NodeConnectors(res);
341 * Add a Name/Bandwidth property to a node connector
343 * @param containerName
344 * Name of the Container
346 * Type of the node being programmed
348 * Node Identifier as specified by
349 * {@link org.opendaylight.controller.sal.core.Node}
350 * @param nodeConnectorType
351 * Type of the node connector being programmed
352 * @param nodeConnectorId
353 * NodeConnector Identifier as specified by
354 * {@link org.opendaylight.controller.sal.core.NodeConnector}
356 * Name of the Property specified by
357 * {@link org.opendaylight.controller.sal.core.Property} and its
360 * Value of the Property specified by
361 * {@link org.opendaylight.controller.sal.core.Property} and its
363 * @return Response as dictated by the HTTP Response Status code
366 @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propName}/{propValue}")
368 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
370 @ResponseCode(code = 200, condition = "Operation successful"),
371 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
372 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
373 public Response addNodeConnectorProperty(
374 @PathParam("containerName") String containerName,
375 @PathParam("nodeType") String nodeType,
376 @PathParam("nodeId") String nodeId,
377 @PathParam("nodeConnectorType") String nodeConnectorType,
378 @PathParam("nodeConnectorId") String nodeConnectorId,
379 @PathParam("propName") String propName,
380 @PathParam("propValue") String propValue) {
382 if (!NorthboundUtils.isAuthorized(
383 getUserName(), containerName, Privilege.WRITE, this)) {
384 throw new UnauthorizedException(
385 "User is not authorized to perform this operation on container "
389 handleDefaultDisabled(containerName);
391 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
392 if (switchManager == null) {
393 throw new ServiceUnavailableException("Switch Manager "
394 + RestMessages.SERVICEUNAVAILABLE.toString());
397 handleNodeAvailability(containerName, nodeType, nodeId);
398 Node node = Node.fromString(nodeType, nodeId);
400 handleNodeConnectorAvailability(containerName, node, nodeConnectorType,
402 NodeConnector nc = NodeConnector
403 .fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
405 Property prop = switchManager.createProperty(propName, propValue);
407 throw new ResourceNotFoundException(
408 RestMessages.INVALIDDATA.toString());
411 Status ret = switchManager.addNodeConnectorProp(nc, prop);
412 if (ret.isSuccess()) {
413 return Response.status(Response.Status.CREATED).build();
415 throw new InternalServerErrorException(ret.getDescription());
419 * Delete a property of a node connector
421 * @param containerName
422 * Name of the Container
424 * Type of the node being programmed
426 * Node Identifier as specified by
427 * {@link org.opendaylight.controller.sal.core.Node}
428 * @param nodeConnectorType
429 * Type of the node connector being programmed
430 * @param nodeConnectorId
431 * NodeConnector Identifier as specified by
432 * {@link org.opendaylight.controller.sal.core.NodeConnector}
433 * @param propertyName
434 * Name of the Property specified by
435 * {@link org.opendaylight.controller.sal.core.Property} and its
437 * @return Response as dictated by the HTTP Response Status code
440 @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}")
442 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
444 @ResponseCode(code = 200, condition = "Operation successful"),
445 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
446 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
447 public Response deleteNodeConnectorProperty(
448 @PathParam("containerName") String containerName,
449 @PathParam("nodeType") String nodeType,
450 @PathParam("nodeId") String nodeId,
451 @PathParam("nodeConnectorType") String nodeConnectorType,
452 @PathParam("nodeConnectorId") String nodeConnectorId,
453 @PathParam("propertyName") String propertyName) {
455 if (!NorthboundUtils.isAuthorized(
456 getUserName(), containerName, Privilege.WRITE, this)) {
457 throw new UnauthorizedException(
458 "User is not authorized to perform this operation on container "
462 handleDefaultDisabled(containerName);
464 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
465 if (switchManager == null) {
466 throw new ServiceUnavailableException("Switch Manager "
467 + RestMessages.SERVICEUNAVAILABLE.toString());
470 handleNodeAvailability(containerName, nodeType, nodeId);
471 Node node = Node.fromString(nodeType, nodeId);
473 handleNodeConnectorAvailability(containerName, node, nodeConnectorType,
475 NodeConnector nc = NodeConnector
476 .fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
477 Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
478 if (ret.isSuccess()) {
479 return Response.ok().build();
481 throw new ResourceNotFoundException(ret.getDescription());
485 * Retrieve a list of Span ports that were configured previously.
487 * @param containerName
488 * Name of the Container
490 * {@link org.opendaylight.controller.switchmanager.SpanConfig}
494 * @Path("/span-config/{containerName}")
498 * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
502 * @ResponseCode(code = 200, condition = "Operation successful"),
504 * @ResponseCode(code = 404, condition = "The containerName is not found"),
506 * @ResponseCode(code = 503, condition =
507 * "One or more of Controller Services are unavailable") }) public
508 * List<SpanConfig> getSpanConfigList(@PathParam("containerName") String
509 * containerName) { ISwitchManager switchManager = (ISwitchManager)
510 * getIfSwitchManagerService(containerName); if (switchManager == null) {
511 * throw new ServiceUnavailableException("Switch Manager " +
512 * RestMessages.SERVICEUNAVAILABLE.toString()); }
514 * return switchManager.getSpanConfigList(); }
516 * Add a span configuration
518 * @param containerName
519 * Name of the Container
521 * {@link org.opendaylight.controller.switchmanager.SpanConfig}
522 * in JSON or XML format
523 * @return Response as dictated by the HTTP Response Status code
526 * @Path("/span-config/{containerName}")
530 * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
534 * @ResponseCode(code = 200, condition = "Operation successful"),
536 * @ResponseCode(code = 404, condition = "The containerName is not found"),
538 * @ResponseCode(code = 503, condition =
539 * "One or more of Controller Services are unavailable") }) public Response
540 * addSpanConfig(@PathParam("containerName") String containerName,
542 * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
543 * ISwitchManager switchManager = (ISwitchManager)
544 * getIfSwitchManagerService(containerName); if (switchManager == null) {
545 * throw new ServiceUnavailableException("Switch Manager " +
546 * RestMessages.SERVICEUNAVAILABLE.toString()); }
548 * String ret = switchManager.addSpanConfig(config.getValue()); if
549 * (ret.equals(ReturnString.SUCCESS.toString())) { return
550 * Response.status(Response.Status.CREATED).build(); } throw new
551 * InternalServerErrorException(ret); }
553 * Delete a span configuration
555 * @param containerName
556 * Name of the Container
558 * {@link org.opendaylight.controller.switchmanager.SpanConfig}
559 * in JSON or XML format
560 * @return Response as dictated by the HTTP Response Status code
563 * @Path("/span-config/{containerName}")
567 * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
571 * @ResponseCode(code = 200, condition = "Operation successful"),
573 * @ResponseCode(code = 404, condition = "The containerName is not found"),
575 * @ResponseCode(code = 503, condition =
576 * "One or more of Controller Services are unavailable") }) public Response
577 * deleteSpanConfig(@PathParam("containerName") String containerName,
579 * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
580 * ISwitchManager switchManager = (ISwitchManager)
581 * getIfSwitchManagerService(containerName); if (switchManager == null) {
582 * throw new ServiceUnavailableException("Switch Manager " +
583 * RestMessages.SERVICEUNAVAILABLE.toString()); }
585 * String ret = switchManager.removeSpanConfig(config.getValue()); if
586 * (ret.equals(ReturnString.SUCCESS.toString())) { return
587 * Response.ok().build(); } throw new ResourceNotFoundException(ret); }
591 * Save the current switch configurations
593 * @param containerName
594 * Name of the Container
595 * @return Response as dictated by the HTTP Response Status code
597 @Path("/{containerName}/switch-config")
599 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
601 @ResponseCode(code = 200, condition = "Operation successful"),
602 @ResponseCode(code = 404, condition = "The containerName is not found"),
603 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
604 public Response saveSwitchConfig(
605 @PathParam("containerName") String containerName) {
607 if (!NorthboundUtils.isAuthorized(
608 getUserName(), containerName, Privilege.WRITE, this)) {
609 throw new UnauthorizedException(
610 "User is not authorized to perform this operation on container "
613 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
614 if (switchManager == null) {
615 throw new ServiceUnavailableException("Switch Manager "
616 + RestMessages.SERVICEUNAVAILABLE.toString());
619 Status ret = switchManager.saveSwitchConfig();
620 if (ret.isSuccess()) {
621 return Response.ok().build();
623 throw new InternalServerErrorException(ret.getDescription());
626 private void handleDefaultDisabled(String containerName) {
627 IContainerManager containerManager = (IContainerManager) ServiceHelper
628 .getGlobalInstance(IContainerManager.class, this);
629 if (containerManager == null) {
630 throw new InternalServerErrorException(
631 RestMessages.INTERNALERROR.toString());
633 if (containerName.equals(GlobalConstants.DEFAULT.toString())
634 && containerManager.hasNonDefaultContainer()) {
635 throw new ResourceConflictException(
636 RestMessages.DEFAULTDISABLED.toString());
640 private Node handleNodeAvailability(String containerName, String nodeType,
643 Node node = Node.fromString(nodeType, nodeId);
645 throw new ResourceNotFoundException(nodeId + " : "
646 + RestMessages.NONODE.toString());
649 ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
650 ISwitchManager.class, containerName, this);
653 throw new ServiceUnavailableException("Switch Manager "
654 + RestMessages.SERVICEUNAVAILABLE.toString());
657 if (!sm.getNodes().contains(node)) {
658 throw new ResourceNotFoundException(node.toString() + " : "
659 + RestMessages.NONODE.toString());
664 private void handleNodeConnectorAvailability(String containerName,
665 Node node, String nodeConnectorType, String nodeConnectorId) {
667 NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType,
668 nodeConnectorId, node);
670 throw new ResourceNotFoundException(nc + " : "
671 + RestMessages.NORESOURCE.toString());
674 ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
675 ISwitchManager.class, containerName, this);
678 throw new ServiceUnavailableException("Switch Manager "
679 + RestMessages.SERVICEUNAVAILABLE.toString());
682 if (!sm.getNodeConnectors(node).contains(nc)) {
683 throw new ResourceNotFoundException(nc.toString() + " : "
684 + RestMessages.NORESOURCE.toString());