blob: 992bbb3eeea21e122ed9007b10836505e385656e [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;
tom025e09f2014-09-15 15:29:24 -07008import org.onlab.onos.net.Host;
tom8bb16062014-09-12 14:47:46 -07009import org.onlab.onos.net.Link;
toma33dd342014-09-12 19:07:40 -070010import org.onlab.onos.net.Path;
tom8bb16062014-09-12 14:47:46 -070011import org.onlab.onos.net.device.DeviceService;
12import org.onlab.onos.net.host.HostService;
13import org.onlab.onos.net.link.LinkService;
14import org.onlab.onos.net.topology.Topology;
15import org.onlab.onos.net.topology.TopologyGraph;
16import org.onlab.onos.net.topology.TopologyService;
17import org.onlab.onos.net.topology.TopologyVertex;
18import org.onlab.rest.BaseResource;
19
20import javax.ws.rs.GET;
tom6a9986b2014-09-12 18:44:52 -070021import javax.ws.rs.PathParam;
tom8bb16062014-09-12 14:47:46 -070022import javax.ws.rs.Produces;
23import javax.ws.rs.core.Response;
24import java.util.HashMap;
25import java.util.HashSet;
26import java.util.Map;
27import java.util.Set;
28
tom6a9986b2014-09-12 18:44:52 -070029import static org.onlab.onos.net.DeviceId.deviceId;
tom025e09f2014-09-15 15:29:24 -070030import static org.onlab.onos.net.PortNumber.portNumber;
tom6a9986b2014-09-12 18:44:52 -070031
tom8bb16062014-09-12 14:47:46 -070032/**
33 * Topology viewer resource.
34 */
tom6a9986b2014-09-12 18:44:52 -070035@javax.ws.rs.Path("topology")
tom8bb16062014-09-12 14:47:46 -070036public class TopologyResource extends BaseResource {
37
tom6a9986b2014-09-12 18:44:52 -070038 @javax.ws.rs.Path("/graph")
tom8bb16062014-09-12 14:47:46 -070039 @GET
40 @Produces("application/json")
41 public Response graph() {
42 ObjectMapper mapper = new ObjectMapper();
43
44 // Fetch the services we'll be using.
45 DeviceService deviceService = get(DeviceService.class);
46 HostService hostService = get(HostService.class);
47 TopologyService topologyService = get(TopologyService.class);
48
49 // Fetch the current topology and its graph that we'll use to render.
50 Topology topo = topologyService.currentTopology();
51 TopologyGraph graph = topologyService.getGraph(topo);
52
53 // Build all interior vertexes, i.e. no end-station hosts yet
54 ArrayNode vertexesNode = mapper.createArrayNode();
55 for (TopologyVertex vertex : graph.getVertexes()) {
56 vertexesNode.add(json(mapper, vertex.deviceId(), 2,
57 deviceService.isAvailable(vertex.deviceId())));
58 }
59
60 // Now scan all links and count number of them between the same devices
61 // using a normalized link key.
62 Map<String, AggLink> linkRecords = aggregateLinks();
63
64 // Now build all interior edges using the aggregated links.
65 ArrayNode edgesNode = mapper.createArrayNode();
66 for (AggLink lr : linkRecords.values()) {
67 edgesNode.add(json(mapper, lr.links.size(), lr.link.src(), lr.link.dst()));
68 }
69
70 // Merge the exterior and interior vertexes and inject host links as
71 // the exterior edges.
tom025e09f2014-09-15 15:29:24 -070072 for (Host host : hostService.getHosts()) {
73 vertexesNode.add(json(mapper, host.id(), 3, true));
74 edgesNode.add(json(mapper, 1, host.location(), new ConnectPoint(host.id(), portNumber(-1))));
75 }
tom8bb16062014-09-12 14:47:46 -070076
77 // Now put the vertexes and edges into a root node and ship them off
78 ObjectNode rootNode = mapper.createObjectNode();
79 rootNode.put("vertexes", vertexesNode);
80 rootNode.put("edges", edgesNode);
81 return Response.ok(rootNode.toString()).build();
82 }
83
tom6a9986b2014-09-12 18:44:52 -070084
tom6a9986b2014-09-12 18:44:52 -070085 /**
86 * Returns a JSON array of all paths between the specified hosts.
87 *
88 * @param src source host id
89 * @param dst target host id
90 * @return JSON array of paths
91 */
92 @javax.ws.rs.Path("/paths/{src}/{dst}")
93 @GET
94 @Produces("application/json")
95 public Response paths(@PathParam("src") String src, @PathParam("dst") String dst) {
96 ObjectMapper mapper = new ObjectMapper();
97
tom6a9986b2014-09-12 18:44:52 -070098 TopologyService topologyService = get(TopologyService.class);
toma33dd342014-09-12 19:07:40 -070099 Topology topology = topologyService.currentTopology();
tom6a9986b2014-09-12 18:44:52 -0700100
101 ArrayNode pathsNode = mapper.createArrayNode();
toma33dd342014-09-12 19:07:40 -0700102 for (Path path : topologyService.getPaths(topology, deviceId(src), deviceId(dst))) {
103 pathsNode.add(json(mapper, path));
104 }
tom6a9986b2014-09-12 18:44:52 -0700105
106 // Now put the vertexes and edges into a root node and ship them off
107 ObjectNode rootNode = mapper.createObjectNode();
toma33dd342014-09-12 19:07:40 -0700108 rootNode.set("paths", pathsNode);
tom6a9986b2014-09-12 18:44:52 -0700109 return Response.ok(rootNode.toString()).build();
110 }
111
tom8bb16062014-09-12 14:47:46 -0700112 // Scan all links and counts number of them between the same devices
113 // using a normalized link key.
114 private Map<String, AggLink> aggregateLinks() {
115 Map<String, AggLink> aggLinks = new HashMap<>();
116 LinkService linkService = get(LinkService.class);
117 for (Link link : linkService.getLinks()) {
118 String key = key(link);
119 AggLink lr = aggLinks.get(key);
120 if (lr == null) {
121 lr = new AggLink(key);
122 aggLinks.put(key, lr);
123 }
124 lr.addLink(link);
125 }
126 return aggLinks;
127 }
128
tom6a9986b2014-09-12 18:44:52 -0700129
tom8bb16062014-09-12 14:47:46 -0700130 // Produces JSON for a graph vertex.
131 private ObjectNode json(ObjectMapper mapper, ElementId id, int group,
132 boolean isOnline) {
133 return mapper.createObjectNode()
toma33dd342014-09-12 19:07:40 -0700134 .put("name", id.uri().toString())
tom8bb16062014-09-12 14:47:46 -0700135 .put("group", group)
136 .put("online", isOnline);
137 }
138
139 // Produces JSON for a graph edge.
140 private ObjectNode json(ObjectMapper mapper, int count,
141 ConnectPoint src, ConnectPoint dst) {
142 return json(mapper, count, id(src), id(dst));
143 }
144
145 // Produces JSON for a graph edge.
146 private ObjectNode json(ObjectMapper mapper, int count, String src, String dst) {
147 return mapper.createObjectNode()
148 .put("source", src).put("target", dst).put("value", count);
149 }
150
toma33dd342014-09-12 19:07:40 -0700151 // Produces JSON representation of a network path.
152 private ArrayNode json(ObjectMapper mapper, Path path) {
153 ArrayNode pathNode = mapper.createArrayNode();
154 for (Link link : path.links()) {
155 ObjectNode linkNode = mapper.createObjectNode()
156 .put("src", id(link.src()))
157 .put("dst", id(link.dst()));
158 pathNode.add(linkNode);
159 }
160 return pathNode;
161 }
162
163
tom8bb16062014-09-12 14:47:46 -0700164 // Aggregate link of all links between the same devices regardless of
165 // their direction.
166 private class AggLink {
167 Link link; // representative links
168
169 final String key;
170 final Set<Link> links = new HashSet<>();
171
172 AggLink(String key) {
173 this.key = key;
174 }
175
176 void addLink(Link link) {
177 links.add(link);
178 if (this.link == null) {
179 this.link = link;
180 }
181 }
182 }
183
184 // Returns a canonical key for the specified link.
185 static String key(Link link) {
186 String s = id(link.src());
187 String d = id(link.dst());
188 return s.compareTo(d) > 0 ? d + s : s + d;
189 }
190
191 // Returns a formatted string for the element associated with the given
192 // connection point.
193 private static String id(ConnectPoint cp) {
toma33dd342014-09-12 19:07:40 -0700194 return cp.elementId().uri().toString();
tom8bb16062014-09-12 14:47:46 -0700195 }
196
197}