Simon Hunt

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
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
28 "labels": [""] 28 "labels": [""]
29 }, 29 },
30 { 30 {
31 - "class": "primary optical", 31 + "class": "animated optical",
32 - "traffic": false, 32 + "traffic": true,
33 "links": [ 33 "links": [
34 "of:0000ffffffff0008/4-of:0000ffffffffff08/1" 34 "of:0000ffffffff0008/4-of:0000ffffffffff08/1"
35 ], 35 ],
...@@ -44,8 +44,8 @@ ...@@ -44,8 +44,8 @@
44 "labels": [""] 44 "labels": [""]
45 }, 45 },
46 { 46 {
47 - "class": "animated optical", 47 + "class": "primary optical",
48 - "traffic": true, 48 + "traffic": false,
49 "links": [ 49 "links": [
50 "of:0000ffffffffff08/4-of:0000ffffffffff03/1" 50 "of:0000ffffffffff08/4-of:0000ffffffffff03/1"
51 ], 51 ],
......
1 +{
2 + "event": "updateDevice",
3 + "payload": {
4 + "id": "of:0000ffffffff0007",
5 + "type": "switch",
6 + "online": false,
7 + "labels": [
8 + "",
9 + "sw-7",
10 + "0000ffffffff0007"
11 + ],
12 + "metaUi": {
13 + "x": 530,
14 + "y": 330
15 + }
16 + }
17 +}
1 +{
2 + "event": "updateDevice",
3 + "payload": {
4 + "id": "of:0000ffffffff0007",
5 + "type": "switch",
6 + "online": true,
7 + "labels": [
8 + "",
9 + "sw-7",
10 + "0000ffffffff0007"
11 + ],
12 + "metaUi": {
13 + "x": 530,
14 + "y": 330
15 + }
16 + }
17 +}
1 +{
2 + "event": "removeDevice",
3 + "payload": {
4 + "id": "of:0000ffffffff0008",
5 + "type": "switch",
6 + "online": false,
7 + "labels": [
8 + "",
9 + "sw-8",
10 + "0000ffffffff0008"
11 + ],
12 + "metaUi": {
13 + "x": 734,
14 + "y": 477
15 + }
16 + }
17 +}
1 +{
2 + "event": "addDevice",
3 + "payload": {
4 + "id": "of:0000ffffffff0008",
5 + "type": "switch",
6 + "online": true,
7 + "labels": [
8 + "",
9 + "sw-8",
10 + "0000ffffffff0008"
11 + ],
12 + "metaUi": {
13 + "x": 734,
14 + "y": 477
15 + }
16 + }
17 +}
1 +{
2 + "event": "removeHost",
3 + "payload": {
4 + "id": "0E:2A:69:30:13:88/-1",
5 + "ingress": "0E:2A:69:30:13:88/-1/0-of:0000ffffffff0007/101",
6 + "egress": "of:0000ffffffff0007/101-0E:2A:69:30:13:86/-1/0",
7 + "cp": {
8 + "device": "of:0000ffffffff0007",
9 + "port": 101
10 + },
11 + "labels": [
12 + "4.5.7.6",
13 + "0E:2A:69:30:13:88"
14 + ],
15 + "props": {}
16 + }
17 +}
...@@ -596,7 +596,7 @@ ...@@ -596,7 +596,7 @@
596 updateHost: updateHost, 596 updateHost: updateHost,
597 597
598 removeInstance: removeInstance, 598 removeInstance: removeInstance,
599 - removeDevice: stillToImplement, 599 + removeDevice: removeDevice,
600 removeLink: removeLink, 600 removeLink: removeLink,
601 removeHost: removeHost, 601 removeHost: removeHost,
602 602
...@@ -621,9 +621,17 @@ ...@@ -621,9 +621,17 @@
621 function addDevice(data) { 621 function addDevice(data) {
622 evTrace(data); 622 evTrace(data);
623 var device = data.payload, 623 var device = data.payload,
624 - nodeData = createDeviceNode(device); 624 + id = device.id,
625 - network.nodes.push(nodeData); 625 + d;
626 - network.lookup[nodeData.id] = nodeData; 626 +
627 + if (network.lookup[id]) {
628 + logicError('Device already added: ' + id);
629 + return;
630 + }
631 +
632 + d = createDeviceNode(device);
633 + network.nodes.push(d);
634 + network.lookup[id] = d;
627 updateNodes(); 635 updateNodes();
628 network.force.start(); 636 network.force.start();
629 } 637 }
...@@ -633,24 +641,24 @@ ...@@ -633,24 +641,24 @@
633 var link = data.payload, 641 var link = data.payload,
634 result = findLink(link, 'add'), 642 result = findLink(link, 'add'),
635 bad = result.badLogic, 643 bad = result.badLogic,
636 - ldata = result.ldata; 644 + d = result.ldata;
637 645
638 if (bad) { 646 if (bad) {
639 logicError(bad + ': ' + link.id); 647 logicError(bad + ': ' + link.id);
640 return; 648 return;
641 } 649 }
642 650
643 - if (ldata) { 651 + if (d) {
644 // we already have a backing store link for src/dst nodes 652 // we already have a backing store link for src/dst nodes
645 - addLinkUpdate(ldata, link); 653 + addLinkUpdate(d, link);
646 return; 654 return;
647 } 655 }
648 656
649 // no backing store link yet 657 // no backing store link yet
650 - ldata = createLink(link); 658 + d = createLink(link);
651 - if (ldata) { 659 + if (d) {
652 - network.links.push(ldata); 660 + network.links.push(d);
653 - network.lookup[ldata.key] = ldata; 661 + network.lookup[d.key] = d;
654 updateLinks(); 662 updateLinks();
655 network.force.start(); 663 network.force.start();
656 } 664 }
...@@ -659,18 +667,26 @@ ...@@ -659,18 +667,26 @@
659 function addHost(data) { 667 function addHost(data) {
660 evTrace(data); 668 evTrace(data);
661 var host = data.payload, 669 var host = data.payload,
662 - node = createHostNode(host), 670 + id = host.id,
671 + d,
663 lnk; 672 lnk;
664 - network.nodes.push(node); 673 +
665 - network.lookup[host.id] = node; 674 + if (network.lookup[id]) {
675 + logicError('Host already added: ' + id);
676 + return;
677 + }
678 +
679 + d = createHostNode(host);
680 + network.nodes.push(d);
681 + network.lookup[host.id] = d;
666 updateNodes(); 682 updateNodes();
667 683
668 lnk = createHostLink(host); 684 lnk = createHostLink(host);
669 if (lnk) { 685 if (lnk) {
670 - node.linkData = lnk; // cache ref on its host 686 + d.linkData = lnk; // cache ref on its host
671 network.links.push(lnk); 687 network.links.push(lnk);
672 - network.lookup[host.ingress] = lnk; 688 + network.lookup[d.ingress] = lnk;
673 - network.lookup[host.egress] = lnk; 689 + network.lookup[d.egress] = lnk;
674 updateLinks(); 690 updateLinks();
675 } 691 }
676 network.force.start(); 692 network.force.start();
...@@ -682,9 +698,9 @@ ...@@ -682,9 +698,9 @@
682 evTrace(data); 698 evTrace(data);
683 var inst = data.payload, 699 var inst = data.payload,
684 id = inst.id, 700 id = inst.id,
685 - instData = onosInstances[id]; 701 + d = onosInstances[id];
686 - if (instData) { 702 + if (d) {
687 - $.extend(instData, inst); 703 + $.extend(d, inst);
688 updateInstances(); 704 updateInstances();
689 } else { 705 } else {
690 logicError('updateInstance lookup fail. ID = "' + id + '"'); 706 logicError('updateInstance lookup fail. ID = "' + id + '"');
...@@ -723,10 +739,10 @@ ...@@ -723,10 +739,10 @@
723 evTrace(data); 739 evTrace(data);
724 var host = data.payload, 740 var host = data.payload,
725 id = host.id, 741 id = host.id,
726 - hostData = network.lookup[id]; 742 + d = network.lookup[id];
727 - if (hostData) { 743 + if (d) {
728 - $.extend(hostData, host); 744 + $.extend(d, host);
729 - updateHostState(hostData); 745 + updateHostState(d);
730 } else { 746 } else {
731 logicError('updateHost lookup fail. ID = "' + id + '"'); 747 logicError('updateHost lookup fail. ID = "' + id + '"');
732 } 748 }
...@@ -737,9 +753,9 @@ ...@@ -737,9 +753,9 @@
737 evTrace(data); 753 evTrace(data);
738 var inst = data.payload, 754 var inst = data.payload,
739 id = inst.id, 755 id = inst.id,
740 - instData = onosInstances[id]; 756 + d = onosInstances[id];
741 - if (instData) { 757 + if (d) {
742 - var idx = find(id, onosOrder, 'id'); 758 + var idx = find(id, onosOrder);
743 if (idx >= 0) { 759 if (idx >= 0) {
744 onosOrder.splice(idx, 1); 760 onosOrder.splice(idx, 1);
745 } 761 }
...@@ -750,13 +766,26 @@ ...@@ -750,13 +766,26 @@
750 } 766 }
751 } 767 }
752 768
769 + function removeDevice(data) {
770 + evTrace(data);
771 + var device = data.payload,
772 + id = device.id,
773 + d = network.lookup[id];
774 + if (d) {
775 + removeDeviceElement(d);
776 + } else {
777 + logicError('removeDevice lookup fail. ID = "' + id + '"');
778 + }
779 + }
780 +
753 function removeLink(data) { 781 function removeLink(data) {
754 evTrace(data); 782 evTrace(data);
755 var link = data.payload, 783 var link = data.payload,
756 result = findLink(link, 'remove'), 784 result = findLink(link, 'remove'),
757 bad = result.badLogic; 785 bad = result.badLogic;
758 if (bad) { 786 if (bad) {
759 - logicError(bad + ': ' + link.id); 787 + // may have already removed link, if attached to removed device
788 + console.warn(bad + ': ' + link.id);
760 return; 789 return;
761 } 790 }
762 result.removeRawLink(); 791 result.removeRawLink();
...@@ -766,14 +795,16 @@ ...@@ -766,14 +795,16 @@
766 evTrace(data); 795 evTrace(data);
767 var host = data.payload, 796 var host = data.payload,
768 id = host.id, 797 id = host.id,
769 - hostData = network.lookup[id]; 798 + d = network.lookup[id];
770 - if (hostData) { 799 + if (d) {
771 - removeHostElement(hostData); 800 + removeHostElement(d, true);
772 } else { 801 } else {
773 - logicError('removeHost lookup fail. ID = "' + id + '"'); 802 + // may have already removed host, if attached to removed device
803 + console.warn('removeHost lookup fail. ID = "' + id + '"');
774 } 804 }
775 } 805 }
776 806
807 + // the following events are server responses to user actions
777 function showSummary(data) { 808 function showSummary(data) {
778 evTrace(data); 809 evTrace(data);
779 populateSummary(data.payload); 810 populateSummary(data.payload);
...@@ -828,14 +859,6 @@ ...@@ -828,14 +859,6 @@
828 859
829 // ............................... 860 // ...............................
830 861
831 - function stillToImplement(data) {
832 - var p = data.payload;
833 - note(data.event, p.id);
834 - if (!config.useLiveData) {
835 - network.view.alert('Not yet implemented: "' + data.event + '"');
836 - }
837 - }
838 -
839 function unknownEvent(data) { 862 function unknownEvent(data) {
840 console.warn('Unknown event type: "' + data.event + '"', data); 863 console.warn('Unknown event type: "' + data.event + '"', data);
841 } 864 }
...@@ -854,17 +877,6 @@ ...@@ -854,17 +877,6 @@
854 function getSel(idx) { 877 function getSel(idx) {
855 return selections[selectOrder[idx]]; 878 return selections[selectOrder[idx]];
856 } 879 }
857 - function getSelId(idx) {
858 - return getSel(idx).obj.id;
859 - }
860 - function getSelIds(start, endOffset) {
861 - var end = selectOrder.length - endOffset;
862 - var ids = [];
863 - selectOrder.slice(start, end).forEach(function (d) {
864 - ids.push(getSelId(d));
865 - });
866 - return ids;
867 - }
868 function allSelectionsClass(cls) { 880 function allSelectionsClass(cls) {
869 for (var i=0, n=nSel(); i<n; i++) { 881 for (var i=0, n=nSel(); i<n; i++) {
870 if (getSel(i).obj.class !== cls) { 882 if (getSel(i).obj.class !== cls) {
...@@ -895,7 +907,6 @@ ...@@ -895,7 +907,6 @@
895 updateDeviceColors(); 907 updateDeviceColors();
896 } 908 }
897 909
898 -
899 function toggleSummary() { 910 function toggleSummary() {
900 if (!summaryPane.isVisible()) { 911 if (!summaryPane.isVisible()) {
901 requestSummary(); 912 requestSummary();
...@@ -1841,14 +1852,18 @@ ...@@ -1841,14 +1852,18 @@
1841 1852
1842 // host node exits.... 1853 // host node exits....
1843 exiting.filter('.host').each(function (d) { 1854 exiting.filter('.host').each(function (d) {
1844 - var node = d3.select(this); 1855 + var node = d.el;
1856 + node.select('use')
1857 + .style('opacity', 0.5)
1858 + .transition()
1859 + .duration(800)
1860 + .style('opacity', 0);
1845 1861
1846 node.select('text') 1862 node.select('text')
1847 .style('opacity', 0.5) 1863 .style('opacity', 0.5)
1848 .transition() 1864 .transition()
1849 - .duration(1000) 1865 + .duration(800)
1850 .style('opacity', 0); 1866 .style('opacity', 0);
1851 - // note, leave <g>.remove to remove this element
1852 1867
1853 node.select('circle') 1868 node.select('circle')
1854 .style('stroke-fill', '#555') 1869 .style('stroke-fill', '#555')
...@@ -1857,11 +1872,22 @@ ...@@ -1857,11 +1872,22 @@
1857 .transition() 1872 .transition()
1858 .duration(1500) 1873 .duration(1500)
1859 .attr('r', 0); 1874 .attr('r', 0);
1860 - // note, leave <g>.remove to remove this element
1861 -
1862 }); 1875 });
1863 1876
1864 - // TODO: device node exit animation 1877 + // device node exits....
1878 + exiting.filter('.device').each(function (d) {
1879 + var node = d.el;
1880 + node.select('use')
1881 + .style('opacity', 0.5)
1882 + .transition()
1883 + .duration(800)
1884 + .style('opacity', 0);
1885 +
1886 + node.selectAll('rect')
1887 + .style('stroke-fill', '#555')
1888 + .style('fill', '#888')
1889 + .style('opacity', 0.5);
1890 + });
1865 1891
1866 network.force.resume(); 1892 network.force.resume();
1867 } 1893 }
...@@ -1968,7 +1994,7 @@ ...@@ -1968,7 +1994,7 @@
1968 } 1994 }
1969 1995
1970 function find(key, array, tag) { 1996 function find(key, array, tag) {
1971 - var _tag = tag || 'key', 1997 + var _tag = tag || 'id',
1972 idx, n, d; 1998 idx, n, d;
1973 for (idx = 0, n = array.length; idx < n; idx++) { 1999 for (idx = 0, n = array.length; idx < n; idx++) {
1974 d = array[idx]; 2000 d = array[idx];
...@@ -1979,8 +2005,8 @@ ...@@ -1979,8 +2005,8 @@
1979 return -1; 2005 return -1;
1980 } 2006 }
1981 2007
1982 - function removeLinkElement(linkData) { 2008 + function removeLinkElement(d) {
1983 - var idx = find(linkData.key, network.links), 2009 + var idx = find(d.key, network.links, 'key'),
1984 removed; 2010 removed;
1985 if (idx >=0) { 2011 if (idx >=0) {
1986 // remove from links array 2012 // remove from links array
...@@ -1992,20 +2018,64 @@ ...@@ -1992,20 +2018,64 @@
1992 } 2018 }
1993 } 2019 }
1994 2020
1995 - function removeHostElement(hostData) { 2021 + function removeHostElement(d, upd) {
2022 + var lu = network.lookup;
1996 // first, remove associated hostLink... 2023 // first, remove associated hostLink...
1997 - removeLinkElement(hostData.linkData); 2024 + removeLinkElement(d.linkData);
2025 +
2026 + // remove hostLink bindings
2027 + delete lu[d.ingress];
2028 + delete lu[d.egress];
1998 2029
1999 // remove from lookup cache 2030 // remove from lookup cache
2000 - delete network.lookup[hostData.id]; 2031 + delete lu[d.id];
2001 // remove from nodes array 2032 // remove from nodes array
2002 - var idx = find(hostData.id, network.nodes); 2033 + var idx = find(d.id, network.nodes);
2003 network.nodes.splice(idx, 1); 2034 network.nodes.splice(idx, 1);
2004 // remove from SVG 2035 // remove from SVG
2036 + // NOTE: upd is false if we were called from removeDeviceElement()
2037 + if (upd) {
2005 updateNodes(); 2038 updateNodes();
2006 network.force.resume(); 2039 network.force.resume();
2007 } 2040 }
2041 + }
2042 +
2043 +
2044 + function removeDeviceElement(d) {
2045 + var id = d.id;
2046 + // first, remove associated hosts and links..
2047 + findAttachedHosts(id).forEach(removeHostElement);
2048 + findAttachedLinks(id).forEach(removeLinkElement);
2008 2049
2050 + // remove from lookup cache
2051 + delete network.lookup[id];
2052 + // remove from nodes array
2053 + var idx = find(id, network.nodes);
2054 + network.nodes.splice(idx, 1);
2055 + // remove from SVG
2056 + updateNodes();
2057 + network.force.resume();
2058 + }
2059 +
2060 + function findAttachedHosts(devId) {
2061 + var hosts = [];
2062 + network.nodes.forEach(function (d) {
2063 + if (d.class === 'host' && d.cp.device === devId) {
2064 + hosts.push(d);
2065 + }
2066 + });
2067 + return hosts;
2068 + }
2069 +
2070 + function findAttachedLinks(devId) {
2071 + var links = [];
2072 + network.links.forEach(function (d) {
2073 + if (d.source.id === devId || d.target.id === devId) {
2074 + links.push(d);
2075 + }
2076 + });
2077 + return links;
2078 + }
2009 2079
2010 function tick() { 2080 function tick() {
2011 node.attr({ 2081 node.attr({
......