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.topology.northbound;
11 import java.util.ArrayList;
12 import java.util.List;
15 import java.util.concurrent.ConcurrentMap;
17 import javax.ws.rs.Consumes;
18 import javax.ws.rs.DELETE;
19 import javax.ws.rs.GET;
20 import javax.ws.rs.PUT;
21 import javax.ws.rs.Path;
22 import javax.ws.rs.PathParam;
23 import javax.ws.rs.Produces;
24 import javax.ws.rs.QueryParam;
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;
29 import javax.ws.rs.ext.ContextResolver;
31 import org.codehaus.enunciate.jaxrs.ResponseCode;
32 import org.codehaus.enunciate.jaxrs.StatusCodes;
33 import org.codehaus.enunciate.jaxrs.TypeHint;
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.ResourceNotFoundException;
37 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
38 import org.opendaylight.controller.northbound.commons.query.QueryContext;
39 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
40 import org.opendaylight.controller.sal.authorization.Privilege;
41 import org.opendaylight.controller.sal.core.Edge;
42 import org.opendaylight.controller.sal.core.NodeConnector;
43 import org.opendaylight.controller.sal.core.Property;
44 import org.opendaylight.controller.sal.utils.ServiceHelper;
45 import org.opendaylight.controller.sal.utils.Status;
46 import org.opendaylight.controller.topologymanager.ITopologyManager;
47 import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig;
50 * Topology Northbound REST API
54 * Authentication scheme : <b>HTTP Basic</b><br>
55 * Authentication realm : <b>opendaylight</b><br>
56 * Transport : <b>HTTP and HTTPS</b><br>
58 * HTTPS Authentication is disabled by default.
62 public class TopologyNorthboundJAXRS {
64 private String username;
65 private QueryContext queryContext;
68 public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
69 if (queryCtxResolver != null) {
70 queryContext = queryCtxResolver.getContext(QueryContext.class);
74 public void setSecurityContext(SecurityContext context) {
75 if (context != null && context.getUserPrincipal() != null) {
76 username = context.getUserPrincipal().getName();
80 protected String getUserName() {
86 * Retrieve the Topology
88 * @param containerName
89 * The container for which we want to retrieve the topology (Eg.
92 * @return A List of EdgeProps each EdgeProp represent an Edge of the graph
93 * with the corresponding properties attached to it.
100 * http://localhost:8080/controller/nb/v2/topology/default
102 * Response body in XML:
103 * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
105 * <edgeProperties>
107 * <tailNodeConnector>
109 * <id>00:00:00:00:00:00:00:02</id>
110 * <type>OF</type>
112 * <id>2</id>
113 * <type>OF</type>
114 * </tailNodeConnector>
115 * <headNodeConnector>
117 * <id>00:00:00:00:00:00:00:51</id>
118 * <type>OF</type>
120 * <id>2</id>
121 * <type>OF</type>
122 * </headNodeConnector>
126 * <value>1</value>
129 * <value>1</value>
132 * <value>C1_2-L2_2</value>
135 * <value>1377279422032</value>
136 * <name>creation</name>
138 * </properties>
139 * </edgeProperties>
140 * <edgeProperties>
142 * <tailNodeConnector>
144 * <id>00:00:00:00:00:00:00:51</id>
145 * <type>OF</type>
147 * <id>2</id>
148 * <type>OF</type>
149 * </tailNodeConnector>
150 * <headNodeConnector>
152 * <id>00:00:00:00:00:00:00:02</id>
153 * <type>OF</type>
155 * <id>2</id>
156 * <type>OF</type>
157 * </headNodeConnector>
161 * <value>1</value>
164 * <value>L2_2-C1_2</value>
167 * <value>1</value>
170 * <value>1377279423564</value>
171 * <name>creation</name>
173 * </properties>
174 * </edgeProperties>
177 * Response body in JSON:
182 * "tailNodeConnector":{
184 * "id":"00:00:00:00:00:00:00:02",
190 * "headNodeConnector":{
192 * "id":"00:00:00:00:00:00:00:51",
201 * "value": 1379527162648,
202 * "name": "creation",
214 * "value": 10000000000
220 * "tailNodeConnector":{
222 * "id":"00:00:00:00:00:00:00:51",
228 * "headNodeConnector":{
230 * "id":"00:00:00:00:00:00:00:02",
239 * "value": 1379527162648,
240 * "name": "creation",
248 @Path("/{containerName}")
250 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
251 @TypeHint(Topology.class)
252 @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
253 public Topology getTopology(@PathParam("containerName") String containerName,
254 @QueryParam("_q") String queryString) {
256 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
257 throw new UnauthorizedException("User is not authorized to perform this operation on container "
260 ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
261 containerName, this);
262 if (topologyManager == null) {
263 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
266 Map<Edge, Set<Property>> topo = topologyManager.getEdges();
270 List<EdgeProperties> res = new ArrayList<EdgeProperties>();
271 for (Map.Entry<Edge, Set<Property>> entry : topo.entrySet()) {
272 EdgeProperties el = new EdgeProperties(entry.getKey(), entry.getValue());
275 Topology result = new Topology(res);
277 if (queryString != null) {
278 queryContext.createQuery(queryString, Topology.class)
279 .filter(result, EdgeProperties.class);
285 * Retrieve the user configured links
287 * @param containerName
288 * The container for which we want to retrieve the user links
291 * @return A List of user configured links
298 * http://localhost:8080/controller/nb/v2/topology/default/userLinks
300 * Response body in XML:
301 * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
304 * <status>Success</status>
305 * <name>link1</name>
306 * <srcNodeConnector>OF|2@OF|00:00:00:00:00:00:00:02</srcNodeConnector>
307 * <dstNodeConnector>OF|2@OF|00:00:00:00:00:00:00:51</dstNodeConnector>
311 * Response body in JSON:
315 * "status": "Success",
317 * "srcNodeConnector": "OF|2@OF|00:00:00:00:00:00:00:02",
318 * "dstNodeConnector": "OF|5@OF|00:00:00:00:00:00:00:05"
325 @Path("/{containerName}/userLinks")
327 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
328 @TypeHint(TopologyUserLinks.class)
329 @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
330 public TopologyUserLinks getUserLinks(@PathParam("containerName") String containerName,
331 @QueryParam("_q") String queryString) {
333 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
334 throw new UnauthorizedException("User is not authorized to perform this operation on container "
337 ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
338 containerName, this);
339 if (topologyManager == null) {
340 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
343 ConcurrentMap<String, TopologyUserLinkConfig> userLinks = topologyManager.getUserLinks();
344 if ((userLinks == null) || (userLinks.values() == null)) {
347 TopologyUserLinks result = new TopologyUserLinks(
348 new ArrayList<TopologyUserLinkConfig>(userLinks.values()));
349 if (queryString != null) {
350 queryContext.createQuery(queryString, TopologyUserLinks.class)
351 .filter(result, TopologyUserLinkConfig.class);
359 * @param containerName
360 * Name of the Container (Eg. 'default')
362 * Name of the user link
363 * @param TopologyUserLinkConfig
364 * in JSON or XML format
365 * @return Response as dictated by the HTTP Response Status code
372 * http://localhost:8080/controller/nb/v2/topology/default/userLink/link1
374 * Request body in XML:
375 * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
376 * <topologyUserLinkConfig>
377 * <status>Success</status>
378 * <name>link1</name>
379 * <srcNodeConnector>OF|2@OF|00:00:00:00:00:00:00:02</srcNodeConnector>
380 * <dstNodeConnector>OF|2@OF|00:00:00:00:00:00:00:51</dstNodeConnector>
381 * </topologyUserLinkConfig>
383 * Request body in JSON:
385 * "status":"Success",
387 * "srcNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:02",
388 * "dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"
393 @Path("/{containerName}/userLink/{name}")
395 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
396 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
398 @ResponseCode(code = 201, condition = "User Link added successfully"),
399 @ResponseCode(code = 404, condition = "The Container Name was not found"),
400 @ResponseCode(code = 409, condition = "Failed to add User Link due to Conflicting Name"),
401 @ResponseCode(code = 500, condition = "Failed to add User Link. Failure Reason included in HTTP Error response"),
402 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
403 public Response addUserLink(@PathParam(value = "containerName") String containerName,
404 @PathParam(value = "name") String name,
405 @TypeHint(TopologyUserLinkConfig.class) TopologyUserLinkConfig userLinkConfig) {
407 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
408 throw new UnauthorizedException("User is not authorized to perform this operation on container "
411 ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
412 containerName, this);
413 if (topologyManager == null) {
414 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
417 Status status = topologyManager.addUserLink(userLinkConfig);
418 if (status.isSuccess()) {
421 "User Link",username,"added", userLinkConfig.getName() + " from " + NorthboundUtils.getPortName(
422 NodeConnector.fromString(userLinkConfig.getSrcNodeConnector()),
423 containerName, this) + " to "
424 + NorthboundUtils.getPortName(NodeConnector.fromString
425 (userLinkConfig.getDstNodeConnector()),containerName, this), containerName);
426 return Response.status(Response.Status.CREATED).build();
428 throw new InternalServerErrorException(status.getDescription());
432 * Delete an User Link
434 * @param containerName
435 * Name of the Container (Eg. 'default')
437 * Name of the Link Configuration (Eg. 'config1')
438 * @return Response as dictated by the HTTP Response Status code
445 * http://localhost:8080/controller/nb/v2/topology/default/userLink/config1
449 @Path("/{containerName}/userLink/{name}")
451 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
452 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
453 @StatusCodes({ @ResponseCode(code = 204, condition = "User link removed successfully"),
454 @ResponseCode(code = 404, condition = "The Container Name or Link Configuration Name was not found"),
455 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
456 public Response deleteUserLink(@PathParam("containerName") String containerName, @PathParam("name") String name) {
458 if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
459 throw new UnauthorizedException("User is not authorized to perform this operation on container "
462 ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
463 containerName, this);
464 if (topologyManager == null) {
465 throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
468 Status ret = topologyManager.deleteUserLink(name);
469 if (ret.isSuccess()) {
470 NorthboundUtils.auditlog("User Link", username, "removed", name, containerName);
471 return Response.noContent().build();
473 return NorthboundUtils.getResponse(ret);