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.MacAddress;
43 import org.opendaylight.controller.sal.core.Node;
44 import org.opendaylight.controller.sal.core.NodeConnector;
45 import org.opendaylight.controller.sal.core.Property;
46 import org.opendaylight.controller.sal.utils.GlobalConstants;
47 import org.opendaylight.controller.sal.utils.ServiceHelper;
48 import org.opendaylight.controller.sal.utils.Status;
49 import org.opendaylight.controller.switchmanager.ISwitchManager;
52 * The class provides Northbound REST APIs to access the nodes, node connectors
53 * and their properties.
58 public class SwitchNorthbound {
60 private String username;
63 public void setSecurityContext(SecurityContext context) {
64 username = context.getUserPrincipal().getName();
67 protected String getUserName() {
71 private ISwitchManager getIfSwitchManagerService(String containerName) {
72 IContainerManager containerManager = (IContainerManager) ServiceHelper
73 .getGlobalInstance(IContainerManager.class, this);
74 if (containerManager == null) {
75 throw new ServiceUnavailableException("Container "
76 + RestMessages.SERVICEUNAVAILABLE.toString());
79 boolean found = false;
80 List<String> containerNames = containerManager.getContainerNames();
81 for (String cName : containerNames) {
82 if (cName.trim().equalsIgnoreCase(containerName.trim())) {
89 throw new ResourceNotFoundException(containerName + " "
90 + RestMessages.NOCONTAINER.toString());
93 ISwitchManager switchManager = (ISwitchManager) ServiceHelper
94 .getInstance(ISwitchManager.class, containerName, this);
96 if (switchManager == null) {
97 throw new ServiceUnavailableException("Switch Manager "
98 + RestMessages.SERVICEUNAVAILABLE.toString());
101 return switchManager;
106 * Retrieve a list of all the nodes and their properties in the network
108 * @param containerName
109 * The container for which we want to retrieve the list
110 * @return A list of Pair each pair represents a
111 * {@link org.opendaylight.controller.sal.core.Node} and Set of
112 * {@link org.opendaylight.controller.sal.core.Property} attached to
115 @Path("/{containerName}/nodes")
117 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
118 @TypeHint(Nodes.class)
120 @ResponseCode(code = 200, condition = "Operation successful"),
121 @ResponseCode(code = 404, condition = "The containerName is not found"),
122 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
123 public Nodes getNodes(@PathParam("containerName") String containerName) {
125 if (!NorthboundUtils.isAuthorized(
126 getUserName(), containerName, Privilege.READ, this)) {
127 throw new UnauthorizedException(
128 "User is not authorized to perform this operation on container "
132 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
133 if (switchManager == null) {
134 throw new ServiceUnavailableException("Switch Manager "
135 + RestMessages.SERVICEUNAVAILABLE.toString());
138 List<NodeProperties> res = new ArrayList<NodeProperties>();
139 Set<Node> nodes = switchManager.getNodes();
144 byte[] controllerMac = switchManager.getControllerMAC();
145 for (Node node : nodes) {
146 Map<String, Property> propMap = switchManager.getNodeProps(node);
147 if (propMap == null) {
150 Set<Property> props = new HashSet<Property>(propMap.values());
152 byte[] nodeMac = switchManager.getNodeMAC(node);
153 Property macAddr = new MacAddress(controllerMac, nodeMac);
156 NodeProperties nodeProps = new NodeProperties(node, props);
160 return new Nodes(res);
164 * Add a Name/Tier property to a node
166 * @param containerName
167 * Name of the Container
169 * Type of the node being programmed
171 * Node Identifier as specified by
172 * {@link org.opendaylight.controller.sal.core.Node}
174 * Name of the Property specified by
175 * {@link org.opendaylight.controller.sal.core.Property} and its
178 * Value of the Property specified by
179 * {@link org.opendaylight.controller.sal.core.Property} and its
181 * @return Response as dictated by the HTTP Response Status code
184 @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propName}/{propValue}")
186 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
187 @TypeHint(Response.class)
189 @ResponseCode(code = 200, condition = "Operation successful"),
190 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
191 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
192 public Response addNodeProperty(
193 @PathParam("containerName") String containerName,
194 @PathParam("nodeType") String nodeType,
195 @PathParam("nodeId") String nodeId,
196 @PathParam("propName") String propName,
197 @PathParam("propValue") String propValue) {
199 if (!NorthboundUtils.isAuthorized(
200 getUserName(), containerName, Privilege.WRITE, this)) {
201 throw new UnauthorizedException(
202 "User is not authorized to perform this operation on container "
205 handleDefaultDisabled(containerName);
207 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
208 if (switchManager == null) {
209 throw new ServiceUnavailableException("Switch Manager "
210 + RestMessages.SERVICEUNAVAILABLE.toString());
213 handleNodeAvailability(containerName, nodeType, nodeId);
214 Node node = Node.fromString(nodeId);
216 Property prop = switchManager.createProperty(propName, propValue);
218 throw new ResourceNotFoundException(
219 RestMessages.INVALIDDATA.toString());
222 switchManager.setNodeProp(node, prop);
223 return Response.status(Response.Status.CREATED).build();
227 * Delete a property of a node
229 * @param containerName
230 * Name of the Container
232 * Type of the node being programmed
234 * Node Identifier as specified by
235 * {@link org.opendaylight.controller.sal.core.Node}
236 * @param propertyName
237 * Name of the Property specified by
238 * {@link org.opendaylight.controller.sal.core.Property} and its
240 * @return Response as dictated by the HTTP Response Status code
243 @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}")
245 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
247 @ResponseCode(code = 200, condition = "Operation successful"),
248 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
249 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
250 public Response deleteNodeProperty(
251 @PathParam("containerName") String containerName,
252 @PathParam("nodeType") String nodeType,
253 @PathParam("nodeId") String nodeId,
254 @PathParam("propertyName") String propertyName) {
256 if (!NorthboundUtils.isAuthorized(
257 getUserName(), containerName, Privilege.WRITE, this)) {
258 throw new UnauthorizedException(
259 "User is not authorized to perform this operation on container "
262 handleDefaultDisabled(containerName);
264 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
265 if (switchManager == null) {
266 throw new ServiceUnavailableException("Switch Manager "
267 + RestMessages.SERVICEUNAVAILABLE.toString());
270 handleNodeAvailability(containerName, nodeType, nodeId);
271 Node node = Node.fromString(nodeId);
273 Status ret = switchManager.removeNodeProp(node, propertyName);
274 if (ret.isSuccess()) {
275 return Response.ok().build();
277 throw new ResourceNotFoundException(ret.getDescription());
282 * Retrieve a list of all the node connectors and their properties in a
285 * @param containerName
286 * The container for which we want to retrieve the list
288 * Type of the node being programmed
290 * Node Identifier as specified by
291 * {@link org.opendaylight.controller.sal.core.Node}
292 * @return A List of Pair each pair represents a
293 * {@link org.opendaylight.controller.sal.core.NodeConnector} and
295 * {@link org.opendaylight.controller.sal.core.Property} attached to
298 @Path("/{containerName}/node/{nodeType}/{nodeId}")
300 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
301 @TypeHint(NodeConnectors.class)
303 @ResponseCode(code = 200, condition = "Operation successful"),
304 @ResponseCode(code = 404, condition = "The containerName is not found"),
305 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
306 public NodeConnectors getNodeConnectors(
307 @PathParam("containerName") String containerName,
308 @PathParam("nodeType") String nodeType,
309 @PathParam("nodeId") String nodeId) {
311 if (!NorthboundUtils.isAuthorized(
312 getUserName(), containerName, Privilege.READ, this)) {
313 throw new UnauthorizedException(
314 "User is not authorized to perform this operation on container "
318 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
319 if (switchManager == null) {
320 throw new ServiceUnavailableException("Switch Manager "
321 + RestMessages.SERVICEUNAVAILABLE.toString());
324 handleNodeAvailability(containerName, nodeType, nodeId);
325 Node node = Node.fromString(nodeId);
327 List<NodeConnectorProperties> res = new ArrayList<NodeConnectorProperties>();
328 Set<NodeConnector> ncs = switchManager.getNodeConnectors(node);
333 for (NodeConnector nc : ncs) {
334 Map<String, Property> propMap = switchManager
335 .getNodeConnectorProps(nc);
336 if (propMap == null) {
339 Set<Property> props = new HashSet<Property>(propMap.values());
340 NodeConnectorProperties ncProps = new NodeConnectorProperties(nc,
345 return new NodeConnectors(res);
349 * Add a Name/Bandwidth property to a node connector
351 * @param containerName
352 * Name of the Container
354 * Type of the node being programmed
356 * Node Identifier as specified by
357 * {@link org.opendaylight.controller.sal.core.Node}
358 * @param nodeConnectorType
359 * Type of the node connector being programmed
360 * @param nodeConnectorId
361 * NodeConnector Identifier as specified by
362 * {@link org.opendaylight.controller.sal.core.NodeConnector}
364 * Name of the Property specified by
365 * {@link org.opendaylight.controller.sal.core.Property} and its
368 * Value of the Property specified by
369 * {@link org.opendaylight.controller.sal.core.Property} and its
371 * @return Response as dictated by the HTTP Response Status code
374 @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propName}/{propValue}")
376 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
378 @ResponseCode(code = 200, condition = "Operation successful"),
379 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
380 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
381 public Response addNodeConnectorProperty(
382 @PathParam("containerName") String containerName,
383 @PathParam("nodeType") String nodeType,
384 @PathParam("nodeId") String nodeId,
385 @PathParam("nodeConnectorType") String nodeConnectorType,
386 @PathParam("nodeConnectorId") String nodeConnectorId,
387 @PathParam("propName") String propName,
388 @PathParam("propValue") String propValue) {
390 if (!NorthboundUtils.isAuthorized(
391 getUserName(), containerName, Privilege.WRITE, this)) {
392 throw new UnauthorizedException(
393 "User is not authorized to perform this operation on container "
397 handleDefaultDisabled(containerName);
399 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
400 if (switchManager == null) {
401 throw new ServiceUnavailableException("Switch Manager "
402 + RestMessages.SERVICEUNAVAILABLE.toString());
405 handleNodeAvailability(containerName, nodeType, nodeId);
406 Node node = Node.fromString(nodeId);
408 handleNodeConnectorAvailability(containerName, node, nodeConnectorType,
410 NodeConnector nc = NodeConnector
411 .fromStringNoNode(nodeConnectorId, node);
413 Property prop = switchManager.createProperty(propName, propValue);
415 throw new ResourceNotFoundException(
416 RestMessages.INVALIDDATA.toString());
419 Status ret = switchManager.addNodeConnectorProp(nc, prop);
420 if (ret.isSuccess()) {
421 return Response.status(Response.Status.CREATED).build();
423 throw new InternalServerErrorException(ret.getDescription());
427 * Delete a property of a node connector
429 * @param containerName
430 * Name of the Container
432 * Type of the node being programmed
434 * Node Identifier as specified by
435 * {@link org.opendaylight.controller.sal.core.Node}
436 * @param nodeConnectorType
437 * Type of the node connector being programmed
438 * @param nodeConnectorId
439 * NodeConnector Identifier as specified by
440 * {@link org.opendaylight.controller.sal.core.NodeConnector}
441 * @param propertyName
442 * Name of the Property specified by
443 * {@link org.opendaylight.controller.sal.core.Property} and its
445 * @return Response as dictated by the HTTP Response Status code
448 @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}")
450 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
452 @ResponseCode(code = 200, condition = "Operation successful"),
453 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
454 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
455 public Response deleteNodeConnectorProperty(
456 @PathParam("containerName") String containerName,
457 @PathParam("nodeType") String nodeType,
458 @PathParam("nodeId") String nodeId,
459 @PathParam("nodeConnectorType") String nodeConnectorType,
460 @PathParam("nodeConnectorId") String nodeConnectorId,
461 @PathParam("propertyName") String propertyName) {
463 if (!NorthboundUtils.isAuthorized(
464 getUserName(), containerName, Privilege.WRITE, this)) {
465 throw new UnauthorizedException(
466 "User is not authorized to perform this operation on container "
470 handleDefaultDisabled(containerName);
472 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
473 if (switchManager == null) {
474 throw new ServiceUnavailableException("Switch Manager "
475 + RestMessages.SERVICEUNAVAILABLE.toString());
478 handleNodeAvailability(containerName, nodeType, nodeId);
479 Node node = Node.fromString(nodeId);
481 handleNodeConnectorAvailability(containerName, node, nodeConnectorType,
483 NodeConnector nc = NodeConnector
484 .fromStringNoNode(nodeConnectorId, node);
486 Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
487 if (ret.isSuccess()) {
488 return Response.ok().build();
490 throw new ResourceNotFoundException(ret.getDescription());
494 * Retrieve a list of Span ports that were configured previously.
496 * @param containerName
497 * Name of the Container
499 * {@link org.opendaylight.controller.switchmanager.SpanConfig}
503 * @Path("/span-config/{containerName}")
507 * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
511 * @ResponseCode(code = 200, condition = "Operation successful"),
513 * @ResponseCode(code = 404, condition = "The containerName is not found"),
515 * @ResponseCode(code = 503, condition =
516 * "One or more of Controller Services are unavailable") }) public
517 * List<SpanConfig> getSpanConfigList(@PathParam("containerName") String
518 * containerName) { ISwitchManager switchManager = (ISwitchManager)
519 * getIfSwitchManagerService(containerName); if (switchManager == null) {
520 * throw new ServiceUnavailableException("Switch Manager " +
521 * RestMessages.SERVICEUNAVAILABLE.toString()); }
523 * return switchManager.getSpanConfigList(); }
525 * Add a span configuration
527 * @param containerName
528 * Name of the Container
530 * {@link org.opendaylight.controller.switchmanager.SpanConfig}
531 * in JSON or XML format
532 * @return Response as dictated by the HTTP Response Status code
535 * @Path("/span-config/{containerName}")
539 * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
543 * @ResponseCode(code = 200, condition = "Operation successful"),
545 * @ResponseCode(code = 404, condition = "The containerName is not found"),
547 * @ResponseCode(code = 503, condition =
548 * "One or more of Controller Services are unavailable") }) public Response
549 * addSpanConfig(@PathParam("containerName") String containerName,
551 * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
552 * ISwitchManager switchManager = (ISwitchManager)
553 * getIfSwitchManagerService(containerName); if (switchManager == null) {
554 * throw new ServiceUnavailableException("Switch Manager " +
555 * RestMessages.SERVICEUNAVAILABLE.toString()); }
557 * String ret = switchManager.addSpanConfig(config.getValue()); if
558 * (ret.equals(ReturnString.SUCCESS.toString())) { return
559 * Response.status(Response.Status.CREATED).build(); } throw new
560 * InternalServerErrorException(ret); }
562 * Delete a span configuration
564 * @param containerName
565 * Name of the Container
567 * {@link org.opendaylight.controller.switchmanager.SpanConfig}
568 * in JSON or XML format
569 * @return Response as dictated by the HTTP Response Status code
572 * @Path("/span-config/{containerName}")
576 * @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
580 * @ResponseCode(code = 200, condition = "Operation successful"),
582 * @ResponseCode(code = 404, condition = "The containerName is not found"),
584 * @ResponseCode(code = 503, condition =
585 * "One or more of Controller Services are unavailable") }) public Response
586 * deleteSpanConfig(@PathParam("containerName") String containerName,
588 * @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
589 * ISwitchManager switchManager = (ISwitchManager)
590 * getIfSwitchManagerService(containerName); if (switchManager == null) {
591 * throw new ServiceUnavailableException("Switch Manager " +
592 * RestMessages.SERVICEUNAVAILABLE.toString()); }
594 * String ret = switchManager.removeSpanConfig(config.getValue()); if
595 * (ret.equals(ReturnString.SUCCESS.toString())) { return
596 * Response.ok().build(); } throw new ResourceNotFoundException(ret); }
600 * Save the current switch configurations
602 * @param containerName
603 * Name of the Container
604 * @return Response as dictated by the HTTP Response Status code
606 @Path("/{containerName}/switch-config")
608 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
610 @ResponseCode(code = 200, condition = "Operation successful"),
611 @ResponseCode(code = 404, condition = "The containerName is not found"),
612 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
613 public Response saveSwitchConfig(
614 @PathParam("containerName") String containerName) {
616 if (!NorthboundUtils.isAuthorized(
617 getUserName(), containerName, Privilege.WRITE, this)) {
618 throw new UnauthorizedException(
619 "User is not authorized to perform this operation on container "
622 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
623 if (switchManager == null) {
624 throw new ServiceUnavailableException("Switch Manager "
625 + RestMessages.SERVICEUNAVAILABLE.toString());
628 Status ret = switchManager.saveSwitchConfig();
629 if (ret.isSuccess()) {
630 return Response.ok().build();
632 throw new InternalServerErrorException(ret.getDescription());
635 private void handleDefaultDisabled(String containerName) {
636 IContainerManager containerManager = (IContainerManager) ServiceHelper
637 .getGlobalInstance(IContainerManager.class, this);
638 if (containerManager == null) {
639 throw new InternalServerErrorException(
640 RestMessages.INTERNALERROR.toString());
642 if (containerName.equals(GlobalConstants.DEFAULT.toString())
643 && containerManager.hasNonDefaultContainer()) {
644 throw new ResourceConflictException(
645 RestMessages.DEFAULTDISABLED.toString());
649 private Node handleNodeAvailability(String containerName, String nodeType,
652 Node node = Node.fromString(nodeType, nodeId);
654 throw new ResourceNotFoundException(nodeId + " : "
655 + RestMessages.NONODE.toString());
658 ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
659 ISwitchManager.class, containerName, this);
662 throw new ServiceUnavailableException("Switch Manager "
663 + RestMessages.SERVICEUNAVAILABLE.toString());
666 if (!sm.getNodes().contains(node)) {
667 throw new ResourceNotFoundException(node.toString() + " : "
668 + RestMessages.NONODE.toString());
673 private void handleNodeConnectorAvailability(String containerName,
674 Node node, String nodeConnectorType, String nodeConnectorId) {
676 NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType,
677 nodeConnectorId, node);
679 throw new ResourceNotFoundException(nc + " : "
680 + RestMessages.NORESOURCE.toString());
683 ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
684 ISwitchManager.class, containerName, this);
687 throw new ServiceUnavailableException("Switch Manager "
688 + RestMessages.SERVICEUNAVAILABLE.toString());
691 if (!sm.getNodeConnectors(node).contains(nc)) {
692 throw new ResourceNotFoundException(nc.toString() + " : "
693 + RestMessages.NORESOURCE.toString());