blob: 145e94aadadf8bd8c75af486ff00a55fe5ea8673 [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;
tom4d0c6632014-09-15 23:27:01 -070018import org.onlab.packet.IPAddress;
tom8bb16062014-09-12 14:47:46 -070019import org.onlab.rest.BaseResource;
20
21import javax.ws.rs.GET;
tom6a9986b2014-09-12 18:44:52 -070022import javax.ws.rs.PathParam;
tom8bb16062014-09-12 14:47:46 -070023import javax.ws.rs.Produces;
24import javax.ws.rs.core.Response;
25import java.util.HashMap;
26import java.util.HashSet;
27import java.util.Map;
28import java.util.Set;
29
tom6a9986b2014-09-12 18:44:52 -070030import static org.onlab.onos.net.DeviceId.deviceId;
tom025e09f2014-09-15 15:29:24 -070031import static org.onlab.onos.net.PortNumber.portNumber;
tom6a9986b2014-09-12 18:44:52 -070032
tom8bb16062014-09-12 14:47:46 -070033/**
34 * Topology viewer resource.
35 */
tom6a9986b2014-09-12 18:44:52 -070036@javax.ws.rs.Path("topology")
tom8bb16062014-09-12 14:47:46 -070037public class TopologyResource extends BaseResource {
38
tom6a9986b2014-09-12 18:44:52 -070039 @javax.ws.rs.Path("/graph")
tom8bb16062014-09-12 14:47:46 -070040 @GET
41 @Produces("application/json")
42 public Response graph() {
43 ObjectMapper mapper = new ObjectMapper();
44
45 // Fetch the services we'll be using.
46 DeviceService deviceService = get(DeviceService.class);
47 HostService hostService = get(HostService.class);
48 TopologyService topologyService = get(TopologyService.class);
49
50 // Fetch the current topology and its graph that we'll use to render.
51 Topology topo = topologyService.currentTopology();
52 TopologyGraph graph = topologyService.getGraph(topo);
53
54 // Build all interior vertexes, i.e. no end-station hosts yet
55 ArrayNode vertexesNode = mapper.createArrayNode();
56 for (TopologyVertex vertex : graph.getVertexes()) {
57 vertexesNode.add(json(mapper, vertex.deviceId(), 2,
tom4d0c6632014-09-15 23:27:01 -070058 vertex.deviceId().uri().getSchemeSpecificPart(),
tom8bb16062014-09-12 14:47:46 -070059 deviceService.isAvailable(vertex.deviceId())));
60 }
61
62 // Now scan all links and count number of them between the same devices
63 // using a normalized link key.
64 Map<String, AggLink> linkRecords = aggregateLinks();
65
66 // Now build all interior edges using the aggregated links.
67 ArrayNode edgesNode = mapper.createArrayNode();
68 for (AggLink lr : linkRecords.values()) {
69 edgesNode.add(json(mapper, lr.links.size(), lr.link.src(), lr.link.dst()));
70 }
71
72 // Merge the exterior and interior vertexes and inject host links as
73 // the exterior edges.
tom025e09f2014-09-15 15:29:24 -070074 for (Host host : hostService.getHosts()) {
tom4d0c6632014-09-15 23:27:01 -070075 Set<IPAddress> ipAddresses = host.ipAddresses();
76 IPAddress ipAddress = ipAddresses.isEmpty() ? null : ipAddresses.iterator().next();
77 String label = ipAddress != null ? ipAddress.toString() : host.mac().toString();
78 vertexesNode.add(json(mapper, host.id(), 3, label, true));
tom025e09f2014-09-15 15:29:24 -070079 edgesNode.add(json(mapper, 1, host.location(), new ConnectPoint(host.id(), portNumber(-1))));
80 }
tom8bb16062014-09-12 14:47:46 -070081
82 // Now put the vertexes and edges into a root node and ship them off
83 ObjectNode rootNode = mapper.createObjectNode();
tom4d0c6632014-09-15 23:27:01 -070084 rootNode.set("vertexes", vertexesNode);
85 rootNode.set("edges", edgesNode);
tom8bb16062014-09-12 14:47:46 -070086 return Response.ok(rootNode.toString()).build();
87 }
88
tom6a9986b2014-09-12 18:44:52 -070089
tom6a9986b2014-09-12 18:44:52 -070090 /**
91 * Returns a JSON array of all paths between the specified hosts.
92 *
93 * @param src source host id
94 * @param dst target host id
95 * @return JSON array of paths
96 */
97 @javax.ws.rs.Path("/paths/{src}/{dst}")
98 @GET
99 @Produces("application/json")
100 public Response paths(@PathParam("src") String src, @PathParam("dst") String dst) {
101 ObjectMapper mapper = new ObjectMapper();
102
tom6a9986b2014-09-12 18:44:52 -0700103 TopologyService topologyService = get(TopologyService.class);
toma33dd342014-09-12 19:07:40 -0700104 Topology topology = topologyService.currentTopology();
tom6a9986b2014-09-12 18:44:52 -0700105
106 ArrayNode pathsNode = mapper.createArrayNode();
toma33dd342014-09-12 19:07:40 -0700107 for (Path path : topologyService.getPaths(topology, deviceId(src), deviceId(dst))) {
108 pathsNode.add(json(mapper, path));
109 }
tom6a9986b2014-09-12 18:44:52 -0700110
111 // Now put the vertexes and edges into a root node and ship them off
112 ObjectNode rootNode = mapper.createObjectNode();
toma33dd342014-09-12 19:07:40 -0700113 rootNode.set("paths", pathsNode);
tom6a9986b2014-09-12 18:44:52 -0700114 return Response.ok(rootNode.toString()).build();
115 }
116
tom8bb16062014-09-12 14:47:46 -0700117 // Scan all links and counts number of them between the same devices
118 // using a normalized link key.
119 private Map<String, AggLink> aggregateLinks() {
120 Map<String, AggLink> aggLinks = new HashMap<>();
121 LinkService linkService = get(LinkService.class);
122 for (Link link : linkService.getLinks()) {
123 String key = key(link);
124 AggLink lr = aggLinks.get(key);
125 if (lr == null) {
126 lr = new AggLink(key);
127 aggLinks.put(key, lr);
128 }
129 lr.addLink(link);
130 }
131 return aggLinks;
132 }
133
134 // Produces JSON for a graph vertex.
135 private ObjectNode json(ObjectMapper mapper, ElementId id, int group,
tom4d0c6632014-09-15 23:27:01 -0700136 String label, boolean isOnline) {
tom8bb16062014-09-12 14:47:46 -0700137 return mapper.createObjectNode()
toma33dd342014-09-12 19:07:40 -0700138 .put("name", id.uri().toString())
tom4d0c6632014-09-15 23:27:01 -0700139 .put("label", label)
tom8bb16062014-09-12 14:47:46 -0700140 .put("group", group)
141 .put("online", isOnline);
142 }
143
144 // Produces JSON for a graph edge.
145 private ObjectNode json(ObjectMapper mapper, int count,
146 ConnectPoint src, ConnectPoint dst) {
147 return json(mapper, count, id(src), id(dst));
148 }
149
150 // Produces JSON for a graph edge.
151 private ObjectNode json(ObjectMapper mapper, int count, String src, String dst) {
152 return mapper.createObjectNode()
153 .put("source", src).put("target", dst).put("value", count);
154 }
155
toma33dd342014-09-12 19:07:40 -0700156 // Produces JSON representation of a network path.
157 private ArrayNode json(ObjectMapper mapper, Path path) {
158 ArrayNode pathNode = mapper.createArrayNode();
159 for (Link link : path.links()) {
160 ObjectNode linkNode = mapper.createObjectNode()
161 .put("src", id(link.src()))
162 .put("dst", id(link.dst()));
163 pathNode.add(linkNode);
164 }
165 return pathNode;
166 }
167
168
tom8bb16062014-09-12 14:47:46 -0700169 // Aggregate link of all links between the same devices regardless of
170 // their direction.
171 private class AggLink {
172 Link link; // representative links
173
174 final String key;
175 final Set<Link> links = new HashSet<>();
176
177 AggLink(String key) {
178 this.key = key;
179 }
180
181 void addLink(Link link) {
182 links.add(link);
183 if (this.link == null) {
184 this.link = link;
185 }
186 }
187 }
188
189 // Returns a canonical key for the specified link.
190 static String key(Link link) {
191 String s = id(link.src());
192 String d = id(link.dst());
193 return s.compareTo(d) > 0 ? d + s : s + d;
194 }
195
196 // Returns a formatted string for the element associated with the given
197 // connection point.
198 private static String id(ConnectPoint cp) {
toma33dd342014-09-12 19:07:40 -0700199 return cp.elementId().uri().toString();
tom8bb16062014-09-12 14:47:46 -0700200 }
201
202}