blob: 7fb5d95219b77e24edb08d3d64954c8136508898 [file] [log] [blame]
Thomas Vachuska329af532015-03-10 02:08:33 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska329af532015-03-10 02:08:33 -07003 *
4 * 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
7 *
8 * 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.
15 */
16package org.onosproject.ui.impl;
17
18import com.fasterxml.jackson.databind.JsonNode;
Thomas Vachuska329af532015-03-10 02:08:33 -070019import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import org.onlab.osgi.ServiceDirectory;
22import org.onlab.packet.IpAddress;
Simon Hunt95d56fd2015-11-12 11:06:44 -080023import org.onlab.util.DefaultHashMap;
Thomas Vachuska329af532015-03-10 02:08:33 -070024import org.onosproject.cluster.ClusterEvent;
25import org.onosproject.cluster.ClusterService;
26import org.onosproject.cluster.ControllerNode;
27import org.onosproject.cluster.NodeId;
28import org.onosproject.core.CoreService;
Thomas Vachuskaf0397b52015-05-29 13:50:17 -070029import org.onosproject.incubator.net.PortStatisticsService;
cheng fan35dc0f22015-06-10 06:02:47 +080030import org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint;
31import org.onosproject.incubator.net.tunnel.Tunnel;
32import org.onosproject.incubator.net.tunnel.TunnelService;
Thomas Vachuska329af532015-03-10 02:08:33 -070033import org.onosproject.mastership.MastershipService;
34import org.onosproject.net.Annotated;
35import org.onosproject.net.AnnotationKeys;
36import org.onosproject.net.Annotations;
37import org.onosproject.net.ConnectPoint;
38import org.onosproject.net.DefaultEdgeLink;
39import org.onosproject.net.Device;
40import org.onosproject.net.DeviceId;
41import org.onosproject.net.EdgeLink;
Simon Huntf4fd2a22016-08-10 15:41:09 -070042import org.onosproject.net.ElementId;
Thomas Vachuska329af532015-03-10 02:08:33 -070043import org.onosproject.net.Host;
44import org.onosproject.net.HostId;
45import org.onosproject.net.HostLocation;
46import org.onosproject.net.Link;
Thomas Vachuska329af532015-03-10 02:08:33 -070047import org.onosproject.net.device.DeviceEvent;
48import org.onosproject.net.device.DeviceService;
49import org.onosproject.net.flow.FlowEntry;
50import org.onosproject.net.flow.FlowRuleService;
Thomas Vachuska329af532015-03-10 02:08:33 -070051import org.onosproject.net.host.HostEvent;
52import org.onosproject.net.host.HostService;
Thomas Vachuska329af532015-03-10 02:08:33 -070053import org.onosproject.net.intent.IntentService;
Thomas Vachuska329af532015-03-10 02:08:33 -070054import org.onosproject.net.link.LinkEvent;
55import org.onosproject.net.link.LinkService;
56import org.onosproject.net.provider.ProviderId;
Thomas Vachuska329af532015-03-10 02:08:33 -070057import org.onosproject.net.statistic.StatisticService;
58import org.onosproject.net.topology.Topology;
59import org.onosproject.net.topology.TopologyService;
Simon Huntd2747a02015-04-30 22:41:16 -070060import org.onosproject.ui.JsonUtils;
Thomas Vachuska329af532015-03-10 02:08:33 -070061import org.onosproject.ui.UiConnection;
Simon Hunta0ddb022015-05-01 09:53:01 -070062import org.onosproject.ui.UiMessageHandler;
Simon Hunted804d52016-03-30 09:51:40 -070063import org.onosproject.ui.impl.topo.util.ServicesBundle;
Simon Hunt0af1ec32015-07-24 12:17:55 -070064import org.onosproject.ui.topo.PropertyPanel;
Thomas Vachuska329af532015-03-10 02:08:33 -070065import org.slf4j.Logger;
66import org.slf4j.LoggerFactory;
67
Thomas Vachuska329af532015-03-10 02:08:33 -070068import java.util.Collection;
69import java.util.Collections;
Thomas Vachuska329af532015-03-10 02:08:33 -070070import java.util.Iterator;
Thomas Vachuska329af532015-03-10 02:08:33 -070071import java.util.Map;
chengfanc553c952016-07-22 15:48:23 +080072import java.util.Optional;
Simon Huntf4fd2a22016-08-10 15:41:09 -070073import java.util.Set;
Thomas Vachuska329af532015-03-10 02:08:33 -070074import java.util.concurrent.ConcurrentHashMap;
75
76import static com.google.common.base.Preconditions.checkNotNull;
77import static com.google.common.base.Strings.isNullOrEmpty;
Thomas Vachuska329af532015-03-10 02:08:33 -070078import static org.onosproject.net.PortNumber.portNumber;
Simon Hunt3a0598f2015-08-04 19:59:04 -070079import static org.onosproject.ui.topo.TopoConstants.CoreButtons;
80import static org.onosproject.ui.topo.TopoConstants.Properties;
Simon Huntd3ceffa2015-08-25 12:44:35 -070081import static org.onosproject.ui.topo.TopoUtils.compactLinkString;
Thomas Vachuska329af532015-03-10 02:08:33 -070082
83/**
84 * Facility for creating messages bound for the topology viewer.
85 */
Simon Hunta0ddb022015-05-01 09:53:01 -070086public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
Thomas Vachuska329af532015-03-10 02:08:33 -070087
Simon Huntf4fd2a22016-08-10 15:41:09 -070088 private static final String NO_GEO_VALUE = "0.0";
89
Simon Hunt95d56fd2015-11-12 11:06:44 -080090 // default to an "add" event...
91 private static final DefaultHashMap<ClusterEvent.Type, String> CLUSTER_EVENT =
92 new DefaultHashMap<>("addInstance");
93
94 // default to an "update" event...
95 private static final DefaultHashMap<DeviceEvent.Type, String> DEVICE_EVENT =
96 new DefaultHashMap<>("updateDevice");
97 private static final DefaultHashMap<LinkEvent.Type, String> LINK_EVENT =
98 new DefaultHashMap<>("updateLink");
99 private static final DefaultHashMap<HostEvent.Type, String> HOST_EVENT =
100 new DefaultHashMap<>("updateHost");
101
102 // but call out specific events that we care to differentiate...
103 static {
104 CLUSTER_EVENT.put(ClusterEvent.Type.INSTANCE_REMOVED, "removeInstance");
105
106 DEVICE_EVENT.put(DeviceEvent.Type.DEVICE_ADDED, "addDevice");
107 DEVICE_EVENT.put(DeviceEvent.Type.DEVICE_REMOVED, "removeDevice");
108
109 LINK_EVENT.put(LinkEvent.Type.LINK_ADDED, "addLink");
110 LINK_EVENT.put(LinkEvent.Type.LINK_REMOVED, "removeLink");
111
112 HOST_EVENT.put(HostEvent.Type.HOST_ADDED, "addHost");
113 HOST_EVENT.put(HostEvent.Type.HOST_REMOVED, "removeHost");
114 HOST_EVENT.put(HostEvent.Type.HOST_MOVED, "moveHost");
115 }
116
Simon Huntd2747a02015-04-30 22:41:16 -0700117 protected static final Logger log =
118 LoggerFactory.getLogger(TopologyViewMessageHandlerBase.class);
Thomas Vachuska329af532015-03-10 02:08:33 -0700119
Simon Huntd2747a02015-04-30 22:41:16 -0700120 private static final ProviderId PID =
121 new ProviderId("core", "org.onosproject.core", true);
Thomas Vachuska329af532015-03-10 02:08:33 -0700122
Simon Hunta17fa672015-08-19 18:42:22 -0700123 protected static final String SHOW_HIGHLIGHTS = "showHighlights";
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700124
Thomas Vachuska329af532015-03-10 02:08:33 -0700125 protected ServiceDirectory directory;
126 protected ClusterService clusterService;
127 protected DeviceService deviceService;
128 protected LinkService linkService;
129 protected HostService hostService;
130 protected MastershipService mastershipService;
131 protected IntentService intentService;
132 protected FlowRuleService flowService;
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700133 protected StatisticService flowStatsService;
134 protected PortStatisticsService portStatsService;
Thomas Vachuska329af532015-03-10 02:08:33 -0700135 protected TopologyService topologyService;
cheng fan35dc0f22015-06-10 06:02:47 +0800136 protected TunnelService tunnelService;
Thomas Vachuska329af532015-03-10 02:08:33 -0700137
Simon Hunta17fa672015-08-19 18:42:22 -0700138 protected ServicesBundle servicesBundle;
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700139
Thomas Vachuska329af532015-03-10 02:08:33 -0700140 private String version;
141
142 // TODO: extract into an external & durable state; good enough for now and demo
143 private static Map<String, ObjectNode> metaUi = new ConcurrentHashMap<>();
144
145 /**
Thomas Vachuska329af532015-03-10 02:08:33 -0700146 * Returns read-only view of the meta-ui information.
147 *
148 * @return map of id to meta-ui mementos
149 */
150 static Map<String, ObjectNode> getMetaUi() {
151 return Collections.unmodifiableMap(metaUi);
152 }
153
154 @Override
155 public void init(UiConnection connection, ServiceDirectory directory) {
156 super.init(connection, directory);
157 this.directory = checkNotNull(directory, "Directory cannot be null");
158 clusterService = directory.get(ClusterService.class);
159 deviceService = directory.get(DeviceService.class);
160 linkService = directory.get(LinkService.class);
161 hostService = directory.get(HostService.class);
162 mastershipService = directory.get(MastershipService.class);
163 intentService = directory.get(IntentService.class);
164 flowService = directory.get(FlowRuleService.class);
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700165 flowStatsService = directory.get(StatisticService.class);
166 portStatsService = directory.get(PortStatisticsService.class);
Thomas Vachuska329af532015-03-10 02:08:33 -0700167 topologyService = directory.get(TopologyService.class);
cheng fan35dc0f22015-06-10 06:02:47 +0800168 tunnelService = directory.get(TunnelService.class);
Thomas Vachuska329af532015-03-10 02:08:33 -0700169
Simon Hunta17fa672015-08-19 18:42:22 -0700170 servicesBundle = new ServicesBundle(intentService, deviceService,
171 hostService, linkService,
172 flowService,
173 flowStatsService, portStatsService);
174
Thomas Vachuska329af532015-03-10 02:08:33 -0700175 String ver = directory.get(CoreService.class).version().toString();
176 version = ver.replace(".SNAPSHOT", "*").replaceFirst("~.*$", "");
177 }
178
Thomas Vachuska329af532015-03-10 02:08:33 -0700179 // Returns the specified set of IP addresses as a string.
180 private String ip(Set<IpAddress> ipAddresses) {
181 Iterator<IpAddress> it = ipAddresses.iterator();
182 return it.hasNext() ? it.next().toString() : "unknown";
183 }
184
185 // Produces JSON structure from annotations.
186 private JsonNode props(Annotations annotations) {
Simon Huntda580882015-05-12 20:58:18 -0700187 ObjectNode props = objectNode();
Thomas Vachuska329af532015-03-10 02:08:33 -0700188 if (annotations != null) {
189 for (String key : annotations.keys()) {
190 props.put(key, annotations.value(key));
191 }
192 }
193 return props;
194 }
195
196 // Produces an informational log message event bound to the client.
197 protected ObjectNode info(long id, String message) {
198 return message("info", id, message);
199 }
200
201 // Produces a warning log message event bound to the client.
202 protected ObjectNode warning(long id, String message) {
203 return message("warning", id, message);
204 }
205
206 // Produces an error log message event bound to the client.
207 protected ObjectNode error(long id, String message) {
208 return message("error", id, message);
209 }
210
211 // Produces a log message event bound to the client.
212 private ObjectNode message(String severity, long id, String message) {
Simon Huntda580882015-05-12 20:58:18 -0700213 ObjectNode payload = objectNode()
Simon Huntd2747a02015-04-30 22:41:16 -0700214 .put("severity", severity)
215 .put("message", message);
Thomas Vachuska329af532015-03-10 02:08:33 -0700216
Simon Huntd2747a02015-04-30 22:41:16 -0700217 return JsonUtils.envelope("message", id, payload);
Thomas Vachuska329af532015-03-10 02:08:33 -0700218 }
219
Thomas Vachuska329af532015-03-10 02:08:33 -0700220 // Produces a cluster instance message to the client.
Simon Hunt95d56fd2015-11-12 11:06:44 -0800221 protected ObjectNode instanceMessage(ClusterEvent event, String msgType) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700222 ControllerNode node = event.subject();
223 int switchCount = mastershipService.getDevicesOf(node.id()).size();
Simon Huntda580882015-05-12 20:58:18 -0700224 ObjectNode payload = objectNode()
Thomas Vachuska329af532015-03-10 02:08:33 -0700225 .put("id", node.id().toString())
226 .put("ip", node.ip().toString())
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800227 .put("online", clusterService.getState(node.id()).isActive())
Thomas Vachuskafba7f3d2016-03-23 15:46:25 -0700228 .put("ready", clusterService.getState(node.id()).isReady())
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700229 .put("uiAttached", node.equals(clusterService.getLocalNode()))
Thomas Vachuska329af532015-03-10 02:08:33 -0700230 .put("switches", switchCount);
231
Simon Huntda580882015-05-12 20:58:18 -0700232 ArrayNode labels = arrayNode();
Thomas Vachuska329af532015-03-10 02:08:33 -0700233 labels.add(node.id().toString());
234 labels.add(node.ip().toString());
235
236 // Add labels, props and stuff the payload into envelope.
237 payload.set("labels", labels);
238 addMetaUi(node.id().toString(), payload);
239
Simon Hunt95d56fd2015-11-12 11:06:44 -0800240 String type = msgType != null ? msgType : CLUSTER_EVENT.get(event.type());
Simon Huntd2747a02015-04-30 22:41:16 -0700241 return JsonUtils.envelope(type, 0, payload);
Thomas Vachuska329af532015-03-10 02:08:33 -0700242 }
243
244 // Produces a device event message to the client.
245 protected ObjectNode deviceMessage(DeviceEvent event) {
246 Device device = event.subject();
Simon Hunt1e20dae2016-10-28 11:26:26 -0700247 String uiType = device.annotations().value(AnnotationKeys.UI_TYPE);
248 String devType = uiType != null ? uiType :
249 device.type().toString().toLowerCase();
250
Simon Huntda580882015-05-12 20:58:18 -0700251 ObjectNode payload = objectNode()
Thomas Vachuska329af532015-03-10 02:08:33 -0700252 .put("id", device.id().toString())
Simon Hunt1e20dae2016-10-28 11:26:26 -0700253 .put("type", devType)
Thomas Vachuska329af532015-03-10 02:08:33 -0700254 .put("online", deviceService.isAvailable(device.id()))
255 .put("master", master(device.id()));
256
257 // Generate labels: id, chassis id, no-label, optional-name
258 String name = device.annotations().value(AnnotationKeys.NAME);
Simon Huntda580882015-05-12 20:58:18 -0700259 ArrayNode labels = arrayNode();
Thomas Vachuska329af532015-03-10 02:08:33 -0700260 labels.add("");
261 labels.add(isNullOrEmpty(name) ? device.id().toString() : name);
262 labels.add(device.id().toString());
263
264 // Add labels, props and stuff the payload into envelope.
265 payload.set("labels", labels);
266 payload.set("props", props(device.annotations()));
267 addGeoLocation(device, payload);
268 addMetaUi(device.id().toString(), payload);
269
Simon Hunt95d56fd2015-11-12 11:06:44 -0800270 String type = DEVICE_EVENT.get(event.type());
Simon Huntd2747a02015-04-30 22:41:16 -0700271 return JsonUtils.envelope(type, 0, payload);
Thomas Vachuska329af532015-03-10 02:08:33 -0700272 }
273
274 // Produces a link event message to the client.
275 protected ObjectNode linkMessage(LinkEvent event) {
276 Link link = event.subject();
Simon Huntda580882015-05-12 20:58:18 -0700277 ObjectNode payload = objectNode()
Thomas Vachuska329af532015-03-10 02:08:33 -0700278 .put("id", compactLinkString(link))
279 .put("type", link.type().toString().toLowerCase())
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800280 .put("expected", link.isExpected())
Thomas Vachuska329af532015-03-10 02:08:33 -0700281 .put("online", link.state() == Link.State.ACTIVE)
282 .put("linkWidth", 1.2)
283 .put("src", link.src().deviceId().toString())
284 .put("srcPort", link.src().port().toString())
285 .put("dst", link.dst().deviceId().toString())
286 .put("dstPort", link.dst().port().toString());
Simon Hunt95d56fd2015-11-12 11:06:44 -0800287 String type = LINK_EVENT.get(event.type());
Simon Huntd2747a02015-04-30 22:41:16 -0700288 return JsonUtils.envelope(type, 0, payload);
Thomas Vachuska329af532015-03-10 02:08:33 -0700289 }
290
291 // Produces a host event message to the client.
292 protected ObjectNode hostMessage(HostEvent event) {
293 Host host = event.subject();
Charles Chan33f28a92015-11-13 13:12:38 -0800294 Host prevHost = event.prevSubject();
Simon Hunt1e20dae2016-10-28 11:26:26 -0700295 String hostType = host.annotations().value(AnnotationKeys.UI_TYPE);
Simon Hunt95d56fd2015-11-12 11:06:44 -0800296
Simon Huntda580882015-05-12 20:58:18 -0700297 ObjectNode payload = objectNode()
Thomas Vachuska329af532015-03-10 02:08:33 -0700298 .put("id", host.id().toString())
299 .put("type", isNullOrEmpty(hostType) ? "endstation" : hostType)
300 .put("ingress", compactLinkString(edgeLink(host, true)))
301 .put("egress", compactLinkString(edgeLink(host, false)));
Simon Huntda580882015-05-12 20:58:18 -0700302 payload.set("cp", hostConnect(host.location()));
Charles Chan33f28a92015-11-13 13:12:38 -0800303 if (prevHost != null && prevHost.location() != null) {
304 payload.set("prevCp", hostConnect(prevHost.location()));
Simon Hunt95d56fd2015-11-12 11:06:44 -0800305 }
Simon Huntda580882015-05-12 20:58:18 -0700306 payload.set("labels", labels(ip(host.ipAddresses()),
Thomas Vachuska329af532015-03-10 02:08:33 -0700307 host.mac().toString()));
308 payload.set("props", props(host.annotations()));
309 addGeoLocation(host, payload);
310 addMetaUi(host.id().toString(), payload);
311
Simon Hunt95d56fd2015-11-12 11:06:44 -0800312 String type = HOST_EVENT.get(event.type());
Simon Huntd2747a02015-04-30 22:41:16 -0700313 return JsonUtils.envelope(type, 0, payload);
Thomas Vachuska329af532015-03-10 02:08:33 -0700314 }
315
316 // Encodes the specified host location into a JSON object.
Simon Huntda580882015-05-12 20:58:18 -0700317 private ObjectNode hostConnect(HostLocation location) {
318 return objectNode()
Thomas Vachuska329af532015-03-10 02:08:33 -0700319 .put("device", location.deviceId().toString())
320 .put("port", location.port().toLong());
321 }
322
323 // Encodes the specified list of labels a JSON array.
Simon Huntda580882015-05-12 20:58:18 -0700324 private ArrayNode labels(String... labels) {
325 ArrayNode json = arrayNode();
Thomas Vachuska329af532015-03-10 02:08:33 -0700326 for (String label : labels) {
327 json.add(label);
328 }
329 return json;
330 }
331
332 // Returns the name of the master node for the specified device id.
333 private String master(DeviceId deviceId) {
334 NodeId master = mastershipService.getMasterFor(deviceId);
335 return master != null ? master.toString() : "";
336 }
337
338 // Generates an edge link from the specified host location.
339 private EdgeLink edgeLink(Host host, boolean ingress) {
340 return new DefaultEdgeLink(PID, new ConnectPoint(host.id(), portNumber(0)),
341 host.location(), ingress);
342 }
343
344 // Adds meta UI information for the specified object.
345 private void addMetaUi(String id, ObjectNode payload) {
346 ObjectNode meta = metaUi.get(id);
347 if (meta != null) {
348 payload.set("metaUi", meta);
349 }
350 }
351
352 // Adds a geo location JSON to the specified payload object.
353 private void addGeoLocation(Annotated annotated, ObjectNode payload) {
354 Annotations annotations = annotated.annotations();
355 if (annotations == null) {
356 return;
357 }
358
Thomas Vachuska329af532015-03-10 02:08:33 -0700359 String slng = annotations.value(AnnotationKeys.LONGITUDE);
Simon Huntfd7106c2016-02-09 15:05:26 -0800360 String slat = annotations.value(AnnotationKeys.LATITUDE);
Simon Huntf4fd2a22016-08-10 15:41:09 -0700361 boolean validLng = slng != null && !slng.equals(NO_GEO_VALUE);
362 boolean validLat = slat != null && !slat.equals(NO_GEO_VALUE);
363 if (validLat && validLng) {
364 try {
Thomas Vachuska329af532015-03-10 02:08:33 -0700365 double lng = Double.parseDouble(slng);
Simon Huntfd7106c2016-02-09 15:05:26 -0800366 double lat = Double.parseDouble(slat);
Simon Huntda580882015-05-12 20:58:18 -0700367 ObjectNode loc = objectNode()
Simon Huntbc30e682017-02-15 18:39:23 -0800368 .put("type", "geo")
Simon Huntfd7106c2016-02-09 15:05:26 -0800369 .put("lng", lng)
370 .put("lat", lat);
Thomas Vachuska329af532015-03-10 02:08:33 -0700371 payload.set("location", loc);
Simon Huntf4fd2a22016-08-10 15:41:09 -0700372 } catch (NumberFormatException e) {
373 log.warn("Invalid geo data: longitude={}, latitude={}", slng, slat);
Thomas Vachuska329af532015-03-10 02:08:33 -0700374 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700375 }
376 }
377
378 // Updates meta UI information for the specified object.
Simon Huntd2747a02015-04-30 22:41:16 -0700379 protected void updateMetaUi(ObjectNode payload) {
380 metaUi.put(JsonUtils.string(payload, "id"),
381 JsonUtils.node(payload, "memento"));
Thomas Vachuska329af532015-03-10 02:08:33 -0700382 }
383
Simon Hunta17fa672015-08-19 18:42:22 -0700384
Simon Huntb745ca62015-07-28 15:37:11 -0700385 // -----------------------------------------------------------------------
386 // Create models of the data to return, that overlays can adjust / augment
387
388 // Returns property panel model for summary response.
Simon Hunt8a0429a2017-01-06 16:52:47 -0800389 protected PropertyPanel summmaryMessage() {
Thomas Vachuska329af532015-03-10 02:08:33 -0700390 Topology topology = topologyService.currentTopology();
Simon Hunt0af1ec32015-07-24 12:17:55 -0700391
Simon Hunt00a27ff2015-07-28 18:53:40 -0700392 return new PropertyPanel("ONOS Summary", "node")
Thomas Vachuskae50b6212015-12-02 08:00:09 -0800393 .addProp(Properties.VERSION, version)
394 .addSeparator()
chengfanc553c952016-07-22 15:48:23 +0800395 .addProp(Properties.DEVICES, deviceService.getDeviceCount())
Simon Huntfb940112015-07-29 18:36:35 -0700396 .addProp(Properties.LINKS, topology.linkCount())
397 .addProp(Properties.HOSTS, hostService.getHostCount())
398 .addProp(Properties.TOPOLOGY_SSCS, topology.clusterCount())
Simon Hunt00a27ff2015-07-28 18:53:40 -0700399 .addSeparator()
Simon Huntfb940112015-07-29 18:36:35 -0700400 .addProp(Properties.INTENTS, intentService.getIntentCount())
401 .addProp(Properties.TUNNELS, tunnelService.tunnelCount())
Thomas Vachuskae50b6212015-12-02 08:00:09 -0800402 .addProp(Properties.FLOWS, flowService.getFlowRuleCount());
Thomas Vachuska329af532015-03-10 02:08:33 -0700403 }
404
Simon Huntb745ca62015-07-28 15:37:11 -0700405 // Returns property panel model for device details response.
Simon Hunt8a0429a2017-01-06 16:52:47 -0800406 protected PropertyPanel deviceDetails(DeviceId deviceId) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700407 Device device = deviceService.getDevice(deviceId);
408 Annotations annot = device.annotations();
409 String name = annot.value(AnnotationKeys.NAME);
410 int portCount = deviceService.getPorts(deviceId).size();
411 int flowCount = getFlowCount(deviceId);
cheng fan35dc0f22015-06-10 06:02:47 +0800412 int tunnelCount = getTunnelCount(deviceId);
Simon Huntb745ca62015-07-28 15:37:11 -0700413
414 String title = isNullOrEmpty(name) ? deviceId.toString() : name;
415 String typeId = device.type().toString().toLowerCase();
416
417 PropertyPanel pp = new PropertyPanel(title, typeId)
Simon Huntfb940112015-07-29 18:36:35 -0700418 .id(deviceId.toString())
Simon Hunt3a0598f2015-08-04 19:59:04 -0700419
Simon Huntfb940112015-07-29 18:36:35 -0700420 .addProp(Properties.URI, deviceId.toString())
421 .addProp(Properties.VENDOR, device.manufacturer())
422 .addProp(Properties.HW_VERSION, device.hwVersion())
423 .addProp(Properties.SW_VERSION, device.swVersion())
424 .addProp(Properties.SERIAL_NUMBER, device.serialNumber())
425 .addProp(Properties.PROTOCOL, annot.value(AnnotationKeys.PROTOCOL))
426 .addSeparator()
Simon Hunt3a0598f2015-08-04 19:59:04 -0700427
Simon Huntfb940112015-07-29 18:36:35 -0700428 .addProp(Properties.LATITUDE, annot.value(AnnotationKeys.LATITUDE))
429 .addProp(Properties.LONGITUDE, annot.value(AnnotationKeys.LONGITUDE))
430 .addSeparator()
Simon Hunt3a0598f2015-08-04 19:59:04 -0700431
Simon Huntfb940112015-07-29 18:36:35 -0700432 .addProp(Properties.PORTS, portCount)
433 .addProp(Properties.FLOWS, flowCount)
Simon Hunt3a0598f2015-08-04 19:59:04 -0700434 .addProp(Properties.TUNNELS, tunnelCount)
Simon Hunt00a27ff2015-07-28 18:53:40 -0700435
Simon Hunt3a0598f2015-08-04 19:59:04 -0700436 .addButton(CoreButtons.SHOW_DEVICE_VIEW)
437 .addButton(CoreButtons.SHOW_FLOW_VIEW)
438 .addButton(CoreButtons.SHOW_PORT_VIEW)
Jian Li79f67322016-01-06 18:22:37 -0800439 .addButton(CoreButtons.SHOW_GROUP_VIEW)
440 .addButton(CoreButtons.SHOW_METER_VIEW);
Simon Huntb745ca62015-07-28 15:37:11 -0700441
442 return pp;
Thomas Vachuska329af532015-03-10 02:08:33 -0700443 }
444
445 protected int getFlowCount(DeviceId deviceId) {
446 int count = 0;
Simon Huntb745ca62015-07-28 15:37:11 -0700447 for (FlowEntry flowEntry : flowService.getFlowEntries(deviceId)) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700448 count++;
Thomas Vachuska329af532015-03-10 02:08:33 -0700449 }
450 return count;
451 }
452
cheng fan35dc0f22015-06-10 06:02:47 +0800453 protected int getTunnelCount(DeviceId deviceId) {
454 int count = 0;
455 Collection<Tunnel> tunnels = tunnelService.queryAllTunnels();
456 for (Tunnel tunnel : tunnels) {
chengfanc553c952016-07-22 15:48:23 +0800457 //Only OpticalTunnelEndPoint has a device
458 if (!(tunnel.src() instanceof OpticalTunnelEndPoint) ||
459 !(tunnel.dst() instanceof OpticalTunnelEndPoint)) {
460 continue;
461 }
462
463 Optional<ElementId> srcElementId = ((OpticalTunnelEndPoint) tunnel.src()).elementId();
464 Optional<ElementId> dstElementId = ((OpticalTunnelEndPoint) tunnel.dst()).elementId();
465 if (!srcElementId.isPresent() || !dstElementId.isPresent()) {
466 continue;
467 }
468 DeviceId srcDeviceId = (DeviceId) srcElementId.get();
469 DeviceId dstDeviceId = (DeviceId) dstElementId.get();
470 if (srcDeviceId.equals(deviceId) || dstDeviceId.equals(deviceId)) {
cheng fan35dc0f22015-06-10 06:02:47 +0800471 count++;
472 }
473 }
474 return count;
475 }
476
Thomas Vachuska329af532015-03-10 02:08:33 -0700477 // Returns host details response.
Simon Hunt8a0429a2017-01-06 16:52:47 -0800478 protected PropertyPanel hostDetails(HostId hostId) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700479 Host host = hostService.getHost(hostId);
480 Annotations annot = host.annotations();
481 String type = annot.value(AnnotationKeys.TYPE);
482 String name = annot.value(AnnotationKeys.NAME);
483 String vlan = host.vlan().toString();
Simon Huntb745ca62015-07-28 15:37:11 -0700484
485 String title = isNullOrEmpty(name) ? hostId.toString() : name;
486 String typeId = isNullOrEmpty(type) ? "endstation" : type;
487
488 PropertyPanel pp = new PropertyPanel(title, typeId)
Simon Huntfb940112015-07-29 18:36:35 -0700489 .id(hostId.toString())
490 .addProp(Properties.MAC, host.mac())
491 .addProp(Properties.IP, host.ipAddresses(), "[\\[\\]]")
Jon Halla3fcf672017-03-28 16:53:22 -0700492 .addProp(Properties.VLAN, "-1".equals(vlan) ? "none" : vlan)
Simon Huntfb940112015-07-29 18:36:35 -0700493 .addSeparator()
494 .addProp(Properties.LATITUDE, annot.value(AnnotationKeys.LATITUDE))
495 .addProp(Properties.LONGITUDE, annot.value(AnnotationKeys.LONGITUDE));
Simon Huntb745ca62015-07-28 15:37:11 -0700496
Simon Hunta17fa672015-08-19 18:42:22 -0700497 // Potentially add button descriptors here
Simon Huntb745ca62015-07-28 15:37:11 -0700498 return pp;
Thomas Vachuska329af532015-03-10 02:08:33 -0700499 }
500
Thomas Vachuska329af532015-03-10 02:08:33 -0700501}