Thomas Vachuska

Sketched out TopologyResource for the new GUI.

1 +/*
2 + * Licensed to the Apache Software Foundation (ASF) under one
3 + * or more contributor license agreements. See the NOTICE file
4 + * distributed with this work for additional information
5 + * regarding copyright ownership. The ASF licenses this file
6 + * to you under the Apache License, Version 2.0 (the
7 + * "License"); you may not use this file except in compliance
8 + * with the License. You may obtain a copy of the License at
9 + *
10 + * http://www.apache.org/licenses/LICENSE-2.0
11 + *
12 + * Unless required by applicable law or agreed to in writing,
13 + * software distributed under the License is distributed on an
14 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 + * KIND, either express or implied. See the License for the
16 + * specific language governing permissions and limitations
17 + * under the License.
18 + */
19 +package org.onlab.onos.gui;
20 +
21 +import com.fasterxml.jackson.databind.ObjectMapper;
22 +import com.fasterxml.jackson.databind.node.ArrayNode;
23 +import com.fasterxml.jackson.databind.node.ObjectNode;
24 +import org.onlab.onos.net.ConnectPoint;
25 +import org.onlab.onos.net.Device;
26 +import org.onlab.onos.net.Host;
27 +import org.onlab.onos.net.HostLocation;
28 +import org.onlab.onos.net.Link;
29 +import org.onlab.onos.net.device.DeviceService;
30 +import org.onlab.onos.net.host.HostService;
31 +import org.onlab.onos.net.link.LinkService;
32 +import org.onlab.onos.net.topology.Topology;
33 +import org.onlab.onos.net.topology.TopologyGraph;
34 +import org.onlab.onos.net.topology.TopologyService;
35 +import org.onlab.onos.net.topology.TopologyVertex;
36 +import org.onlab.packet.IpPrefix;
37 +import org.onlab.packet.MacAddress;
38 +import org.onlab.rest.BaseResource;
39 +
40 +import javax.ws.rs.GET;
41 +import javax.ws.rs.Produces;
42 +import javax.ws.rs.core.Response;
43 +import java.util.HashMap;
44 +import java.util.HashSet;
45 +import java.util.Iterator;
46 +import java.util.Map;
47 +import java.util.Set;
48 +
49 +/**
50 + * Topology viewer resource.
51 + */
52 +@javax.ws.rs.Path("topology")
53 +public class TopologyResource extends BaseResource {
54 +
55 + @javax.ws.rs.Path("/graph")
56 + @GET
57 + @Produces("application/json")
58 + public Response graph() {
59 + // Fetch the services we'll be using.
60 + DeviceService deviceService = get(DeviceService.class);
61 + HostService hostService = get(HostService.class);
62 + TopologyService topologyService = get(TopologyService.class);
63 +
64 + // Fetch the current topology and its graph that we'll use to render.
65 + Topology topo = topologyService.currentTopology();
66 + TopologyGraph graph = topologyService.getGraph(topo);
67 +
68 + ObjectMapper mapper = new ObjectMapper();
69 + ObjectNode rootNode = mapper.createObjectNode();
70 + rootNode.set("devices", getDevices(mapper, deviceService, graph));
71 + rootNode.set("links", getLinks(mapper, topo, graph));
72 + rootNode.set("hosts", getHosts(mapper, hostService));
73 + return Response.ok(rootNode.toString()).build();
74 + }
75 +
76 + // Encodes all infrastructure devices.
77 + private ArrayNode getDevices(ObjectMapper mapper, DeviceService deviceService,
78 + TopologyGraph graph) {
79 + ArrayNode devices = mapper.createArrayNode();
80 + for (TopologyVertex vertex : graph.getVertexes()) {
81 + devices.add(json(mapper, deviceService.getDevice(vertex.deviceId()),
82 + deviceService.isAvailable(vertex.deviceId())));
83 + }
84 + return devices;
85 + }
86 +
87 + // Encodes all infrastructure links.
88 + private ArrayNode getLinks(ObjectMapper mapper, Topology topo, TopologyGraph graph) {
89 + // Now scan all links and count number of them between the same devices
90 + // using a normalized link key.
91 + Map<String, AggLink> linkRecords = aggregateLinks();
92 +
93 + // Now build all interior edges using the aggregated links.
94 + ArrayNode links = mapper.createArrayNode();
95 + for (AggLink lr : linkRecords.values()) {
96 + links.add(json(mapper, lr));
97 + }
98 + return links;
99 + }
100 +
101 + // Encodes all end-station hosts.
102 + private ArrayNode getHosts(ObjectMapper mapper, HostService hostService) {
103 + ArrayNode hosts = mapper.createArrayNode();
104 + for (Host host : hostService.getHosts()) {
105 + Set<IpPrefix> ipAddresses = host.ipAddresses();
106 + IpPrefix ipAddress = ipAddresses.isEmpty() ? null : ipAddresses.iterator().next();
107 + String label = ipAddress != null ? ipAddress.toString() : host.mac().toString();
108 + hosts.add(json(mapper, host));
109 + }
110 + return hosts;
111 + }
112 +
113 + // 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 +
130 + // Produces JSON for a device.
131 + private ObjectNode json(ObjectMapper mapper, Device device, boolean isOnline) {
132 + ObjectNode node = mapper.createObjectNode()
133 + .put("id", device.id().toString())
134 + .put("type", device.type().toString().toLowerCase())
135 + .put("online", isOnline);
136 + node.set("labels", labels(mapper,
137 + device.id().uri().getSchemeSpecificPart(),
138 + MacAddress.valueOf(device.chassisId().value()).toString(),
139 + device.serialNumber()));
140 + return node;
141 + }
142 +
143 + // Produces JSON for a link.
144 + private ObjectNode json(ObjectMapper mapper, AggLink aggLink) {
145 + Link link = aggLink.link;
146 + return mapper.createObjectNode()
147 + .put("src", link.src().deviceId().toString())
148 + .put("dst", link.dst().deviceId().toString())
149 + .put("type", link.type().toString().toLowerCase())
150 + .put("linkWidth", aggLink.links.size());
151 + }
152 +
153 + // Produces JSON for a device.
154 + private ObjectNode json(ObjectMapper mapper, Host host) {
155 + ObjectNode json = mapper.createObjectNode()
156 + .put("id", host.id().toString());
157 + json.set("cp", location(mapper, host.location()));
158 + json.set("labels", labels(mapper, ip(host.ipAddresses()),
159 + host.mac().toString()));
160 + return json;
161 + }
162 +
163 + private String ip(Set<IpPrefix> ipPrefixes) {
164 + Iterator<IpPrefix> it = ipPrefixes.iterator();
165 + return it.hasNext() ? it.next().toString() : "unknown";
166 + }
167 +
168 + private ObjectNode location(ObjectMapper mapper, HostLocation location) {
169 + return mapper.createObjectNode()
170 + .put("device", location.deviceId().toString())
171 + .put("port", location.port().toLong());
172 + }
173 +
174 + private ArrayNode labels(ObjectMapper mapper, String... labels) {
175 + ArrayNode json = mapper.createArrayNode();
176 + for (String label : labels) {
177 + json.add(label);
178 + }
179 + return json;
180 + }
181 +
182 + // Aggregate link of all links between the same devices regardless of
183 + // their direction.
184 + private class AggLink {
185 + Link link; // representative links
186 +
187 + final String key;
188 + final Set<Link> links = new HashSet<>();
189 +
190 + AggLink(String key) {
191 + this.key = key;
192 + }
193 +
194 + void addLink(Link link) {
195 + links.add(link);
196 + if (this.link == null) {
197 + this.link = link;
198 + }
199 + }
200 + }
201 +
202 + // Returns a canonical key for the specified link.
203 + static String key(Link link) {
204 + String s = id(link.src());
205 + String d = id(link.dst());
206 + return s.compareTo(d) > 0 ? d + s : s + d;
207 + }
208 +
209 + // Returns a formatted string for the element associated with the given
210 + // connection point.
211 + private static String id(ConnectPoint cp) {
212 + return cp.elementId().toString();
213 + }
214 +
215 +}
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
14 layering: true, 14 layering: true,
15 collisionPrevention: true 15 collisionPrevention: true
16 }, 16 },
17 + XjsonUrl: 'rs/topology/graph',
17 jsonUrl: 'network.json', 18 jsonUrl: 'network.json',
18 iconUrl: { 19 iconUrl: {
19 device: 'img/device.png', 20 device: 'img/device.png',
......