blob: 83e54b4310c3a53b7f5f24d125cf02b6569f1bd5 [file] [log] [blame]
Thomas Vachuska7d638d32014-11-07 10:24:43 -08001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
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.onlab.onos.gui;
17
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080018import com.fasterxml.jackson.databind.node.ObjectNode;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080019import org.eclipse.jetty.websocket.WebSocket;
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080020import org.onlab.onos.cluster.ClusterEvent;
21import org.onlab.onos.cluster.ClusterEventListener;
22import org.onlab.onos.cluster.ControllerNode;
Thomas Vachuska4830d392014-11-09 17:09:56 -080023import org.onlab.onos.core.ApplicationId;
24import org.onlab.onos.core.CoreService;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080025import org.onlab.onos.mastership.MastershipEvent;
26import org.onlab.onos.mastership.MastershipListener;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080027import org.onlab.onos.net.Device;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080028import org.onlab.onos.net.Host;
29import org.onlab.onos.net.HostId;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080030import org.onlab.onos.net.Link;
Thomas Vachuskad1be50d2014-11-08 16:10:20 -080031import org.onlab.onos.net.Path;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080032import org.onlab.onos.net.device.DeviceEvent;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080033import org.onlab.onos.net.device.DeviceListener;
Thomas Vachuska4830d392014-11-09 17:09:56 -080034import org.onlab.onos.net.flow.DefaultTrafficSelector;
35import org.onlab.onos.net.flow.DefaultTrafficTreatment;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080036import org.onlab.onos.net.host.HostEvent;
37import org.onlab.onos.net.host.HostListener;
Thomas Vachuska4830d392014-11-09 17:09:56 -080038import org.onlab.onos.net.intent.HostToHostIntent;
39import org.onlab.onos.net.intent.Intent;
40import org.onlab.onos.net.intent.IntentEvent;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080041import org.onlab.onos.net.intent.IntentId;
Thomas Vachuska4830d392014-11-09 17:09:56 -080042import org.onlab.onos.net.intent.IntentListener;
Thomas Vachuska4830d392014-11-09 17:09:56 -080043import org.onlab.onos.net.intent.PathIntent;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080044import org.onlab.onos.net.link.LinkEvent;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080045import org.onlab.onos.net.link.LinkListener;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080046import org.onlab.osgi.ServiceDirectory;
47
48import java.io.IOException;
Thomas Vachuska4830d392014-11-09 17:09:56 -080049import java.util.List;
Thomas Vachuskad1be50d2014-11-08 16:10:20 -080050import java.util.Map;
Thomas Vachuska4830d392014-11-09 17:09:56 -080051import java.util.concurrent.ConcurrentHashMap;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080052
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080053import static org.onlab.onos.cluster.ClusterEvent.Type.INSTANCE_ADDED;
Thomas Vachuskad1be50d2014-11-08 16:10:20 -080054import static org.onlab.onos.net.DeviceId.deviceId;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080055import static org.onlab.onos.net.HostId.hostId;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080056import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_ADDED;
Thomas Vachuska4830d392014-11-09 17:09:56 -080057import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080058import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080059
Thomas Vachuska7d638d32014-11-07 10:24:43 -080060/**
61 * Web socket capable of interacting with the GUI topology view.
62 */
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080063public class TopologyWebSocket
64 extends TopologyMessages implements WebSocket.OnTextMessage {
Thomas Vachuska7d638d32014-11-07 10:24:43 -080065
Thomas Vachuska4830d392014-11-09 17:09:56 -080066 private static final String APP_ID = "org.onlab.onos.gui";
Thomas Vachuska4830d392014-11-09 17:09:56 -080067
68 private final ApplicationId appId;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080069
Thomas Vachuska7d638d32014-11-07 10:24:43 -080070 private Connection connection;
71
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080072 private final ClusterEventListener clusterListener = new InternalClusterListener();
Thomas Vachuska690e5f62014-11-09 08:26:47 -080073 private final DeviceListener deviceListener = new InternalDeviceListener();
74 private final LinkListener linkListener = new InternalLinkListener();
75 private final HostListener hostListener = new InternalHostListener();
76 private final MastershipListener mastershipListener = new InternalMastershipListener();
Thomas Vachuska4830d392014-11-09 17:09:56 -080077 private final IntentListener intentListener = new InternalIntentListener();
Thomas Vachuska690e5f62014-11-09 08:26:47 -080078
Thomas Vachuska4830d392014-11-09 17:09:56 -080079 // Intents that are being monitored for the GUI
80 private static Map<IntentId, Long> intentsToMonitor = new ConcurrentHashMap<>();
Thomas Vachuskad1be50d2014-11-08 16:10:20 -080081
Thomas Vachuska7d638d32014-11-07 10:24:43 -080082 /**
83 * Creates a new web-socket for serving data to GUI topology view.
84 *
85 * @param directory service directory
86 */
87 public TopologyWebSocket(ServiceDirectory directory) {
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080088 super(directory);
Thomas Vachuska4830d392014-11-09 17:09:56 -080089 appId = directory.get(CoreService.class).registerApplication(APP_ID);
Thomas Vachuska7d638d32014-11-07 10:24:43 -080090 }
91
92 @Override
93 public void onOpen(Connection connection) {
94 this.connection = connection;
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080095 addListeners();
Thomas Vachuska7d638d32014-11-07 10:24:43 -080096
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080097 sendAllInstances();
Thomas Vachuska690e5f62014-11-09 08:26:47 -080098 sendAllDevices();
99 sendAllLinks();
Thomas Vachuska4830d392014-11-09 17:09:56 -0800100 sendAllHosts();
101 }
102
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800103 @Override
104 public void onClose(int closeCode, String message) {
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800105 removeListeners();
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800106 }
107
108 @Override
109 public void onMessage(String data) {
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800110 try {
111 ObjectNode event = (ObjectNode) mapper.reader().readTree(data);
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800112 String type = string(event, "event", "unknown");
113 if (type.equals("showDetails")) {
114 showDetails(event);
115 } else if (type.equals("updateMeta")) {
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800116 updateMetaUi(event);
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800117 } else if (type.equals("requestPath")) {
Thomas Vachuska4830d392014-11-09 17:09:56 -0800118 createHostIntent(event);
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800119 } else if (type.equals("requestTraffic")) {
120 sendTraffic(event);
121 } else if (type.equals("cancelTraffic")) {
122 cancelTraffic(event);
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800123 }
Thomas Vachuska4830d392014-11-09 17:09:56 -0800124 } catch (Exception e) {
125 System.out.println("WTF?! " + data);
126 e.printStackTrace();
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800127 }
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800128 }
129
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800130 // Sends the specified data to the client.
131 private void sendMessage(ObjectNode data) {
132 try {
133 connection.sendMessage(data.toString());
134 } catch (IOException e) {
135 e.printStackTrace();
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800136 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800137 }
138
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800139 // Sends all controller nodes to the client as node-added messages.
140 private void sendAllInstances() {
141 for (ControllerNode node : clusterService.getNodes()) {
142 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800143 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800144 }
145
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800146 // Sends all devices to the client as device-added messages.
147 private void sendAllDevices() {
148 for (Device device : deviceService.getDevices()) {
149 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800150 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800151 }
152
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800153 // Sends all links to the client as link-added messages.
154 private void sendAllLinks() {
155 for (Link link : linkService.getLinks()) {
156 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800157 }
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800158 }
159
160 // Sends all hosts to the client as host-added messages.
161 private void sendAllHosts() {
162 for (Host host : hostService.getHosts()) {
163 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
164 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800165 }
166
167 // Sends back device or host details.
168 private void showDetails(ObjectNode event) {
169 ObjectNode payload = payload(event);
170 String type = string(payload, "type", "unknown");
171 if (type.equals("device")) {
172 sendMessage(deviceDetails(deviceId(string(payload, "id")),
173 number(event, "sid")));
174 } else if (type.equals("host")) {
175 sendMessage(hostDetails(hostId(string(payload, "id")),
176 number(event, "sid")));
177 }
178 }
179
Thomas Vachuska4830d392014-11-09 17:09:56 -0800180 // Creates host-to-host intent.
181 private void createHostIntent(ObjectNode event) {
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800182 ObjectNode payload = payload(event);
183 long id = number(event, "sid");
Thomas Vachuska4830d392014-11-09 17:09:56 -0800184 // TODO: add protection against device ids and non-existent hosts.
185 HostId one = hostId(string(payload, "one"));
186 HostId two = hostId(string(payload, "two"));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800187
Thomas Vachuska4830d392014-11-09 17:09:56 -0800188 HostToHostIntent hostIntent = new HostToHostIntent(appId, one, two,
189 DefaultTrafficSelector.builder().build(),
190 DefaultTrafficTreatment.builder().build());
191 intentsToMonitor.put(hostIntent.id(), number(event, "sid"));
192 intentService.submit(hostIntent);
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800193 }
194
195 // Sends traffic message.
196 private void sendTraffic(ObjectNode event) {
197 ObjectNode payload = payload(event);
198 long id = number(event, "sid");
199 IntentId intentId = IntentId.valueOf(payload.path("intentId").asLong());
200
201 if (payload != null) {
202 payload.put("traffic", true);
203 sendMessage(envelope("showPath", id, payload));
204 } else {
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800205 sendMessage(warning(id, "No path found"));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800206 }
207 }
208
209 // Cancels sending traffic messages.
210 private void cancelTraffic(ObjectNode event) {
211 // TODO: implement this
212 }
213
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800214
215 // Adds all internal listeners.
216 private void addListeners() {
217 clusterService.addListener(clusterListener);
218 deviceService.addListener(deviceListener);
219 linkService.addListener(linkListener);
220 hostService.addListener(hostListener);
221 mastershipService.addListener(mastershipListener);
222 intentService.addListener(intentListener);
223 }
224
225 // Removes all internal listeners.
226 private void removeListeners() {
227 clusterService.removeListener(clusterListener);
228 deviceService.removeListener(deviceListener);
229 linkService.removeListener(linkListener);
230 hostService.removeListener(hostListener);
231 mastershipService.removeListener(mastershipListener);
232 }
233
234 // Cluster event listener.
235 private class InternalClusterListener implements ClusterEventListener {
236 @Override
237 public void event(ClusterEvent event) {
238 sendMessage(instanceMessage(event));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800239 }
240 }
241
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800242 // Device event listener.
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800243 private class InternalDeviceListener implements DeviceListener {
244 @Override
245 public void event(DeviceEvent event) {
246 sendMessage(deviceMessage(event));
247 }
248 }
249
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800250 // Link event listener.
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800251 private class InternalLinkListener implements LinkListener {
252 @Override
253 public void event(LinkEvent event) {
254 sendMessage(linkMessage(event));
255 }
256 }
257
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800258 // Host event listener.
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800259 private class InternalHostListener implements HostListener {
260 @Override
261 public void event(HostEvent event) {
262 sendMessage(hostMessage(event));
263 }
264 }
265
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800266 // Mastership event listener.
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800267 private class InternalMastershipListener implements MastershipListener {
268 @Override
269 public void event(MastershipEvent event) {
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800270 // TODO: Is DeviceEvent.Type.DEVICE_MASTERSHIP_CHANGED the same?
Thomas Vachuskad472c6e2014-11-07 19:11:05 -0800271 }
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800272 }
Thomas Vachuska4830d392014-11-09 17:09:56 -0800273
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800274 // Intent event listener.
Thomas Vachuska4830d392014-11-09 17:09:56 -0800275 private class InternalIntentListener implements IntentListener {
276 @Override
277 public void event(IntentEvent event) {
278 Intent intent = event.subject();
279 Long sid = intentsToMonitor.get(intent.id());
280 if (sid != null) {
281 List<Intent> installable = intentService.getInstallableIntents(intent.id());
282 if (installable != null && !installable.isEmpty()) {
283 PathIntent pathIntent = (PathIntent) installable.iterator().next();
284 Path path = pathIntent.path();
285 ObjectNode payload = pathMessage(path).put("intentId", intent.id().toString());
286 sendMessage(envelope("showPath", sid, payload));
287 }
288 }
289 }
290 }
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800291
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800292}
293