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