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.core.Context;
25 import javax.ws.rs.core.MediaType;
26 import javax.ws.rs.core.Response;
27 import javax.ws.rs.core.SecurityContext;
28 import javax.xml.bind.JAXBElement;
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.northbound.commons.RestMessages;
34 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
35 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
36 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
37 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
38 import org.opendaylight.controller.sal.authorization.Privilege;
39 import org.opendaylight.controller.sal.core.Edge;
40 import org.opendaylight.controller.sal.core.Property;
41 import org.opendaylight.controller.sal.utils.ServiceHelper;
42 import org.opendaylight.controller.sal.utils.Status;
43 import org.opendaylight.controller.topologymanager.ITopologyManager;
44 import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig;
47 * Topology Northbound REST API
51 * Authentication scheme : <b>HTTP Basic</b><br>
52 * Authentication realm : <b>opendaylight</b><br>
53 * Transport : <b>HTTP and HTTPS</b><br>
55 * HTTPS Authentication is disabled by default. Administrator can enable it in
56 * tomcat-server.xml after adding a proper keystore / SSL certificate from a
57 * trusted authority.<br>
59 * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
63 public class TopologyNorthboundJAXRS {
65 private String username;
68 public void setSecurityContext(SecurityContext context) {
69 if (context != null && context.getUserPrincipal() != null) username = context.getUserPrincipal().getName();
72 protected String getUserName() {
78 * Retrieve the Topology
80 * @param containerName
81 * The container for which we want to retrieve the topology (Eg.
84 * @return A List of EdgeProps each EdgeProp represent an Edge of the grap
85 * with the corresponding properties attached to it.
92 * http://localhost:8080/controller/nb/v2/topology/default
95 * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
97 * <edgeProperties>
99 * <tailNodeConnector>
101 * <id>00:00:00:00:00:00:00:02</id>
102 * <type>OF</type>
104 * <id>2</id>
105 * <type>OF</type>
106 * </tailNodeConnector>
107 * <headNodeConnector>
109 * <id>00:00:00:00:00:00:00:51</id>
110 * <type>OF</type>
112 * <id>2</id>
113 * <type>OF</type>
114 * </headNodeConnector>
118 * <value>1</value>
121 * <value>1</value>
124 * <value>C1_2-L2_2</value>
127 * <value>1377279422032</value>
128 * <name>creation</name>
130 * </properties>
131 * </edgeProperties>
132 * <edgeProperties>
134 * <tailNodeConnector>
136 * <id>00:00:00:00:00:00:00:51</id>
137 * <type>OF</type>
139 * <id>2</id>
140 * <type>OF</type>
141 * </tailNodeConnector>
142 * <headNodeConnector>
144 * <id>00:00:00:00:00:00:00:02</id>
145 * <type>OF</type>
147 * <id>2</id>
148 * <type>OF</type>
149 * </headNodeConnector>
153 * <value>1</value>
156 * <value>L2_2-C1_2</value>
159 * <value>1</value>
162 * <value>1377279423564</value>
163 * <name>creation</name>
165 * </properties>
166 * </edgeProperties>
170 * {"edgeProperties":[{"edge":{"tailNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:02","type":"OF"},
171 * "id":"2","type":"OF"},"headNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:51","type":"OF"},"id":
172 * "2","type":"OF"}},"properties":{"timeStamp":{"value":"1377278961017","name":"creation"}}},
173 * {"edge":{"tailNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:51","type":"OF"},"id":
174 * "2","type":"OF"}},"headNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:02","type":"OF"},
175 * "id":"2","type":"OF"}},"properties":{"timeStamp":{"value":"1377278961018","name":"creation"}}}]}
179 @Path("/{containerName}")
181 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
182 @TypeHint(Topology.class)
183 @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
184 public Topology getTopology(@PathParam("containerName") String containerName) {
186 if (!NorthboundUtils.isAuthorized(
187 getUserName(), containerName, Privilege.READ, this)) {
188 throw new UnauthorizedException(
189 "User is not authorized to perform this operation on container "
192 ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
193 .getInstance(ITopologyManager.class, containerName, this);
194 if (topologyManager == null) {
195 throw new ResourceNotFoundException(
196 RestMessages.NOCONTAINER.toString());
199 Map<Edge, Set<Property>> topo = topologyManager.getEdges();
201 List<EdgeProperties> res = new ArrayList<EdgeProperties>();
202 for (Map.Entry<Edge, Set<Property>> entry : topo.entrySet()) {
203 EdgeProperties el = new EdgeProperties(entry.getKey(),
207 return new Topology(res);
214 * Retrieve the user configured links
216 * @param containerName
217 * The container for which we want to retrieve the user links (Eg. 'default')
219 * @return A List of user configured links
226 * http://localhost:8080/controller/nb/v2/topology/default/user-link
229 * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
230 * <topologyUserLinks>
232 * <status>Success</status>
233 * <name>link1</name>
234 * <srcNodeConnector>OF|2@OF|00:00:00:00:00:00:00:02</srcNodeConnector>
235 * <dstNodeConnector>OF|2@OF|00:00:00:00:00:00:00:51</dstNodeConnector>
237 * </topologyUserLinks>
240 * {"userLinks":{"status":"Success","name":"link1","srcNodeConnector":
241 * "OF|2@OF|00:00:00:00:00:00:00:02","dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"}}
245 @Path("/{containerName}/user-link")
247 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
248 @TypeHint(TopologyUserLinks.class)
249 @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
250 public TopologyUserLinks getUserLinks(
251 @PathParam("containerName") String containerName) {
253 if (!NorthboundUtils.isAuthorized(
254 getUserName(), containerName, Privilege.READ, this)) {
255 throw new UnauthorizedException(
256 "User is not authorized to perform this operation on container "
259 ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
260 .getInstance(ITopologyManager.class, containerName, this);
261 if (topologyManager == null) {
262 throw new ResourceNotFoundException(
263 RestMessages.NOCONTAINER.toString());
266 ConcurrentMap<String, TopologyUserLinkConfig> userLinks = topologyManager
268 if ((userLinks != null) && (userLinks.values() != null)) {
269 List<TopologyUserLinkConfig> res = new ArrayList<TopologyUserLinkConfig>(
271 return new TopologyUserLinks(res);
280 * @param containerName
281 * Name of the Container (Eg. 'default')
282 * @param TopologyUserLinkConfig
283 * in JSON or XML format
284 * @return Response as dictated by the HTTP Response Status code
291 * http://localhost:8080/controller/nb/v2/topology/default/user-link
294 * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
295 * <topologyUserLinks>
296 * <status>Success</status>
297 * <name>link1</name>
298 * <srcNodeConnector>OF|2@OF|00:00:00:00:00:00:00:02</srcNodeConnector>
299 * <dstNodeConnector>OF|2@OF|00:00:00:00:00:00:00:51</dstNodeConnector>
300 * </topologyUserLinks>
303 * {"status":"Success","name":"link1","srcNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:02","dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"}
307 @Path("/{containerName}/user-link")
309 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
310 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
312 @ResponseCode(code = 201, condition = "User Link added successfully"),
313 @ResponseCode(code = 404, condition = "The Container Name was not found"),
314 @ResponseCode(code = 409, condition = "Failed to add User Link due to Conflicting Name"),
315 @ResponseCode(code = 500, condition = "Failed to add User Link. Failure Reason included in HTTP Error response"),
316 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
317 public Response addUserLink(
318 @PathParam(value = "containerName") String containerName,
319 @TypeHint(TopologyUserLinkConfig.class) JAXBElement<TopologyUserLinkConfig> userLinkConfig) {
321 if (!NorthboundUtils.isAuthorized(
322 getUserName(), containerName, Privilege.WRITE, this)) {
323 throw new UnauthorizedException(
324 "User is not authorized to perform this operation on container "
327 ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
328 .getInstance(ITopologyManager.class, containerName, this);
329 if (topologyManager == null) {
330 throw new ResourceNotFoundException(
331 RestMessages.NOCONTAINER.toString());
334 Status status = topologyManager.addUserLink(userLinkConfig.getValue());
335 if (status.isSuccess()) {
336 NorthboundUtils.auditlog("User Link", username, "added", userLinkConfig.getValue().getName(), containerName);
337 return Response.status(Response.Status.CREATED).build();
339 throw new InternalServerErrorException(status.getDescription());
343 * Delete an User Link
345 * @param containerName
346 * Name of the Container (Eg. 'default')
348 * Name of the Link Configuration (Eg. 'config1')
349 * @return Response as dictated by the HTTP Response Status code
356 * http://localhost:8080/controller/nb/v2/topology/default/user-link/config1
360 @Path("/{containerName}/user-link/{name}")
362 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
363 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
365 @ResponseCode(code = 200, condition = "Operation successful"),
366 @ResponseCode(code = 404, condition = "The Container Name or Link Configuration Name was not found"),
367 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
368 public Response deleteUserLink(
369 @PathParam("containerName") String containerName,
370 @PathParam("name") String name) {
372 if (!NorthboundUtils.isAuthorized(
373 getUserName(), containerName, Privilege.WRITE, this)) {
374 throw new UnauthorizedException(
375 "User is not authorized to perform this operation on container "
378 ITopologyManager topologyManager = (ITopologyManager) ServiceHelper
379 .getInstance(ITopologyManager.class, containerName, this);
380 if (topologyManager == null) {
381 throw new ResourceNotFoundException(
382 RestMessages.NOCONTAINER.toString());
385 Status ret = topologyManager.deleteUserLink(name);
386 if (ret.isSuccess()) {
387 NorthboundUtils.auditlog("User Link", username, "removed", name, containerName);
388 return Response.ok().build();
390 throw new ResourceNotFoundException(ret.getDescription());