From ca867ac7867f7952a9eb8fce31e4dc9c8166e5fb Mon Sep 17 00:00:00 2001 From: Simon Hunt Date: Fri, 28 Nov 2014 18:07:35 -0800 Subject: [PATCH] GUI -- [ONOS-310] - Implemented removeDevice(). - when a device is removed, we also removed any attached hosts and links. - cleaned up animations, etc. Change-Id: Ifc82f7f60dd8c7bbe4d32beeb923969713492430 --- .../webapp/json/ev/traffic/ev_18_onos.json | 8 +- .../webapp/json/ev/traffic/ev_20_onos.json | 17 ++ .../webapp/json/ev/traffic/ev_21_onos.json | 17 ++ .../webapp/json/ev/traffic/ev_22_onos.json | 17 ++ .../webapp/json/ev/traffic/ev_23_onos.json | 17 ++ .../webapp/json/ev/traffic/ev_24_onos.json | 17 ++ web/gui/src/main/webapp/topo.js | 200 ++++++++++++------ 7 files changed, 224 insertions(+), 69 deletions(-) create mode 100644 web/gui/src/main/webapp/json/ev/traffic/ev_20_onos.json create mode 100644 web/gui/src/main/webapp/json/ev/traffic/ev_21_onos.json create mode 100644 web/gui/src/main/webapp/json/ev/traffic/ev_22_onos.json create mode 100644 web/gui/src/main/webapp/json/ev/traffic/ev_23_onos.json create mode 100644 web/gui/src/main/webapp/json/ev/traffic/ev_24_onos.json diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_18_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_18_onos.json index 7ecaa886d1..3b3e921791 100644 --- a/web/gui/src/main/webapp/json/ev/traffic/ev_18_onos.json +++ b/web/gui/src/main/webapp/json/ev/traffic/ev_18_onos.json @@ -28,8 +28,8 @@ "labels": [""] }, { - "class": "primary optical", - "traffic": false, + "class": "animated optical", + "traffic": true, "links": [ "of:0000ffffffff0008/4-of:0000ffffffffff08/1" ], @@ -44,8 +44,8 @@ "labels": [""] }, { - "class": "animated optical", - "traffic": true, + "class": "primary optical", + "traffic": false, "links": [ "of:0000ffffffffff08/4-of:0000ffffffffff03/1" ], diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_20_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_20_onos.json new file mode 100644 index 0000000000..2f9d567cdf --- /dev/null +++ b/web/gui/src/main/webapp/json/ev/traffic/ev_20_onos.json @@ -0,0 +1,17 @@ +{ + "event": "updateDevice", + "payload": { + "id": "of:0000ffffffff0007", + "type": "switch", + "online": false, + "labels": [ + "", + "sw-7", + "0000ffffffff0007" + ], + "metaUi": { + "x": 530, + "y": 330 + } + } +} diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_21_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_21_onos.json new file mode 100644 index 0000000000..a409b6141d --- /dev/null +++ b/web/gui/src/main/webapp/json/ev/traffic/ev_21_onos.json @@ -0,0 +1,17 @@ +{ + "event": "updateDevice", + "payload": { + "id": "of:0000ffffffff0007", + "type": "switch", + "online": true, + "labels": [ + "", + "sw-7", + "0000ffffffff0007" + ], + "metaUi": { + "x": 530, + "y": 330 + } + } +} diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_22_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_22_onos.json new file mode 100644 index 0000000000..0478da1deb --- /dev/null +++ b/web/gui/src/main/webapp/json/ev/traffic/ev_22_onos.json @@ -0,0 +1,17 @@ +{ + "event": "removeDevice", + "payload": { + "id": "of:0000ffffffff0008", + "type": "switch", + "online": false, + "labels": [ + "", + "sw-8", + "0000ffffffff0008" + ], + "metaUi": { + "x": 734, + "y": 477 + } + } +} diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_23_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_23_onos.json new file mode 100644 index 0000000000..0a4c85396e --- /dev/null +++ b/web/gui/src/main/webapp/json/ev/traffic/ev_23_onos.json @@ -0,0 +1,17 @@ +{ + "event": "addDevice", + "payload": { + "id": "of:0000ffffffff0008", + "type": "switch", + "online": true, + "labels": [ + "", + "sw-8", + "0000ffffffff0008" + ], + "metaUi": { + "x": 734, + "y": 477 + } + } +} diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_24_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_24_onos.json new file mode 100644 index 0000000000..69fc2bcb7b --- /dev/null +++ b/web/gui/src/main/webapp/json/ev/traffic/ev_24_onos.json @@ -0,0 +1,17 @@ +{ + "event": "removeHost", + "payload": { + "id": "0E:2A:69:30:13:88/-1", + "ingress": "0E:2A:69:30:13:88/-1/0-of:0000ffffffff0007/101", + "egress": "of:0000ffffffff0007/101-0E:2A:69:30:13:86/-1/0", + "cp": { + "device": "of:0000ffffffff0007", + "port": 101 + }, + "labels": [ + "4.5.7.6", + "0E:2A:69:30:13:88" + ], + "props": {} + } +} diff --git a/web/gui/src/main/webapp/topo.js b/web/gui/src/main/webapp/topo.js index e233f8c78e..5b46e3d6d8 100644 --- a/web/gui/src/main/webapp/topo.js +++ b/web/gui/src/main/webapp/topo.js @@ -596,7 +596,7 @@ updateHost: updateHost, removeInstance: removeInstance, - removeDevice: stillToImplement, + removeDevice: removeDevice, removeLink: removeLink, removeHost: removeHost, @@ -621,9 +621,17 @@ function addDevice(data) { evTrace(data); var device = data.payload, - nodeData = createDeviceNode(device); - network.nodes.push(nodeData); - network.lookup[nodeData.id] = nodeData; + id = device.id, + d; + + if (network.lookup[id]) { + logicError('Device already added: ' + id); + return; + } + + d = createDeviceNode(device); + network.nodes.push(d); + network.lookup[id] = d; updateNodes(); network.force.start(); } @@ -633,24 +641,24 @@ var link = data.payload, result = findLink(link, 'add'), bad = result.badLogic, - ldata = result.ldata; + d = result.ldata; if (bad) { logicError(bad + ': ' + link.id); return; } - if (ldata) { + if (d) { // we already have a backing store link for src/dst nodes - addLinkUpdate(ldata, link); + addLinkUpdate(d, link); return; } // no backing store link yet - ldata = createLink(link); - if (ldata) { - network.links.push(ldata); - network.lookup[ldata.key] = ldata; + d = createLink(link); + if (d) { + network.links.push(d); + network.lookup[d.key] = d; updateLinks(); network.force.start(); } @@ -659,18 +667,26 @@ function addHost(data) { evTrace(data); var host = data.payload, - node = createHostNode(host), + id = host.id, + d, lnk; - network.nodes.push(node); - network.lookup[host.id] = node; + + if (network.lookup[id]) { + logicError('Host already added: ' + id); + return; + } + + d = createHostNode(host); + network.nodes.push(d); + network.lookup[host.id] = d; updateNodes(); lnk = createHostLink(host); if (lnk) { - node.linkData = lnk; // cache ref on its host + d.linkData = lnk; // cache ref on its host network.links.push(lnk); - network.lookup[host.ingress] = lnk; - network.lookup[host.egress] = lnk; + network.lookup[d.ingress] = lnk; + network.lookup[d.egress] = lnk; updateLinks(); } network.force.start(); @@ -682,9 +698,9 @@ evTrace(data); var inst = data.payload, id = inst.id, - instData = onosInstances[id]; - if (instData) { - $.extend(instData, inst); + d = onosInstances[id]; + if (d) { + $.extend(d, inst); updateInstances(); } else { logicError('updateInstance lookup fail. ID = "' + id + '"'); @@ -723,10 +739,10 @@ evTrace(data); var host = data.payload, id = host.id, - hostData = network.lookup[id]; - if (hostData) { - $.extend(hostData, host); - updateHostState(hostData); + d = network.lookup[id]; + if (d) { + $.extend(d, host); + updateHostState(d); } else { logicError('updateHost lookup fail. ID = "' + id + '"'); } @@ -737,9 +753,9 @@ evTrace(data); var inst = data.payload, id = inst.id, - instData = onosInstances[id]; - if (instData) { - var idx = find(id, onosOrder, 'id'); + d = onosInstances[id]; + if (d) { + var idx = find(id, onosOrder); if (idx >= 0) { onosOrder.splice(idx, 1); } @@ -750,13 +766,26 @@ } } + function removeDevice(data) { + evTrace(data); + var device = data.payload, + id = device.id, + d = network.lookup[id]; + if (d) { + removeDeviceElement(d); + } else { + logicError('removeDevice lookup fail. ID = "' + id + '"'); + } + } + function removeLink(data) { evTrace(data); var link = data.payload, result = findLink(link, 'remove'), bad = result.badLogic; if (bad) { - logicError(bad + ': ' + link.id); + // may have already removed link, if attached to removed device + console.warn(bad + ': ' + link.id); return; } result.removeRawLink(); @@ -766,14 +795,16 @@ evTrace(data); var host = data.payload, id = host.id, - hostData = network.lookup[id]; - if (hostData) { - removeHostElement(hostData); + d = network.lookup[id]; + if (d) { + removeHostElement(d, true); } else { - logicError('removeHost lookup fail. ID = "' + id + '"'); + // may have already removed host, if attached to removed device + console.warn('removeHost lookup fail. ID = "' + id + '"'); } } + // the following events are server responses to user actions function showSummary(data) { evTrace(data); populateSummary(data.payload); @@ -828,14 +859,6 @@ // ............................... - function stillToImplement(data) { - var p = data.payload; - note(data.event, p.id); - if (!config.useLiveData) { - network.view.alert('Not yet implemented: "' + data.event + '"'); - } - } - function unknownEvent(data) { console.warn('Unknown event type: "' + data.event + '"', data); } @@ -854,17 +877,6 @@ function getSel(idx) { return selections[selectOrder[idx]]; } - function getSelId(idx) { - return getSel(idx).obj.id; - } - function getSelIds(start, endOffset) { - var end = selectOrder.length - endOffset; - var ids = []; - selectOrder.slice(start, end).forEach(function (d) { - ids.push(getSelId(d)); - }); - return ids; - } function allSelectionsClass(cls) { for (var i=0, n=nSel(); i.remove to remove this element node.select('circle') .style('stroke-fill', '#555') @@ -1857,11 +1872,22 @@ .transition() .duration(1500) .attr('r', 0); - // note, leave .remove to remove this element - }); - // TODO: device node exit animation + // device node exits.... + exiting.filter('.device').each(function (d) { + var node = d.el; + node.select('use') + .style('opacity', 0.5) + .transition() + .duration(800) + .style('opacity', 0); + + node.selectAll('rect') + .style('stroke-fill', '#555') + .style('fill', '#888') + .style('opacity', 0.5); + }); network.force.resume(); } @@ -1968,7 +1994,7 @@ } function find(key, array, tag) { - var _tag = tag || 'key', + var _tag = tag || 'id', idx, n, d; for (idx = 0, n = array.length; idx < n; idx++) { d = array[idx]; @@ -1979,8 +2005,8 @@ return -1; } - function removeLinkElement(linkData) { - var idx = find(linkData.key, network.links), + function removeLinkElement(d) { + var idx = find(d.key, network.links, 'key'), removed; if (idx >=0) { // remove from links array @@ -1992,20 +2018,64 @@ } } - function removeHostElement(hostData) { + function removeHostElement(d, upd) { + var lu = network.lookup; // first, remove associated hostLink... - removeLinkElement(hostData.linkData); + removeLinkElement(d.linkData); + + // remove hostLink bindings + delete lu[d.ingress]; + delete lu[d.egress]; // remove from lookup cache - delete network.lookup[hostData.id]; + delete lu[d.id]; // remove from nodes array - var idx = find(hostData.id, network.nodes); + var idx = find(d.id, network.nodes); + network.nodes.splice(idx, 1); + // remove from SVG + // NOTE: upd is false if we were called from removeDeviceElement() + if (upd) { + updateNodes(); + network.force.resume(); + } + } + + + function removeDeviceElement(d) { + var id = d.id; + // first, remove associated hosts and links.. + findAttachedHosts(id).forEach(removeHostElement); + findAttachedLinks(id).forEach(removeLinkElement); + + // remove from lookup cache + delete network.lookup[id]; + // remove from nodes array + var idx = find(id, network.nodes); network.nodes.splice(idx, 1); // remove from SVG updateNodes(); network.force.resume(); } + function findAttachedHosts(devId) { + var hosts = []; + network.nodes.forEach(function (d) { + if (d.class === 'host' && d.cp.device === devId) { + hosts.push(d); + } + }); + return hosts; + } + + function findAttachedLinks(devId) { + var links = []; + network.links.forEach(function (d) { + if (d.source.id === devId || d.target.id === devId) { + links.push(d); + } + }); + return links; + } function tick() { node.attr({