blob: 4c9b581ed9baab352ef0351adb3c4e77d3ccab67 [file] [log] [blame]
tom8bb16062014-09-12 14:47:46 -07001package org.onlab.onos.tvue;
2
3import com.fasterxml.jackson.databind.ObjectMapper;
4import com.fasterxml.jackson.databind.node.ArrayNode;
5import com.fasterxml.jackson.databind.node.ObjectNode;
6import org.onlab.onos.net.ConnectPoint;
7import org.onlab.onos.net.ElementId;
8import org.onlab.onos.net.Link;
toma33dd342014-09-12 19:07:40 -07009import org.onlab.onos.net.Path;
tom8bb16062014-09-12 14:47:46 -070010import org.onlab.onos.net.device.DeviceService;
11import org.onlab.onos.net.host.HostService;
12import org.onlab.onos.net.link.LinkService;
13import org.onlab.onos.net.topology.Topology;
14import org.onlab.onos.net.topology.TopologyGraph;
15import org.onlab.onos.net.topology.TopologyService;
16import org.onlab.onos.net.topology.TopologyVertex;
17import org.onlab.rest.BaseResource;
18
19import javax.ws.rs.GET;
tom6a9986b2014-09-12 18:44:52 -070020import javax.ws.rs.PathParam;
tom8bb16062014-09-12 14:47:46 -070021import javax.ws.rs.Produces;
22import javax.ws.rs.core.Response;
23import java.util.HashMap;
24import java.util.HashSet;
25import java.util.Map;
26import java.util.Set;
27
tom6a9986b2014-09-12 18:44:52 -070028import static org.onlab.onos.net.DeviceId.deviceId;
29
tom8bb16062014-09-12 14:47:46 -070030/**
31 * Topology viewer resource.
32 */
tom6a9986b2014-09-12 18:44:52 -070033@javax.ws.rs.Path("topology")
tom8bb16062014-09-12 14:47:46 -070034public class TopologyResource extends BaseResource {
35
tom6a9986b2014-09-12 18:44:52 -070036 @javax.ws.rs.Path("/graph")
tom8bb16062014-09-12 14:47:46 -070037 @GET
38 @Produces("application/json")
39 public Response graph() {
40 ObjectMapper mapper = new ObjectMapper();
41
42 // Fetch the services we'll be using.
43 DeviceService deviceService = get(DeviceService.class);
44 HostService hostService = get(HostService.class);
45 TopologyService topologyService = get(TopologyService.class);
46
47 // Fetch the current topology and its graph that we'll use to render.
48 Topology topo = topologyService.currentTopology();
49 TopologyGraph graph = topologyService.getGraph(topo);
50
51 // Build all interior vertexes, i.e. no end-station hosts yet
52 ArrayNode vertexesNode = mapper.createArrayNode();
53 for (TopologyVertex vertex : graph.getVertexes()) {
54 vertexesNode.add(json(mapper, vertex.deviceId(), 2,
55 deviceService.isAvailable(vertex.deviceId())));
56 }
57
58 // Now scan all links and count number of them between the same devices
59 // using a normalized link key.
60 Map<String, AggLink> linkRecords = aggregateLinks();
61
62 // Now build all interior edges using the aggregated links.
63 ArrayNode edgesNode = mapper.createArrayNode();
64 for (AggLink lr : linkRecords.values()) {
65 edgesNode.add(json(mapper, lr.links.size(), lr.link.src(), lr.link.dst()));
66 }
67
68 // Merge the exterior and interior vertexes and inject host links as
69 // the exterior edges.
70// Iterator<Host> hosts = hostService.getHosts();
71// while (hosts.hasNext()) {
72// Host host = hosts.next();
73// vertexesNode.add(json(mapper, host.id().ip().toString(), 3, true));
74// edgesNode.add(json(mapper, 1, host.ip().toString(),
75// host.location().elementId().uri()));
76// }
77
78 // Now put the vertexes and edges into a root node and ship them off
79 ObjectNode rootNode = mapper.createObjectNode();
80 rootNode.put("vertexes", vertexesNode);
81 rootNode.put("edges", edgesNode);
82 return Response.ok(rootNode.toString()).build();
83 }
84
tom6a9986b2014-09-12 18:44:52 -070085
tom6a9986b2014-09-12 18:44:52 -070086 /**
87 * Returns a JSON array of all paths between the specified hosts.
88 *
89 * @param src source host id
90 * @param dst target host id
91 * @return JSON array of paths
92 */
93 @javax.ws.rs.Path("/paths/{src}/{dst}")
94 @GET
95 @Produces("application/json")
96 public Response paths(@PathParam("src") String src, @PathParam("dst") String dst) {
97 ObjectMapper mapper = new ObjectMapper();
98
tom6a9986b2014-09-12 18:44:52 -070099 TopologyService topologyService = get(TopologyService.class);
toma33dd342014-09-12 19:07:40 -0700100 Topology topology = topologyService.currentTopology();
tom6a9986b2014-09-12 18:44:52 -0700101
102 ArrayNode pathsNode = mapper.createArrayNode();
toma33dd342014-09-12 19:07:40 -0700103 for (Path path : topologyService.getPaths(topology, deviceId(src), deviceId(dst))) {
104 pathsNode.add(json(mapper, path));
105 }
tom6a9986b2014-09-12 18:44:52 -0700106
107 // Now put the vertexes and edges into a root node and ship them off
108 ObjectNode rootNode = mapper.createObjectNode();
toma33dd342014-09-12 19:07:40 -0700109 rootNode.set("paths", pathsNode);
tom6a9986b2014-09-12 18:44:52 -0700110 return Response.ok(rootNode.toString()).build();
111 }
112
tom8bb16062014-09-12 14:47:46 -0700113 // Scan all links and counts number of them between the same devices
114 // using a normalized link key.
115 private Map<String, AggLink> aggregateLinks() {
116 Map<String, AggLink> aggLinks = new HashMap<>();
117 LinkService linkService = get(LinkService.class);
118 for (Link link : linkService.getLinks()) {
119 String key = key(link);
120 AggLink lr = aggLinks.get(key);
121 if (lr == null) {
122 lr = new AggLink(key);
123 aggLinks.put(key, lr);
124 }
125 lr.addLink(link);
126 }
127 return aggLinks;
128 }
129
tom6a9986b2014-09-12 18:44:52 -0700130
tom8bb16062014-09-12 14:47:46 -0700131 // Produces JSON for a graph vertex.
132 private ObjectNode json(ObjectMapper mapper, ElementId id, int group,
133 boolean isOnline) {
134 return mapper.createObjectNode()
toma33dd342014-09-12 19:07:40 -0700135 .put("name", id.uri().toString())
tom8bb16062014-09-12 14:47:46 -0700136 .put("group", group)
137 .put("online", isOnline);
138 }
139
140 // Produces JSON for a graph edge.
141 private ObjectNode json(ObjectMapper mapper, int count,
142 ConnectPoint src, ConnectPoint dst) {
143 return json(mapper, count, id(src), id(dst));
144 }
145
146 // Produces JSON for a graph edge.
147 private ObjectNode json(ObjectMapper mapper, int count, String src, String dst) {
148 return mapper.createObjectNode()
149 .put("source", src).put("target", dst).put("value", count);
150 }
151
toma33dd342014-09-12 19:07:40 -0700152 // Produces JSON representation of a network path.
153 private ArrayNode json(ObjectMapper mapper, Path path) {
154 ArrayNode pathNode = mapper.createArrayNode();
155 for (Link link : path.links()) {
156 ObjectNode linkNode = mapper.createObjectNode()
157 .put("src", id(link.src()))
158 .put("dst", id(link.dst()));
159 pathNode.add(linkNode);
160 }
161 return pathNode;
162 }
163
164
tom8bb16062014-09-12 14:47:46 -0700165 // Aggregate link of all links between the same devices regardless of
166 // their direction.
167 private class AggLink {
168 Link link; // representative links
169
170 final String key;
171 final Set<Link> links = new HashSet<>();
172
173 AggLink(String key) {
174 this.key = key;
175 }
176
177 void addLink(Link link) {
178 links.add(link);
179 if (this.link == null) {
180 this.link = link;
181 }
182 }
183 }
184
185 // Returns a canonical key for the specified link.
186 static String key(Link link) {
187 String s = id(link.src());
188 String d = id(link.dst());
189 return s.compareTo(d) > 0 ? d + s : s + d;
190 }
191
192 // Returns a formatted string for the element associated with the given
193 // connection point.
194 private static String id(ConnectPoint cp) {
toma33dd342014-09-12 19:07:40 -0700195 return cp.elementId().uri().toString();
tom8bb16062014-09-12 14:47:46 -0700196 }
197
198}