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(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(nodeId);
267 Status ret = switchManager.removeNodeProp(node, propertyName);
268 if (ret.isSuccess()) {
269 return Response.ok().build();
271 throw new ResourceNotFoundException(ret.getDescription());
276 * Retrieve a list of all the node connectors and their properties in a
279 * @param containerName
280 * The container for which we want to retrieve the list
282 * Type of the node being programmed
284 * Node Identifier as specified by
285 * {@link org.opendaylight.controller.sal.core.Node}
286 * @return A List of Pair each pair represents a
287 * {@link org.opendaylight.controller.sal.core.NodeConnector} and
289 * {@link org.opendaylight.controller.sal.core.Property} attached to
292 @Path("/{containerName}/node/{nodeType}/{nodeId}")
294 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
295 @TypeHint(NodeConnectors.class)
297 @ResponseCode(code = 200, condition = "Operation successful"),
298 @ResponseCode(code = 404, condition = "The containerName is not found"),
299 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
300 public NodeConnectors getNodeConnectors(
301 @PathParam("containerName") String containerName,
302 @PathParam("nodeType") String nodeType,
303 @PathParam("nodeId") String nodeId) {
305 if (!NorthboundUtils.isAuthorized(
306 getUserName(), containerName, Privilege.READ, this)) {
307 throw new UnauthorizedException(
308 "User is not authorized to perform this operation on container "
312 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
313 if (switchManager == null) {
314 throw new ServiceUnavailableException("Switch Manager "
315 + RestMessages.SERVICEUNAVAILABLE.toString());
318 handleNodeAvailability(containerName, nodeType, nodeId);
319 Node node = Node.fromString(nodeId);
321 List<NodeConnectorProperties> res = new ArrayList<NodeConnectorProperties>();
322 Set<NodeConnector> ncs = switchManager.getNodeConnectors(node);
327 for (NodeConnector nc : ncs) {
328 Map<String, Property> propMap = switchManager
329 .getNodeConnectorProps(nc);
330 if (propMap == null) {
333 Set<Property> props = new HashSet<Property>(propMap.values());
334 NodeConnectorProperties ncProps = new NodeConnectorProperties(nc,
339 return new NodeConnectors(res);
343 * Add a Name/Bandwidth property to a node connector
345 * @param containerName
346 * Name of the Container
348 * Type of the node being programmed
350 * Node Identifier as specified by
351 * {@link org.opendaylight.controller.sal.core.Node}
352 * @param nodeConnectorType
353 * Type of the node connector being programmed
354 * @param nodeConnectorId
355 * NodeConnector Identifier as specified by
356 * {@link org.opendaylight.controller.sal.core.NodeConnector}
358 * Name of the Property specified by
359 * {@link org.opendaylight.controller.sal.core.Property} and its
362 * Value of the Property specified by
363 * {@link org.opendaylight.controller.sal.core.Property} and its
365 * @return Response as dictated by the HTTP Response Status code
368 @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propName}/{propValue}")
370 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
372 @ResponseCode(code = 200, condition = "Operation successful"),
373 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
374 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
375 public Response addNodeConnectorProperty(
376 @PathParam("containerName") String containerName,
377 @PathParam("nodeType") String nodeType,
378 @PathParam("nodeId") String nodeId,
379 @PathParam("nodeConnectorType") String nodeConnectorType,
380 @PathParam("nodeConnectorId") String nodeConnectorId,
381 @PathParam("propName") String propName,
382 @PathParam("propValue") String propValue) {
384 if (!NorthboundUtils.isAuthorized(
385 getUserName(), containerName, Privilege.WRITE, this)) {
386 throw new UnauthorizedException(
387 "User is not authorized to perform this operation on container "
391 handleDefaultDisabled(containerName);
393 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
394 if (switchManager == null) {
395 throw new ServiceUnavailableException("Switch Manager "
396 + RestMessages.SERVICEUNAVAILABLE.toString());
399 handleNodeAvailability(containerName, nodeType, nodeId);
400 Node node = Node.fromString(nodeId);
402 handleNodeConnectorAvailability(containerName, node, nodeConnectorType,
404 NodeConnector nc = NodeConnector
405 .fromStringNoNode(nodeConnectorId, node);
407 Property prop = switchManager.createProperty(propName, propValue);
409 throw new ResourceNotFoundException(
410 RestMessages.INVALIDDATA.toString());
413 Status ret = switchManager.addNodeConnectorProp(nc, prop);
414 if (ret.isSuccess()) {
415 return Response.status(Response.Status.CREATED).build();
417 throw new InternalServerErrorException(ret.getDescription());
421 * Delete a property of a node connector
423 * @param containerName
424 * Name of the Container
426 * Type of the node being programmed
428 * Node Identifier as specified by
429 * {@link org.opendaylight.controller.sal.core.Node}
430 * @param nodeConnectorType
431 * Type of the node connector being programmed
432 * @param nodeConnectorId
433 * NodeConnector Identifier as specified by
434 * {@link org.opendaylight.controller.sal.core.NodeConnector}
435 * @param propertyName
436 * Name of the Property specified by
437 * {@link org.opendaylight.controller.sal.core.Property} and its
439 * @return Response as dictated by the HTTP Response Status code
442 @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}")
444 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
446 @ResponseCode(code = 200, condition = "Operation successful"),
447 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
448 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
449 public Response deleteNodeConnectorProperty(
450 @PathParam("containerName") String containerName,
451 @PathParam("nodeType") String nodeType,
452 @PathParam("nodeId") String nodeId,
453 @PathParam("nodeConnectorType") String nodeConnectorType,
454 @PathParam("nodeConnectorId") String nodeConnectorId,
455 @PathParam("propertyName") String propertyName) {
457 if (!NorthboundUtils.isAuthorized(
458 getUserName(), containerName, Privilege.WRITE, this)) {
459 throw new UnauthorizedException(
460 "User is not authorized to perform this operation on container "
464 handleDefaultDisabled(containerName);
466 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
467 if (switchManager == null) {
468 throw new ServiceUnavailableException("Switch Manager "
469 + RestMessages.SERVICEUNAVAILABLE.toString());
472 handleNodeAvailability(containerName, nodeType, nodeId);
473 Node node = Node.fromString(nodeId);
475 handleNodeConnectorAvailability(containerName, node, nodeConnectorType,
477 NodeConnector nc = NodeConnector
478 .fromStringNoNode(nodeConnectorId, node);
480 Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
481 if (ret.isSuccess()) {
482 return Response.ok().build();
484 throw new ResourceNotFoundException(ret.getDescription());
488 * Retrieve a list of Span ports that were configured previously.
490 * @param containerName
491 * Name of the Container
493 * {@link org.opendaylight.controller.switchmanager.SpanConfig}
497 * @Path("/span-config/{containerName}")
501 * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
505 * @ResponseCode(code = 200, condition = "Operation successful"),
507 * @ResponseCode(code = 404, condition = "The containerName is not found"),
509 * @ResponseCode(code = 503, condition =
510 * "One or more of Controller Services are unavailable") }) public
511 * List<SpanConfig> getSpanConfigList(@PathParam("containerName") String
512 * containerName) { ISwitchManager switchManager = (ISwitchManager)
513 * getIfSwitchManagerService(containerName); if (switchManager == null) {
514 * throw new ServiceUnavailableException("Switch Manager " +
515 * RestMessages.SERVICEUNAVAILABLE.toString()); }
517 * return switchManager.getSpanConfigList(); }
519 * Add a span configuration
521 * @param containerName
522 * Name of the Container
524 * {@link org.opendaylight.controller.switchmanager.SpanConfig}
525 * in JSON or XML format
526 * @return Response as dictated by the HTTP Response Status code
529 * @Path("/span-config/{containerName}")
533 * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
537 * @ResponseCode(code = 200, condition = "Operation successful"),
539 * @ResponseCode(code = 404, condition = "The containerName is not found"),
541 * @ResponseCode(code = 503, condition =
542 * "One or more of Controller Services are unavailable") }) public Response
543 * addSpanConfig(@PathParam("containerName") String containerName,
545 * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
546 * ISwitchManager switchManager = (ISwitchManager)
547 * getIfSwitchManagerService(containerName); if (switchManager == null) {
548 * throw new ServiceUnavailableException("Switch Manager " +
549 * RestMessages.SERVICEUNAVAILABLE.toString()); }
551 * String ret = switchManager.addSpanConfig(config.getValue()); if
552 * (ret.equals(ReturnString.SUCCESS.toString())) { return
553 * Response.status(Response.Status.CREATED).build(); } throw new
554 * InternalServerErrorException(ret); }
556 * Delete a span configuration
558 * @param containerName
559 * Name of the Container
561 * {@link org.opendaylight.controller.switchmanager.SpanConfig}
562 * in JSON or XML format
563 * @return Response as dictated by the HTTP Response Status code
566 * @Path("/span-config/{containerName}")
570 * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
574 * @ResponseCode(code = 200, condition = "Operation successful"),
576 * @ResponseCode(code = 404, condition = "The containerName is not found"),
578 * @ResponseCode(code = 503, condition =
579 * "One or more of Controller Services are unavailable") }) public Response
580 * deleteSpanConfig(@PathParam("containerName") String containerName,
582 * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
583 * ISwitchManager switchManager = (ISwitchManager)
584 * getIfSwitchManagerService(containerName); if (switchManager == null) {
585 * throw new ServiceUnavailableException("Switch Manager " +
586 * RestMessages.SERVICEUNAVAILABLE.toString()); }
588 * String ret = switchManager.removeSpanConfig(config.getValue()); if
589 * (ret.equals(ReturnString.SUCCESS.toString())) { return
590 * Response.ok().build(); } throw new ResourceNotFoundException(ret); }
594 * Save the current switch configurations
596 * @param containerName
597 * Name of the Container
598 * @return Response as dictated by the HTTP Response Status code
600 @Path("/{containerName}/switch-config")
602 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
604 @ResponseCode(code = 200, condition = "Operation successful"),
605 @ResponseCode(code = 404, condition = "The containerName is not found"),
606 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
607 public Response saveSwitchConfig(
608 @PathParam("containerName") String containerName) {
610 if (!NorthboundUtils.isAuthorized(
611 getUserName(), containerName, Privilege.WRITE, this)) {
612 throw new UnauthorizedException(
613 "User is not authorized to perform this operation on container "
616 ISwitchManager switchManager = getIfSwitchManagerService(containerName);
617 if (switchManager == null) {
618 throw new ServiceUnavailableException("Switch Manager "
619 + RestMessages.SERVICEUNAVAILABLE.toString());
622 Status ret = switchManager.saveSwitchConfig();
623 if (ret.isSuccess()) {
624 return Response.ok().build();
626 throw new InternalServerErrorException(ret.getDescription());
629 private void handleDefaultDisabled(String containerName) {
630 IContainerManager containerManager = (IContainerManager) ServiceHelper
631 .getGlobalInstance(IContainerManager.class, this);
632 if (containerManager == null) {
633 throw new InternalServerErrorException(
634 RestMessages.INTERNALERROR.toString());
636 if (containerName.equals(GlobalConstants.DEFAULT.toString())
637 && containerManager.hasNonDefaultContainer()) {
638 throw new ResourceConflictException(
639 RestMessages.DEFAULTDISABLED.toString());
643 private Node handleNodeAvailability(String containerName, String nodeType,
646 Node node = Node.fromString(nodeType, nodeId);
648 throw new ResourceNotFoundException(nodeId + " : "
649 + RestMessages.NONODE.toString());
652 ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
653 ISwitchManager.class, containerName, this);
656 throw new ServiceUnavailableException("Switch Manager "
657 + RestMessages.SERVICEUNAVAILABLE.toString());
660 if (!sm.getNodes().contains(node)) {
661 throw new ResourceNotFoundException(node.toString() + " : "
662 + RestMessages.NONODE.toString());
667 private void handleNodeConnectorAvailability(String containerName,
668 Node node, String nodeConnectorType, String nodeConnectorId) {
670 NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType,
671 nodeConnectorId, node);
673 throw new ResourceNotFoundException(nc + " : "
674 + RestMessages.NORESOURCE.toString());
677 ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
678 ISwitchManager.class, containerName, this);
681 throw new ServiceUnavailableException("Switch Manager "
682 + RestMessages.SERVICEUNAVAILABLE.toString());
685 if (!sm.getNodeConnectors(node).contains(nc)) {
686 throw new ResourceNotFoundException(nc.toString() + " : "
687 + RestMessages.NORESOURCE.toString());