blob: 77ce06115c717f5de81628d378eb4c6d0aa4c0b7 [file] [log] [blame]
Thomas Vachuska598924e2014-10-23 22:26:07 -07001/*
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 */
19package org.onlab.onos.gui;
20
21import com.fasterxml.jackson.databind.ObjectMapper;
22import com.fasterxml.jackson.databind.node.ArrayNode;
23import com.fasterxml.jackson.databind.node.ObjectNode;
24import org.onlab.onos.net.ConnectPoint;
25import org.onlab.onos.net.Device;
26import org.onlab.onos.net.Host;
27import org.onlab.onos.net.HostLocation;
28import org.onlab.onos.net.Link;
29import org.onlab.onos.net.device.DeviceService;
30import org.onlab.onos.net.host.HostService;
31import org.onlab.onos.net.link.LinkService;
32import org.onlab.onos.net.topology.Topology;
33import org.onlab.onos.net.topology.TopologyGraph;
34import org.onlab.onos.net.topology.TopologyService;
35import org.onlab.onos.net.topology.TopologyVertex;
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -070036import org.onlab.packet.IpAddress;
Thomas Vachuska598924e2014-10-23 22:26:07 -070037import org.onlab.packet.MacAddress;
38import org.onlab.rest.BaseResource;
39
40import javax.ws.rs.GET;
41import javax.ws.rs.Produces;
42import javax.ws.rs.core.Response;
43import java.util.HashMap;
44import java.util.HashSet;
45import java.util.Iterator;
46import java.util.Map;
47import java.util.Set;
48
49/**
50 * Topology viewer resource.
51 */
52@javax.ws.rs.Path("topology")
53public 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()) {
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700105 Set<IpAddress> ipAddresses = host.ipAddresses();
106 IpAddress ipAddress = ipAddresses.isEmpty() ? null : ipAddresses.iterator().next();
Thomas Vachuska598924e2014-10-23 22:26:07 -0700107 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
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700163 private String ip(Set<IpAddress> ipAddresses) {
164 Iterator<IpAddress> it = ipAddresses.iterator();
Thomas Vachuska598924e2014-10-23 22:26:07 -0700165 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}