Thomas Vachuska

Adding code to enable GUI failover.

Change-Id: I8423f17349411d24332db8670840438d0d8ec8ba
...@@ -29,4 +29,13 @@ public interface UiConnection { ...@@ -29,4 +29,13 @@ public interface UiConnection {
29 */ 29 */
30 void sendMessage(ObjectNode message); 30 void sendMessage(ObjectNode message);
31 31
32 + /**
33 + * Composes a message into JSON and sends it to the user interface client.
34 + *
35 + * @param type message type
36 + * @param sid message sequence number
37 + * @param payload message payload
38 + */
39 + void sendMessage(String type, long sid, ObjectNode payload);
40 +
32 } 41 }
...\ No newline at end of file ...\ No newline at end of file
......
1 +# Bare metal cluster with rearranged nodes
2 +
3 +# Use the 10G NIC for cluster communications
4 +export ONOS_NIC="10.254.1.*"
5 +
6 +# ONOS Test proxy
7 +export OCT=10.254.1.200
8 +
9 +# Use the 1G NICs for external access
10 +export OC1=10.254.1.207
11 +export OC2=10.254.1.202
12 +export OC3=10.254.1.203
13 +export OC4=10.254.1.204
14 +export OC5=10.254.1.206
15 +
16 +export OCI=${OC1}
17 +
18 +export ONOS_FEATURES=webconsole,onos-api,onos-core,onos-cli,onos-rest,onos-null
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.onosproject.ui.impl;
17 -
18 -import com.fasterxml.jackson.databind.ObjectMapper;
19 -import com.fasterxml.jackson.databind.node.ArrayNode;
20 -import com.fasterxml.jackson.databind.node.ObjectNode;
21 -import com.google.common.collect.ImmutableSet;
22 -import org.onlab.osgi.ServiceDirectory;
23 -import org.onosproject.cluster.ClusterService;
24 -import org.onosproject.cluster.ControllerNode;
25 -import org.onosproject.ui.UiConnection;
26 -import org.onosproject.ui.UiMessageHandler;
27 -
28 -import java.util.ArrayList;
29 -import java.util.Collections;
30 -import java.util.Comparator;
31 -import java.util.List;
32 -
33 -
34 -/**
35 - * Facility for creating and sending initial bootstrap message to the GUI.
36 - */
37 -public class BootstrapMessageHandler extends UiMessageHandler {
38 -
39 - private static final String BOOTSTRAP = "bootstrap";
40 -
41 - private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
42 - new Comparator<ControllerNode>() {
43 - @Override
44 - public int compare(ControllerNode o1, ControllerNode o2) {
45 - return o1.id().toString().compareTo(o2.id().toString());
46 - }
47 - };
48 -
49 - private final ObjectMapper mapper = new ObjectMapper();
50 -
51 - private ClusterService clusterService;
52 -
53 - // TODO: ClusterEventListener - update GUI when instances come or go...
54 -
55 - /**
56 - * Creates a new bootstrap message handler for bootstrapping the GUI.
57 - */
58 - protected BootstrapMessageHandler() {
59 - super(ImmutableSet.of(BOOTSTRAP));
60 - }
61 -
62 - @Override
63 - public void init(UiConnection connection, ServiceDirectory directory) {
64 - super.init(connection, directory);
65 - clusterService = directory.get(ClusterService.class);
66 -
67 - // Obtain list of cluster nodes and send bootstrap message to GUI
68 - List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
69 - Collections.sort(nodes, NODE_COMPARATOR);
70 -
71 - ObjectNode payload = mapper.createObjectNode();
72 -
73 - ArrayNode anode = mapper.createArrayNode();
74 - for (ControllerNode node : nodes) {
75 - anode.add(clusterNodeData(node));
76 - }
77 - payload.set("instances", anode);
78 - connection.sendMessage(envelope(BOOTSTRAP, 0, payload));
79 - }
80 -
81 - private ObjectNode clusterNodeData(ControllerNode node) {
82 - return mapper.createObjectNode()
83 - .put("id", node.id().toString())
84 - .put("ip", node.ip().toString())
85 - .put("uiAttached", node.equals(clusterService.getLocalNode()));
86 - }
87 -
88 -
89 - @Override
90 - public void process(ObjectNode message) {
91 - // We registered for "bootstrap" events, but we don't expect
92 - // the GUI to send us any; it was just that we had to define a
93 - // non-empty set of events that we handle, in the constructor.
94 - }
95 -
96 -}
...@@ -305,7 +305,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -305,7 +305,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
305 .put("id", node.id().toString()) 305 .put("id", node.id().toString())
306 .put("ip", node.ip().toString()) 306 .put("ip", node.ip().toString())
307 .put("online", clusterService.getState(node.id()) == ACTIVE) 307 .put("online", clusterService.getState(node.id()) == ACTIVE)
308 - .put("uiAttached", event.subject().equals(clusterService.getLocalNode())) 308 + .put("uiAttached", node.equals(clusterService.getLocalNode()))
309 .put("switches", switchCount); 309 .put("switches", switchCount);
310 310
311 ArrayNode labels = mapper.createArrayNode(); 311 ArrayNode labels = mapper.createArrayNode();
......
...@@ -61,7 +61,6 @@ public class UiExtensionManager implements UiExtensionService { ...@@ -61,7 +61,6 @@ public class UiExtensionManager implements UiExtensionService {
61 new UiView("device", "Devices")); 61 new UiView("device", "Devices"));
62 UiMessageHandlerFactory messageHandlerFactory = 62 UiMessageHandlerFactory messageHandlerFactory =
63 () -> ImmutableList.of( 63 () -> ImmutableList.of(
64 - new BootstrapMessageHandler(),
65 new TopologyViewMessageHandler() 64 new TopologyViewMessageHandler()
66 ); 65 );
67 return new UiExtension(coreViews, messageHandlerFactory, "core", 66 return new UiExtension(coreViews, messageHandlerFactory, "core",
......
...@@ -16,9 +16,12 @@ ...@@ -16,9 +16,12 @@
16 package org.onosproject.ui.impl; 16 package org.onosproject.ui.impl;
17 17
18 import com.fasterxml.jackson.databind.ObjectMapper; 18 import com.fasterxml.jackson.databind.ObjectMapper;
19 +import com.fasterxml.jackson.databind.node.ArrayNode;
19 import com.fasterxml.jackson.databind.node.ObjectNode; 20 import com.fasterxml.jackson.databind.node.ObjectNode;
20 import org.eclipse.jetty.websocket.WebSocket; 21 import org.eclipse.jetty.websocket.WebSocket;
21 import org.onlab.osgi.ServiceDirectory; 22 import org.onlab.osgi.ServiceDirectory;
23 +import org.onosproject.cluster.ClusterService;
24 +import org.onosproject.cluster.ControllerNode;
22 import org.onosproject.ui.UiConnection; 25 import org.onosproject.ui.UiConnection;
23 import org.onosproject.ui.UiExtensionService; 26 import org.onosproject.ui.UiExtensionService;
24 import org.onosproject.ui.UiMessageHandler; 27 import org.onosproject.ui.UiMessageHandler;
...@@ -99,6 +102,7 @@ public class UiWebSocket ...@@ -99,6 +102,7 @@ public class UiWebSocket
99 this.connection = connection; 102 this.connection = connection;
100 this.control = (FrameConnection) connection; 103 this.control = (FrameConnection) connection;
101 createHandlers(); 104 createHandlers();
105 + sendInstanceData();
102 } 106 }
103 107
104 @Override 108 @Override
...@@ -143,6 +147,18 @@ public class UiWebSocket ...@@ -143,6 +147,18 @@ public class UiWebSocket
143 } 147 }
144 } 148 }
145 149
150 + @Override
151 + public void sendMessage(String type, long sid, ObjectNode payload) {
152 + ObjectNode message = mapper.createObjectNode();
153 + message.put("event", type);
154 + if (sid > 0) {
155 + message.put("sid", sid);
156 + }
157 + message.set("payload", payload);
158 + sendMessage(message);
159 +
160 + }
161 +
146 // Creates new message handlers. 162 // Creates new message handlers.
147 private void createHandlers() { 163 private void createHandlers() {
148 handlers = new HashMap<>(); 164 handlers = new HashMap<>();
...@@ -163,5 +179,24 @@ public class UiWebSocket ...@@ -163,5 +179,24 @@ public class UiWebSocket
163 handlers.forEach((type, handler) -> handler.destroy()); 179 handlers.forEach((type, handler) -> handler.destroy());
164 handlers.clear(); 180 handlers.clear();
165 } 181 }
182 +
183 + // Sends cluster node/instance information to allow GUI to fail-over.
184 + private void sendInstanceData() {
185 + ClusterService service = directory.get(ClusterService.class);
186 + ArrayNode instances = mapper.createArrayNode();
187 +
188 + for (ControllerNode node : service.getNodes()) {
189 + ObjectNode instance = mapper.createObjectNode()
190 + .put("id", node.id().toString())
191 + .put("ip", node.ip().toString())
192 + .put("uiAttached", node.equals(service.getLocalNode()));
193 + instances.add(instance);
194 + }
195 +
196 + ObjectNode payload = mapper.createObjectNode();
197 + payload.set("instances", instances);
198 + sendMessage("onosInstances", 0, payload);
199 + }
200 +
166 } 201 }
167 202
......
...@@ -29,8 +29,14 @@ ...@@ -29,8 +29,14 @@
29 sid = 0, // event sequence identifier 29 sid = 0, // event sequence identifier
30 handlers = {}, // event handler bindings 30 handlers = {}, // event handler bindings
31 pendingEvents = [], // events TX'd while socket not up 31 pendingEvents = [], // events TX'd while socket not up
32 - url; // web socket URL 32 + url, // web socket URL
33 + instances = [];
33 34
35 + var builtinHandlers = {
36 + onosInstances: function (data) {
37 + instances = data.instances;
38 + }
39 + }
34 40
35 // ========================== 41 // ==========================
36 // === Web socket callbacks 42 // === Web socket callbacks
...@@ -186,6 +192,11 @@ ...@@ -186,6 +192,11 @@
186 wsock = _wsock_; 192 wsock = _wsock_;
187 vs = _vs_; 193 vs = _vs_;
188 194
195 + // Bind instance handlers
196 + bindHandlers({
197 + onosInstances: builtinHandlers
198 + });
199 +
189 return { 200 return {
190 resetSid: resetSid, 201 resetSid: resetSid,
191 createWebSocket: createWebSocket, 202 createWebSocket: createWebSocket,
......