GUI -- Continued work on supporting GUI failover. WIP
- Thomas to complete. Change-Id: I4ed40a0d5b0b48cd1d9fac175a1f66e81df7dacf
Showing
3 changed files
with
64 additions
and
26 deletions
| ... | @@ -33,25 +33,25 @@ | ... | @@ -33,25 +33,25 @@ |
| 33 | return secure ? protocol + 's' : protocol; | 33 | return secure ? protocol + 's' : protocol; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | - function urlBase(protocol, port) { | 36 | + function urlBase(protocol, port, host) { |
| 37 | return matchSecure(protocol) + '://' + | 37 | return matchSecure(protocol) + '://' + |
| 38 | - $loc.host() + ':' + (port || $loc.port()); | 38 | + (host || $loc.host()) + ':' + (port || $loc.port()); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | function httpPrefix(suffix) { | 41 | function httpPrefix(suffix) { |
| 42 | return urlBase('http') + suffix; | 42 | return urlBase('http') + suffix; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | - function wsPrefix(suffix, wsport) { | 45 | + function wsPrefix(suffix, wsport, host) { |
| 46 | - return urlBase('ws', wsport) + suffix; | 46 | + return urlBase('ws', wsport, host) + suffix; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | function rsUrl(path) { | 49 | function rsUrl(path) { |
| 50 | return httpPrefix(rsSuffix) + path; | 50 | return httpPrefix(rsSuffix) + path; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | - function wsUrl(path, wsport) { | 53 | + function wsUrl(path, wsport, host) { |
| 54 | - return wsPrefix(wsSuffix, wsport) + path; | 54 | + return wsPrefix(wsSuffix, wsport, host) + path; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | return { | 57 | return { | ... | ... |
| ... | @@ -24,30 +24,45 @@ | ... | @@ -24,30 +24,45 @@ |
| 24 | var $log, $loc, fs, ufs, wsock, vs; | 24 | var $log, $loc, fs, ufs, wsock, vs; |
| 25 | 25 | ||
| 26 | // internal state | 26 | // internal state |
| 27 | - var ws = null, // web socket reference | 27 | + var webSockOpts, // web socket options |
| 28 | + ws = null, // web socket reference | ||
| 28 | wsUp = false, // web socket is good to go | 29 | wsUp = false, // web socket is good to go |
| 29 | sid = 0, // event sequence identifier | 30 | sid = 0, // event sequence identifier |
| 30 | handlers = {}, // event handler bindings | 31 | handlers = {}, // event handler bindings |
| 31 | pendingEvents = [], // events TX'd while socket not up | 32 | pendingEvents = [], // events TX'd while socket not up |
| 32 | url, // web socket URL | 33 | url, // web socket URL |
| 33 | - instances = []; | 34 | + clusterNodes = [], // ONOS instances data for failover |
| 35 | + clusterIndex = -1, // the instance to which we are connected | ||
| 36 | + connectRetries = 0; | ||
| 37 | + | ||
| 38 | + // ======================= | ||
| 39 | + // === Bootstrap Handler | ||
| 34 | 40 | ||
| 35 | var builtinHandlers = { | 41 | var builtinHandlers = { |
| 36 | - onosInstances: function (data) { | 42 | + bootstrap: function (data) { |
| 37 | - instances = data.instances; | 43 | + clusterNodes = data.instances; |
| 38 | - } | 44 | + clusterNodes.forEach(function (d, i) { |
| 39 | - } | 45 | + if (d.uiAttached) { |
| 46 | + clusterIndex = i; | ||
| 47 | + } | ||
| 48 | + }); | ||
| 49 | + } | ||
| 50 | + }; | ||
| 40 | 51 | ||
| 41 | // ========================== | 52 | // ========================== |
| 42 | // === Web socket callbacks | 53 | // === Web socket callbacks |
| 43 | 54 | ||
| 44 | function handleOpen() { | 55 | function handleOpen() { |
| 45 | $log.info('Web socket open'); | 56 | $log.info('Web socket open'); |
| 57 | + vs.hide(); | ||
| 58 | + | ||
| 46 | $log.debug('Sending ' + pendingEvents.length + ' pending event(s)...'); | 59 | $log.debug('Sending ' + pendingEvents.length + ' pending event(s)...'); |
| 47 | pendingEvents.forEach(function (ev) { | 60 | pendingEvents.forEach(function (ev) { |
| 48 | _send(ev); | 61 | _send(ev); |
| 49 | }); | 62 | }); |
| 50 | pendingEvents = []; | 63 | pendingEvents = []; |
| 64 | + | ||
| 65 | + connectRetries = 0; | ||
| 51 | wsUp = true; | 66 | wsUp = true; |
| 52 | } | 67 | } |
| 53 | 68 | ||
| ... | @@ -76,23 +91,42 @@ | ... | @@ -76,23 +91,42 @@ |
| 76 | } | 91 | } |
| 77 | 92 | ||
| 78 | function handleClose() { | 93 | function handleClose() { |
| 94 | + var gsucc; | ||
| 95 | + | ||
| 79 | $log.info('Web socket closed'); | 96 | $log.info('Web socket closed'); |
| 80 | wsUp = false; | 97 | wsUp = false; |
| 81 | 98 | ||
| 82 | - // FIXME: implement controller failover logic | 99 | + if (gsucc = findGuiSuccessor()) { |
| 83 | - | 100 | + createWebSocket(webSockOpts, gsucc); |
| 84 | - // If no controllers left to contact, show the Veil... | 101 | + } else { |
| 85 | - vs.show([ | 102 | + // If no controllers left to contact, show the Veil... |
| 86 | - 'Oops!', | 103 | + vs.show([ |
| 87 | - 'Web-socket connection to server closed...', | 104 | + 'Oops!', |
| 88 | - 'Try refreshing the page.' | 105 | + 'Web-socket connection to server closed...', |
| 89 | - ]); | 106 | + 'Try refreshing the page.' |
| 107 | + ]); | ||
| 108 | + } | ||
| 90 | } | 109 | } |
| 91 | 110 | ||
| 92 | 111 | ||
| 93 | // ============================== | 112 | // ============================== |
| 94 | // === Private Helper Functions | 113 | // === Private Helper Functions |
| 95 | 114 | ||
| 115 | + function findGuiSuccessor() { | ||
| 116 | + var ncn = clusterNodes.length, | ||
| 117 | + ip = undefined, | ||
| 118 | + node; | ||
| 119 | + | ||
| 120 | + while (connectRetries < ncn && !ip) { | ||
| 121 | + connectRetries++; | ||
| 122 | + clusterIndex = (clusterIndex + 1) % ncn; | ||
| 123 | + node = clusterNodes[clusterIndex]; | ||
| 124 | + ip = node && node.ip; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + return ip; | ||
| 128 | + } | ||
| 129 | + | ||
| 96 | function _send(ev) { | 130 | function _send(ev) { |
| 97 | $log.debug(' *Tx* >> ', ev.event, ev.payload); | 131 | $log.debug(' *Tx* >> ', ev.event, ev.payload); |
| 98 | ws.send(JSON.stringify(ev)); | 132 | ws.send(JSON.stringify(ev)); |
| ... | @@ -109,10 +143,12 @@ | ... | @@ -109,10 +143,12 @@ |
| 109 | 143 | ||
| 110 | // Currently supported opts: | 144 | // Currently supported opts: |
| 111 | // wsport: web socket port (other than default 8181) | 145 | // wsport: web socket port (other than default 8181) |
| 112 | - function createWebSocket(opts) { | 146 | + // server: if defined, is the server address to use |
| 147 | + function createWebSocket(opts, server) { | ||
| 113 | var wsport = (opts && opts.wsport) || null; | 148 | var wsport = (opts && opts.wsport) || null; |
| 149 | + webSockOpts = opts; // preserved for future calls | ||
| 114 | 150 | ||
| 115 | - url = ufs.wsUrl('core', wsport); | 151 | + url = ufs.wsUrl('core', wsport, server); |
| 116 | 152 | ||
| 117 | $log.debug('Attempting to open websocket to: ' + url); | 153 | $log.debug('Attempting to open websocket to: ' + url); |
| 118 | ws = wsock.newWebSocket(url); | 154 | ws = wsock.newWebSocket(url); |
| ... | @@ -192,10 +228,7 @@ | ... | @@ -192,10 +228,7 @@ |
| 192 | wsock = _wsock_; | 228 | wsock = _wsock_; |
| 193 | vs = _vs_; | 229 | vs = _vs_; |
| 194 | 230 | ||
| 195 | - // Bind instance handlers | 231 | + bindHandlers(builtinHandlers); |
| 196 | - bindHandlers({ | ||
| 197 | - onosInstances: builtinHandlers | ||
| 198 | - }); | ||
| 199 | 232 | ||
| 200 | return { | 233 | return { |
| 201 | resetSid: resetSid, | 234 | resetSid: resetSid, | ... | ... |
| ... | @@ -81,4 +81,9 @@ describe('factory: fw/remote/urlfn.js', function () { | ... | @@ -81,4 +81,9 @@ describe('factory: fw/remote/urlfn.js', function () { |
| 81 | setLoc('http', 'foo', '123'); | 81 | setLoc('http', 'foo', '123'); |
| 82 | expect(ufs.wsUrl('xyyzy', 456)).toEqual('ws://foo:456/onos/ui/websock/xyyzy'); | 82 | expect(ufs.wsUrl('xyyzy', 456)).toEqual('ws://foo:456/onos/ui/websock/xyyzy'); |
| 83 | }); | 83 | }); |
| 84 | + | ||
| 85 | + it('should allow us to define an alternate host', function () { | ||
| 86 | + setLoc('http', 'foo', '123'); | ||
| 87 | + expect(ufs.wsUrl('core', 456, 'bar')).toEqual('ws://bar:456/onos/ui/websock/core'); | ||
| 88 | + }); | ||
| 84 | }); | 89 | }); | ... | ... |
-
Please register or login to post a comment