Thomas Vachuska

Starting on STC monitor.

Change-Id: I279ef5f26a0e3a5a44c6f597be6c2980f8c955ed
...@@ -17,6 +17,7 @@ ssh $remote " ...@@ -17,6 +17,7 @@ ssh $remote "
17 cd /tmp/$ONOS_BITS 17 cd /tmp/$ONOS_BITS
18 bin/onos-service server 1>/tmp/onos.out 2>/tmp/onos.err & 18 bin/onos-service server 1>/tmp/onos.out 2>/tmp/onos.err &
19 19
20 - # Setup a symlink to allow other tools to work 20 + # Setup a few symlinks to allow other tools to work
21 sudo ln -s /tmp/$ONOS_BITS $ONOS_INSTALL_DIR 21 sudo ln -s /tmp/$ONOS_BITS $ONOS_INSTALL_DIR
22 + sudo ln -s /tmp/$ONOS_BITS/$KARAF_DIST/data/log $ONOS_INSTALL_DIR/log
22 " 23 "
......
...@@ -51,6 +51,22 @@ ...@@ -51,6 +51,22 @@
51 <groupId>commons-collections</groupId> 51 <groupId>commons-collections</groupId>
52 <artifactId>commons-collections</artifactId> 52 <artifactId>commons-collections</artifactId>
53 </dependency> 53 </dependency>
54 +
55 + <dependency>
56 + <groupId>org.eclipse.jetty</groupId>
57 + <artifactId>jetty-server</artifactId>
58 + <version>8.1.17.v20150415</version>
59 + </dependency>
60 + <dependency>
61 + <groupId>org.eclipse.jetty</groupId>
62 + <artifactId>jetty-servlet</artifactId>
63 + <version>8.1.17.v20150415</version>
64 + </dependency>
65 + <dependency>
66 + <groupId>org.eclipse.jetty</groupId>
67 + <artifactId>jetty-websocket</artifactId>
68 + <version>8.1.17.v20150415</version>
69 + </dependency>
54 </dependencies> 70 </dependencies>
55 71
56 <build> 72 <build>
...@@ -61,11 +77,22 @@ ...@@ -61,11 +77,22 @@
61 <version>2.3</version> 77 <version>2.3</version>
62 <configuration> 78 <configuration>
63 <transformers> 79 <transformers>
64 - <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> 80 + <transformer
81 + implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
65 <mainClass>org.onlab.stc.Main 82 <mainClass>org.onlab.stc.Main
66 </mainClass> 83 </mainClass>
67 </transformer> 84 </transformer>
68 </transformers> 85 </transformers>
86 + <filters>
87 + <filter>
88 + <artifact>*:*</artifact>
89 + <excludes>
90 + <exclude>META-INF/*.SF</exclude>
91 + <exclude>META-INF/*.DSA</exclude>
92 + <exclude>META-INF/*.RSA</exclude>
93 + </excludes>
94 + </filter>
95 + </filters>
69 </configuration> 96 </configuration>
70 <executions> 97 <executions>
71 <execution> 98 <execution>
......
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
16 package org.onlab.stc; 16 package org.onlab.stc;
17 17
18 import com.google.common.collect.ImmutableList; 18 import com.google.common.collect.ImmutableList;
19 +import org.eclipse.jetty.server.Server;
20 +import org.eclipse.jetty.servlet.ServletHandler;
21 +import org.eclipse.jetty.util.log.Logger;
19 import org.onlab.stc.Coordinator.Status; 22 import org.onlab.stc.Coordinator.Status;
20 23
21 import java.io.FileInputStream; 24 import java.io.FileInputStream;
...@@ -106,6 +109,9 @@ public final class Main { ...@@ -106,6 +109,9 @@ public final class Main {
106 coordinator = new Coordinator(scenario, compiler.processFlow(), 109 coordinator = new Coordinator(scenario, compiler.processFlow(),
107 compiler.logDir()); 110 compiler.logDir());
108 coordinator.addListener(delegate); 111 coordinator.addListener(delegate);
112 +
113 + startMonitorServer();
114 +
109 processCommand(); 115 processCommand();
110 116
111 } catch (FileNotFoundException e) { 117 } catch (FileNotFoundException e) {
...@@ -113,6 +119,20 @@ public final class Main { ...@@ -113,6 +119,20 @@ public final class Main {
113 } 119 }
114 } 120 }
115 121
122 + // Initiates a web-server for the monitor GUI.
123 + private static void startMonitorServer() {
124 + org.eclipse.jetty.util.log.Log.setLog(new NullLogger());
125 + Server server = new Server(9999);
126 + ServletHandler handler = new ServletHandler();
127 + server.setHandler(handler);
128 + handler.addServletWithMapping(MonitorWebSocketServlet.class, "/*");
129 + try {
130 + server.start();
131 + } catch (Exception e) {
132 + e.printStackTrace();
133 + }
134 + }
135 +
116 // Processes the appropriate command 136 // Processes the appropriate command
117 private void processCommand() { 137 private void processCommand() {
118 switch (command) { 138 switch (command) {
...@@ -224,4 +244,65 @@ public final class Main { ...@@ -224,4 +244,65 @@ public final class Main {
224 } 244 }
225 } 245 }
226 246
247 + // Logger to quiet Jetty down
248 + private static class NullLogger implements Logger {
249 + @Override
250 + public String getName() {
251 + return "quiet";
252 + }
253 +
254 + @Override
255 + public void warn(String msg, Object... args) {
256 + }
257 +
258 + @Override
259 + public void warn(Throwable thrown) {
260 + }
261 +
262 + @Override
263 + public void warn(String msg, Throwable thrown) {
264 + }
265 +
266 + @Override
267 + public void info(String msg, Object... args) {
268 + }
269 +
270 + @Override
271 + public void info(Throwable thrown) {
272 + }
273 +
274 + @Override
275 + public void info(String msg, Throwable thrown) {
276 + }
277 +
278 + @Override
279 + public boolean isDebugEnabled() {
280 + return false;
281 + }
282 +
283 + @Override
284 + public void setDebugEnabled(boolean enabled) {
285 + }
286 +
287 + @Override
288 + public void debug(String msg, Object... args) {
289 + }
290 +
291 + @Override
292 + public void debug(Throwable thrown) {
293 + }
294 +
295 + @Override
296 + public void debug(String msg, Throwable thrown) {
297 + }
298 +
299 + @Override
300 + public Logger getLogger(String name) {
301 + return this;
302 + }
303 +
304 + @Override
305 + public void ignore(Throwable ignored) {
306 + }
307 + }
227 } 308 }
......
1 +/*
2 + * Copyright 2015 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 + */
16 +package org.onlab.stc;
17 +
18 +import com.fasterxml.jackson.databind.ObjectMapper;
19 +import com.fasterxml.jackson.databind.node.ObjectNode;
20 +import org.eclipse.jetty.websocket.WebSocket;
21 +import org.slf4j.Logger;
22 +import org.slf4j.LoggerFactory;
23 +
24 +import java.io.IOException;
25 +
26 +/**
27 + * Web socket capable of interacting with the STC monitor GUI.
28 + */
29 +public class MonitorWebSocket implements WebSocket.OnTextMessage, WebSocket.OnControl {
30 +
31 + private static final Logger log = LoggerFactory.getLogger(MonitorWebSocket.class);
32 +
33 + private static final long MAX_AGE_MS = 30_000;
34 +
35 + private static final byte PING = 0x9;
36 + private static final byte PONG = 0xA;
37 + private static final byte[] PING_DATA = new byte[]{(byte) 0xde, (byte) 0xad};
38 +
39 + private Connection connection;
40 + private FrameConnection control;
41 +
42 + private final ObjectMapper mapper = new ObjectMapper();
43 +
44 + private long lastActive = System.currentTimeMillis();
45 +
46 + /**
47 + * Issues a close on the connection.
48 + */
49 + synchronized void close() {
50 + destroyHandlers();
51 + if (connection.isOpen()) {
52 + connection.close();
53 + }
54 + }
55 +
56 + /**
57 + * Indicates if this connection is idle.
58 + *
59 + * @return true if idle or closed
60 + */
61 + synchronized boolean isIdle() {
62 + long quietFor = System.currentTimeMillis() - lastActive;
63 + boolean idle = quietFor > MAX_AGE_MS;
64 + if (idle || (connection != null && !connection.isOpen())) {
65 + log.debug("IDLE (or closed) websocket [{} ms]", quietFor);
66 + return true;
67 + } else if (connection != null) {
68 + try {
69 + control.sendControl(PING, PING_DATA, 0, PING_DATA.length);
70 + } catch (IOException e) {
71 + log.warn("Unable to send ping message due to: ", e);
72 + }
73 + }
74 + return false;
75 + }
76 +
77 + @Override
78 + public void onOpen(Connection connection) {
79 + this.connection = connection;
80 + this.control = (FrameConnection) connection;
81 + try {
82 + createHandlers();
83 + log.info("GUI client connected");
84 +
85 + } catch (Exception e) {
86 + log.warn("Unable to open monitor connection: {}", e);
87 + this.connection.close();
88 + this.connection = null;
89 + this.control = null;
90 + }
91 + }
92 +
93 + @Override
94 + public synchronized void onClose(int closeCode, String message) {
95 + destroyHandlers();
96 + log.info("GUI client disconnected [close-code={}, message={}]",
97 + closeCode, message);
98 + }
99 +
100 + @Override
101 + public boolean onControl(byte controlCode, byte[] data, int offset, int length) {
102 + lastActive = System.currentTimeMillis();
103 + return true;
104 + }
105 +
106 + @Override
107 + public void onMessage(String data) {
108 + lastActive = System.currentTimeMillis();
109 + try {
110 + ObjectNode message = (ObjectNode) mapper.reader().readTree(data);
111 + // TODO:
112 + log.info("Got message: {}", message);
113 + } catch (Exception e) {
114 + log.warn("Unable to parse GUI message {} due to {}", data, e);
115 + log.debug("Boom!!!", e);
116 + }
117 + }
118 +
119 + public synchronized void sendMessage(ObjectNode message) {
120 + try {
121 + if (connection.isOpen()) {
122 + connection.sendMessage(message.toString());
123 + }
124 + } catch (IOException e) {
125 + log.warn("Unable to send message {} to GUI due to {}", message, e);
126 + log.debug("Boom!!!", e);
127 + }
128 + }
129 +
130 + public synchronized void sendMessage(String type, long sid, ObjectNode payload) {
131 + ObjectNode message = mapper.createObjectNode();
132 + message.put("event", type);
133 + if (sid > 0) {
134 + message.put("sid", sid);
135 + }
136 + message.set("payload", payload);
137 + sendMessage(message);
138 +
139 + }
140 +
141 + // Creates new message handlers.
142 + private synchronized void createHandlers() {
143 + }
144 +
145 + // Destroys message handlers.
146 + private synchronized void destroyHandlers() {
147 + }
148 +
149 +}
150 +
1 +/*
2 + * Copyright 2015 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 + */
16 +package org.onlab.stc;
17 +
18 +import com.google.common.io.ByteStreams;
19 +import com.google.common.net.MediaType;
20 +import org.eclipse.jetty.websocket.WebSocket;
21 +import org.eclipse.jetty.websocket.WebSocketServlet;
22 +
23 +import javax.servlet.ServletException;
24 +import javax.servlet.http.HttpServletRequest;
25 +import javax.servlet.http.HttpServletResponse;
26 +import java.io.IOException;
27 +import java.io.InputStream;
28 +import java.util.HashSet;
29 +import java.util.Iterator;
30 +import java.util.Set;
31 +import java.util.Timer;
32 +import java.util.TimerTask;
33 +
34 +/**
35 + * Web socket servlet capable of creating web sockets for the STC monitor.
36 + */
37 +public class MonitorWebSocketServlet extends WebSocketServlet {
38 +
39 + private static final long PING_DELAY_MS = 5000;
40 + private static final String DOT = ".";
41 +
42 + private static MonitorWebSocketServlet instance;
43 +
44 + private final Set<MonitorWebSocket> sockets = new HashSet<>();
45 + private final Timer timer = new Timer();
46 + private final TimerTask pruner = new Pruner();
47 +
48 + /**
49 + * Closes all currently open monitor web-sockets.
50 + */
51 + public static void closeAll() {
52 + if (instance != null) {
53 + instance.sockets.forEach(MonitorWebSocket::close);
54 + instance.sockets.clear();
55 + }
56 + }
57 +
58 + @Override
59 + public void init() throws ServletException {
60 + super.init();
61 + instance = this;
62 + System.out.println("Yo!!!!");
63 + timer.schedule(pruner, PING_DELAY_MS, PING_DELAY_MS);
64 + }
65 +
66 + @Override
67 + protected void doGet(HttpServletRequest req, HttpServletResponse resp)
68 + throws ServletException, IOException {
69 + String uri = req.getRequestURI();
70 + uri = uri.length() <= 1 ? "/index.html" : uri;
71 + InputStream resource = getClass().getResourceAsStream(uri);
72 + if (resource == null) {
73 + resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
74 + } else {
75 + byte[] entity = ByteStreams.toByteArray(resource);
76 + resp.setStatus(HttpServletResponse.SC_OK);
77 + resp.setContentType(contentType(uri).toString());
78 + resp.setContentLength(entity.length);
79 + resp.getOutputStream().write(entity);
80 + }
81 + }
82 +
83 + private MediaType contentType(String uri) {
84 + int sep = uri.lastIndexOf(DOT);
85 + String ext = sep > 0 ? uri.substring(sep + 1) : null;
86 + return ext == null ? MediaType.APPLICATION_BINARY :
87 + ext.equals("html") ? MediaType.HTML_UTF_8 :
88 + ext.equals("js") ? MediaType.JAVASCRIPT_UTF_8 :
89 + ext.equals("css") ? MediaType.CSS_UTF_8 :
90 + MediaType.APPLICATION_BINARY;
91 + }
92 +
93 + @Override
94 + public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
95 + System.out.println("Wazup????");
96 + MonitorWebSocket socket = new MonitorWebSocket();
97 + synchronized (sockets) {
98 + sockets.add(socket);
99 + }
100 + return socket;
101 + }
102 +
103 + // Task for pruning web-sockets that are idle.
104 + private class Pruner extends TimerTask {
105 + @Override
106 + public void run() {
107 + synchronized (sockets) {
108 + Iterator<MonitorWebSocket> it = sockets.iterator();
109 + while (it.hasNext()) {
110 + MonitorWebSocket socket = it.next();
111 + if (socket.isIdle()) {
112 + it.remove();
113 + socket.close();
114 + }
115 + }
116 + }
117 + }
118 + }
119 +}
1 +<!DOCTYPE html>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<html>
18 +<head lang="en">
19 + <meta charset="UTF-8">
20 + <title>Scenario Test Coordinator</title>
21 +
22 + <script src="stc.js"></script>
23 + <link rel="stylesheet" href="stc.css">
24 +</head>
25 +<body>
26 +<h1>Scenario Test Coordinator</h1>
27 +
28 +</body>
29 +</html>
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2015 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 + */
16 +
17 +.body {
18 + font-family: Helvetica, Arial;
19 +}
1 +/*
2 + * Copyright 2015 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 + */
16 +(function () {
17 +
18 +})();
...\ No newline at end of file ...\ No newline at end of file
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
39 <dependency> 39 <dependency>
40 <groupId>org.eclipse.jetty</groupId> 40 <groupId>org.eclipse.jetty</groupId>
41 <artifactId>jetty-websocket</artifactId> 41 <artifactId>jetty-websocket</artifactId>
42 - <version>8.1.15.v20140411</version> 42 + <version>8.1.17.v20150415</version>
43 </dependency> 43 </dependency>
44 <dependency> 44 <dependency>
45 <groupId>javax.servlet</groupId> 45 <groupId>javax.servlet</groupId>
......