Conversion class FromSalConversionsUtils.
[controller.git] / opendaylight / northbound / topology / src / main / java / org / opendaylight / controller / topology / northbound / TopologyNorthboundJAXRS.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.topology.northbound;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15 import java.util.concurrent.ConcurrentMap;
16
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
29 import org.codehaus.enunciate.jaxrs.ResponseCode;
30 import org.codehaus.enunciate.jaxrs.StatusCodes;
31 import org.codehaus.enunciate.jaxrs.TypeHint;
32 import org.opendaylight.controller.northbound.commons.RestMessages;
33 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
34 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
35 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
36 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
37 import org.opendaylight.controller.sal.authorization.Privilege;
38 import org.opendaylight.controller.sal.core.Edge;
39 import org.opendaylight.controller.sal.core.NodeConnector;
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;
45
46 /**
47  * Topology Northbound REST API
48  *
49  * <br>
50  * <br>
51  * Authentication scheme : <b>HTTP Basic</b><br>
52  * Authentication realm : <b>opendaylight</b><br>
53  * Transport : <b>HTTP and HTTPS</b><br>
54  * <br>
55  * HTTPS Authentication is disabled by default.
56  */
57
58 @Path("/")
59 public class TopologyNorthboundJAXRS {
60
61     private String username;
62
63     @Context
64     public void setSecurityContext(SecurityContext context) {
65         if (context != null && context.getUserPrincipal() != null) {
66             username = context.getUserPrincipal().getName();
67         }
68     }
69
70     protected String getUserName() {
71         return username;
72     }
73
74     /**
75      *
76      * Retrieve the Topology
77      *
78      * @param containerName
79      *            The container for which we want to retrieve the topology (Eg.
80      *            'default')
81      *
82      * @return A List of EdgeProps each EdgeProp represent an Edge of the graph
83      *         with the corresponding properties attached to it.
84      *
85      *         <pre>
86      *
87      * Example:
88      *
89      * RequestURL:
90      * http://localhost:8080/controller/nb/v2/topology/default
91      *
92      * Response in XML:
93      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
94      * &lt;topology&gt;
95      *     &lt;edgeProperties&gt;
96      *         &lt;edge&gt;
97      *             &lt;tailNodeConnector&gt;
98      *                 &lt;node&gt;
99      *                     &lt;id&gt;00:00:00:00:00:00:00:02&lt;/id&gt;
100      *                     &lt;type&gt;OF&lt;/type&gt;
101      *                 &lt;/node&gt;
102      *                 &lt;id&gt;2&lt;/id&gt;
103      *                 &lt;type&gt;OF&lt;/type&gt;
104      *             &lt;/tailNodeConnector&gt;
105      *             &lt;headNodeConnector&gt;
106      *                 &lt;node&gt;
107      *                     &lt;id&gt;00:00:00:00:00:00:00:51&lt;/id&gt;
108      *                     &lt;type&gt;OF&lt;/type&gt;
109      *                 &lt;/node&gt;
110      *                 &lt;id&gt;2&lt;/id&gt;
111      *                 &lt;type&gt;OF&lt;/type&gt;
112      *             &lt;/headNodeConnector&gt;
113      *         &lt;/edge&gt;
114      *         &lt;properties&gt;
115      *             &lt;state&gt;
116      *                 &lt;value&gt;1&lt;/value&gt;
117      *             &lt;/state&gt;
118      *             &lt;config&gt;
119      *                 &lt;value&gt;1&lt;/value&gt;
120      *             &lt;/config&gt;
121      *             &lt;name&gt;
122      *                 &lt;value&gt;C1_2-L2_2&lt;/value&gt;
123      *             &lt;/name&gt;
124      *             &lt;timeStamp&gt;
125      *                 &lt;value&gt;1377279422032&lt;/value&gt;
126      *                 &lt;name&gt;creation&lt;/name&gt;
127      *             &lt;/timeStamp&gt;
128      *         &lt;/properties&gt;
129      *     &lt;/edgeProperties&gt;
130      *     &lt;edgeProperties&gt;
131      *         &lt;edge&gt;
132      *             &lt;tailNodeConnector&gt;
133      *                 &lt;node&gt;
134      *                     &lt;id&gt;00:00:00:00:00:00:00:51&lt;/id&gt;
135      *                     &lt;type&gt;OF&lt;/type&gt;
136      *                 &lt;/node&gt;
137      *                 &lt;id&gt;2&lt;/id&gt;
138      *                 &lt;type&gt;OF&lt;/type&gt;
139      *             &lt;/tailNodeConnector&gt;
140      *             &lt;headNodeConnector&gt;
141      *                 &lt;node&gt;
142      *                     &lt;id&gt;00:00:00:00:00:00:00:02&lt;/id&gt;
143      *                     &lt;type&gt;OF&lt;/type&gt;
144      *                 &lt;/node&gt;
145      *                 &lt;id&gt;2&lt;/id&gt;
146      *                 &lt;type&gt;OF&lt;/type&gt;
147      *             &lt;/headNodeConnector&gt;
148      *         &lt;/edge&gt;
149      *         &lt;properties&gt;
150      *             &lt;state&gt;
151      *                 &lt;value&gt;1&lt;/value&gt;
152      *             &lt;/state&gt;
153      *             &lt;name&gt;
154      *                 &lt;value&gt;L2_2-C1_2&lt;/value&gt;
155      *             &lt;/name&gt;
156      *             &lt;config&gt;
157      *                 &lt;value&gt;1&lt;/value&gt;
158      *             &lt;/config&gt;
159      *             &lt;timeStamp&gt;
160      *                 &lt;value&gt;1377279423564&lt;/value&gt;
161      *                 &lt;name&gt;creation&lt;/name&gt;
162      *             &lt;/timeStamp&gt;
163      *         &lt;/properties&gt;
164      *     &lt;/edgeProperties&gt;
165      * &lt;/topology&gt;
166      *
167      * Response in JSON:
168      * {"edgeProperties":[{"edge":{"tailNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:02","type":"OF"},
169      * "id":"2","type":"OF"},"headNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:51","type":"OF"},"id":
170      * "2","type":"OF"}},"properties":{"timeStamp":{"value":"1377278961017","name":"creation"}}},
171      * {"edge":{"tailNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:51","type":"OF"},"id":
172      * "2","type":"OF"}},"headNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:02","type":"OF"},
173      * "id":"2","type":"OF"}},"properties":{"timeStamp":{"value":"1377278961018","name":"creation"}}}]}
174      *
175      * </pre>
176      */
177     @Path("/{containerName}")
178     @GET
179     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
180     @TypeHint(Topology.class)
181     @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
182     public Topology getTopology(@PathParam("containerName") String containerName) {
183
184         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
185             throw new UnauthorizedException("User is not authorized to perform this operation on container "
186                     + containerName);
187         }
188         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
189                 containerName, this);
190         if (topologyManager == null) {
191             throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
192         }
193
194         Map<Edge, Set<Property>> topo = topologyManager.getEdges();
195         if (topo != null) {
196             List<EdgeProperties> res = new ArrayList<EdgeProperties>();
197             for (Map.Entry<Edge, Set<Property>> entry : topo.entrySet()) {
198                 EdgeProperties el = new EdgeProperties(entry.getKey(), entry.getValue());
199                 res.add(el);
200             }
201             return new Topology(res);
202         }
203
204         return null;
205     }
206
207     /**
208      * Retrieve the user configured links
209      *
210      * @param containerName
211      *            The container for which we want to retrieve the user links
212      *            (Eg. 'default')
213      *
214      * @return A List of user configured links
215      *
216      *         <pre>
217      *
218      * Example:
219      *
220      * RequestURL:
221      * http://localhost:8080/controller/nb/v2/topology/default/userLinks
222      *
223      * Response in XML:
224      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
225      * &lt;topologyUserLinks&gt;
226      * &lt;userLinks&gt;
227      * &lt;status&gt;Success&lt;/status&gt;
228      * &lt;name&gt;link1&lt;/name&gt;
229      * &lt;srcNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:02&lt;/srcNodeConnector&gt;
230      * &lt;dstNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:51&lt;/dstNodeConnector&gt;
231      * &lt;/userLinks&gt;
232      * &lt;/topologyUserLinks&gt;
233      *
234      * Response in JSON:
235      * {"userLinks":{"status":"Success","name":"link1","srcNodeConnector":
236      * "OF|2@OF|00:00:00:00:00:00:00:02","dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"}}
237      *
238      * </pre>
239      */
240     @Path("/{containerName}/userLinks")
241     @GET
242     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
243     @TypeHint(TopologyUserLinks.class)
244     @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
245     public TopologyUserLinks getUserLinks(@PathParam("containerName") String containerName) {
246
247         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
248             throw new UnauthorizedException("User is not authorized to perform this operation on container "
249                     + containerName);
250         }
251         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
252                 containerName, this);
253         if (topologyManager == null) {
254             throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
255         }
256
257         ConcurrentMap<String, TopologyUserLinkConfig> userLinks = topologyManager.getUserLinks();
258         if ((userLinks != null) && (userLinks.values() != null)) {
259             List<TopologyUserLinkConfig> res = new ArrayList<TopologyUserLinkConfig>(userLinks.values());
260             return new TopologyUserLinks(res);
261         }
262
263         return null;
264     }
265
266     /**
267      * Add an User Link
268      *
269      * @param containerName
270      *            Name of the Container (Eg. 'default')
271      * @param name
272      *            Name of the user link
273      * @param TopologyUserLinkConfig
274      *            in JSON or XML format
275      * @return Response as dictated by the HTTP Response Status code
276      *
277      *         <pre>
278      *
279      * Example:
280      *
281      * RequestURL:
282      * http://localhost:8080/controller/nb/v2/topology/default/userLink/link1
283      *
284      * Request in XML:
285      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
286      * &lt;topologyUserLinks&gt;
287      * &lt;status&gt;Success&lt;/status&gt;
288      * &lt;name&gt;link1&lt;/name&gt;
289      * &lt;srcNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:02&lt;/srcNodeConnector&gt;
290      * &lt;dstNodeConnector&gt;OF|2@OF|00:00:00:00:00:00:00:51&lt;/dstNodeConnector&gt;
291      * &lt;/topologyUserLinks&gt;
292      *
293      * Request in JSON:
294      * {"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"}
295      *
296      * </pre>
297      */
298     @Path("/{containerName}/userLink/{name}")
299     @PUT
300     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
301     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
302     @StatusCodes({
303         @ResponseCode(code = 201, condition = "User Link added successfully"),
304         @ResponseCode(code = 404, condition = "The Container Name was not found"),
305         @ResponseCode(code = 409, condition = "Failed to add User Link due to Conflicting Name"),
306         @ResponseCode(code = 500, condition = "Failed to add User Link. Failure Reason included in HTTP Error response"),
307         @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
308     public Response addUserLink(@PathParam(value = "containerName") String containerName,
309             @PathParam(value = "name") String name,
310             @TypeHint(TopologyUserLinkConfig.class) TopologyUserLinkConfig userLinkConfig) {
311
312         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
313             throw new UnauthorizedException("User is not authorized to perform this operation on container "
314                     + containerName);
315         }
316         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
317                 containerName, this);
318         if (topologyManager == null) {
319             throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
320         }
321
322         Status status = topologyManager.addUserLink(userLinkConfig);
323         if (status.isSuccess()) {
324             NorthboundUtils
325             .auditlog(
326                     "User Link",username,"added", userLinkConfig.getName() + " from " + NorthboundUtils.getPortName(
327                             NodeConnector.fromString(userLinkConfig.getSrcNodeConnector()),
328                             containerName, this) + " to "
329                             + NorthboundUtils.getPortName(NodeConnector.fromString
330                                     (userLinkConfig.getDstNodeConnector()),containerName, this), containerName);
331             return Response.status(Response.Status.CREATED).build();
332         }
333         throw new InternalServerErrorException(status.getDescription());
334     }
335
336     /**
337      * Delete an User Link
338      *
339      * @param containerName
340      *            Name of the Container (Eg. 'default')
341      * @param name
342      *            Name of the Link Configuration (Eg. 'config1')
343      * @return Response as dictated by the HTTP Response Status code
344      *
345      *         <pre>
346      *
347      * Example:
348      *
349      * RequestURL:
350      * http://localhost:8080/controller/nb/v2/topology/default/userLink/config1
351      *
352      * </pre>
353      */
354     @Path("/{containerName}/userLink/{name}")
355     @DELETE
356     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
357     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
358     @StatusCodes({ @ResponseCode(code = 204, condition = "User link removed successfully"),
359         @ResponseCode(code = 404, condition = "The Container Name or Link Configuration Name was not found"),
360         @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
361     public Response deleteUserLink(@PathParam("containerName") String containerName, @PathParam("name") String name) {
362
363         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
364             throw new UnauthorizedException("User is not authorized to perform this operation on container "
365                     + containerName);
366         }
367         ITopologyManager topologyManager = (ITopologyManager) ServiceHelper.getInstance(ITopologyManager.class,
368                 containerName, this);
369         if (topologyManager == null) {
370             throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString());
371         }
372
373         Status ret = topologyManager.deleteUserLink(name);
374         if (ret.isSuccess()) {
375             NorthboundUtils.auditlog("User Link", username, "removed", name, containerName);
376             return Response.noContent().build();
377         }
378         return NorthboundUtils.getResponse(ret);
379     }
380 }