diff --git a/webroot/common/ui/templates/controller.tmpl b/webroot/common/ui/templates/controller.tmpl index 895744ef1..556d8ff2b 100644 --- a/webroot/common/ui/templates/controller.tmpl +++ b/webroot/common/ui/templates/controller.tmpl @@ -24,16 +24,11 @@ diff --git a/webroot/monitor/infrastructure/common/ui/js/utils/monitor.infra.parsers.js b/webroot/monitor/infrastructure/common/ui/js/utils/monitor.infra.parsers.js index 7f7eeb1a7..e891cd57f 100644 --- a/webroot/monitor/infrastructure/common/ui/js/utils/monitor.infra.parsers.js +++ b/webroot/monitor/infrastructure/common/ui/js/utils/monitor.infra.parsers.js @@ -1725,9 +1725,8 @@ define( } }; this.parseUnderlayFlowRecords = function (response) { - var graphView = - $("#"+ctwl.UNDERLAY_GRAPH_ID).data('graphView'); - response['vRouters'] = graphView.model.vRouters; + var graphModel = monitorInfraUtils.getUnderlayGraphModel(); + response['vRouters'] = graphModel.vRouters; var vRouters = ifNull(response['vRouters'],[]); $.each(ifNull(response['data'],[]),function (idx,obj) { var formattedVrouter,formattedOtherVrouter, diff --git a/webroot/monitor/infrastructure/common/ui/js/utils/monitor.infra.utils.js b/webroot/monitor/infrastructure/common/ui/js/utils/monitor.infra.utils.js index c8116e953..aa5939893 100644 --- a/webroot/monitor/infrastructure/common/ui/js/utils/monitor.infra.utils.js +++ b/webroot/monitor/infrastructure/common/ui/js/utils/monitor.infra.utils.js @@ -1863,13 +1863,13 @@ define([ viewConfig: { data: viewConfig.data, templateConfig: monitorInfraUtils. - getUnderlayDetailsTabTemplateConfig(), + getUnderlayDetailsTabTemplateConfig(viewConfig.data), app: cowc.APP_CONTRAIL_CONTROLLER, }, } }; - self.getUnderlayDetailsTabTemplateConfig = function() { + self.getUnderlayDetailsTabTemplateConfig = function(data) { return { advancedViewOptions: false, templateGenerator: 'RowSectionTemplateGenerator', @@ -1883,12 +1883,15 @@ define([ class: 'span6', rows: [ { - title: ctwl.UNDERLAY_PROUTER_DETAILS, + title: contrail.format('{0} ( {1} )', + ctwl.UNDERLAY_PROUTER_DETAILS, + data.hostName), templateGenerator: 'BlockListTemplateGenerator', templateGeneratorConfig: [ { key: 'hostName', + label: 'Hostname', templateGenerator: 'TextGenerator' },{ @@ -1906,6 +1909,7 @@ define([ } },{ key: 'managementIP', + label: 'Management IP', templateGenerator: 'TextGenerator', } @@ -1924,10 +1928,8 @@ define([ self.getTrafficStatisticsTabViewConfig = function (data) { var ajaxConfig = {}; var endpoints = ifNull(data['endpoints'],[]); - var sourceType = getValueByJsonPath(data, - 'sourceElement;attributes;nodeDetails;node_type','-'); - var targetType = getValueByJsonPath(data, - 'targetElement;attributes;nodeDetails;node_type','-'); + var sourceType = getValueByJsonPath(data,'sourceElement;node_type','-'); + var targetType = getValueByJsonPath(data,'targetElement;node_type','-'); var view = 'LineWithFocusChartView', modelMap = null; var viewConfig = {}, viewPathPrefix; if(sourceType == ctwc.PROUTER && targetType == ctwc.PROUTER) { @@ -1951,8 +1953,7 @@ define([ }; } else if(sourceType == ctwc.PROUTER && targetType == ctwc.VROUTER) { var vrouter = (sourceType == ctwc.VROUTER) ? - data['sourceElement']['attributes']['nodeDetails']['name']: - data['targetElement']['attributes']['nodeDetails']['name']; + data['sourceElement']['name']: data['targetElement']['name']; var params = { minsSince: 60, sampleCnt: 120, @@ -1991,10 +1992,9 @@ define([ } } else if(sourceType == ctwc.VIRTUALMACHINE || targetType == ctwc.VIRTUALMACHINE) { - var instanceUUID = getValueByJsonPath(data, - 'targetElement;attributes;nodeDetails;name','-'); + var instanceUUID = getValueByJsonPath(data, 'targetElement;name','-'); var vmName = getValueByJsonPath(data, - 'targetElement;attributes;nodeDetails;more_attributes;vm_name','-'); + 'targetElement;more_attributes;vm_name','-'); var modelKey = ctwc.get(ctwc.UMID_INSTANCE_UVE, instanceUUID); view = 'InstanceTrafficStatsView'; viewPathPrefix = 'monitor/networking/ui/js/views/'; @@ -2094,8 +2094,8 @@ define([ }, self.getTraceFlowVrouterGridColumns = function () { - var graphView = $("#"+ctwl.UNDERLAY_GRAPH_ID).data('graphView'); - computeNodes = graphView.model.vRouters; + var graphModel = monitorInfraUtils.getUnderlayGraphModel(); + computeNodes = graphModel.vRouters; return [ { field:'peer_vrouter', @@ -2358,8 +2358,8 @@ define([ } ]; }; - self.getUnderlayGraphInstance = function () { - return $("#"+ctwl.UNDERLAY_GRAPH_ID).data('graphView'); + self.getUnderlayGraphModel = function () { + return $("#"+ctwl.UNDERLAY_GRAPH_ID).data('graphModel'); }; self.showFlowPath = function (connectionWrapIds, offsetWidth, graphView) { @@ -2619,7 +2619,7 @@ define([ }; self.showUnderlayPaths = function (data) { - var graphModel = monitorInfraUtils.getUnderlayGraphInstance().model; + var graphModel = monitorInfraUtils.getUnderlayGraphModel(); var currentUrlHashObj = layoutHandler.getURLHashObj(), currentPage = currentUrlHashObj.p, currentParams = currentUrlHashObj.q; diff --git a/webroot/monitor/infrastructure/underlay/ui/js/models/UnderlayGraphModel.js b/webroot/monitor/infrastructure/underlay/ui/js/models/UnderlayGraphModel.js index e0b6071fd..f2705f4e6 100644 --- a/webroot/monitor/infrastructure/underlay/ui/js/models/UnderlayGraphModel.js +++ b/webroot/monitor/infrastructure/underlay/ui/js/models/UnderlayGraphModel.js @@ -2,9 +2,8 @@ * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. */ -define(['contrail-graph-model', 'backbone'],function(ContrailGraphModel, Backbone) { - var UnderlayGraphModel = ContrailGraphModel.extend({ - +define(['contrail-vis-model', 'backbone'],function(ContrailVisModel, Backbone) { + UnderlayGraphModel = ContrailVisModel.extend({ initialize: function (graphModelConfig) { this.nodes = [], this.links = [], @@ -24,6 +23,7 @@ define(['contrail-graph-model', 'backbone'],function(ContrailGraphModel, Backbon this.underlayPathReqObj = {}, this.uveMissingNodes = [], this.configMissingNodes = [], + this.firstLevelNode = "", this.selectedElement = new Backbone.Model({ nodeType: '', nodeDetail: {} @@ -32,9 +32,9 @@ define(['contrail-graph-model', 'backbone'],function(ContrailGraphModel, Backbon nodes: [], links: [] }); - ContrailGraphModel.prototype.initialize.apply(this, [graphModelConfig]); + ContrailVisModel.prototype.initialize.apply(this, [graphModelConfig]); }, - getElementsForUnderlayGraph : function (response) { + initializeUnderlayModel : function (response) { //update chasis-type in nodes var nodes = ifNull(response['nodes'], []); var configMissingNodes = getValueByJsonPath(response, @@ -47,7 +47,7 @@ define(['contrail-graph-model', 'backbone'],function(ContrailGraphModel, Backbon var nodeObj = { name:configMissingNodes[i], node_type: "physical-router", - chassis_type: "coreswitch", + chassis_type: "unknown", more_attributes: {}, errorMsg:'Configuration Unavailable' }; @@ -57,7 +57,7 @@ define(['contrail-graph-model', 'backbone'],function(ContrailGraphModel, Backbon var nodeObj = { name:uveMissingNodes[i], node_type: "physical-router", - chassis_type: "coreswitch", + chassis_type: "unknown", more_attributes: {}, errorMsg:'System Information Unavailable' }; @@ -131,17 +131,21 @@ define(['contrail-graph-model', 'backbone'],function(ContrailGraphModel, Backbon } if(cores.length > 0) { firstLevelNodes = cores; + this.firstLevelNode = "coreswitch"; } else { var spines = this.spines; if(spines.length > 0) { firstLevelNodes = spines; + this.firstLevelNode = "spine"; } else { var tors = this.tors; if(tors.length > 0) { firstLevelNodes = tors; + this.firstLevelNode = "tor"; } } } + this.firstLevelNodes = firstLevelNodes; this.parseTree(firstLevelNodes, tree, tmpTree); if(JSON.stringify(tmpTree) !== "{}") { $.each(tmpTree, function (elementKey, elementValue) { @@ -152,263 +156,14 @@ define(['contrail-graph-model', 'backbone'],function(ContrailGraphModel, Backbon var adjacencyList = this.prepareData('tor'); this.adjacencyList = adjacencyList; this.underlayAdjacencyList = adjacencyList; - var els = this.createElementsFromAdjacencyList(); + //this.addElementsToGraph(els, null); - return { - elements: els, - nodes: this.nodes, - links: this.links, - }; }, - createElementsFromAdjacencyList: function () { - var elements = []; - var linkElements = []; - var self = this; - var adjacencyList = this.adjacencyList; - var conElements = this.connectedElements; - var nodes = this.nodes; - var links = this.links; - var elMap = this.elementMap; - _.each(adjacencyList, function(edges, parentElementLabel) { - if(null !== elMap["node"][parentElementLabel] && - typeof elMap["node"][parentElementLabel] !== "undefined") { - var el = self.getCell(elMap["node"][parentElementLabel]); - if(null !== el && typeof el !== "undefined") { - elements.push(el); - return; - } else { - el = jsonPath(conElements, '$[?(@.id=="' + - elMap["node"][parentElementLabel] + '")]'); - if(typeof el === "object" && el.length === 1) { - elements.push(el[0]); - return; - } - } - } - var parentNode = jsonPath(nodes, '$[?(@.name=="' + - parentElementLabel + '")]'); - if(false !== parentNode && parentNode.length === 1) { - parentNode = parentNode[0]; - var parentName = parentNode.name; - var parentNodeType = parentNode.node_type; - elements.push(self.createNode(parentNode)); - var currentEl = elements[elements.length-1]; - conElements.push(currentEl); - var currentElId = currentEl.id; - elMap.node[parentName] = currentElId; - } - }); - - _.each(adjacencyList, function(edges, parentElementLabel) { - var parentNode = jsonPath(nodes, '$[?(@.name=="' + - parentElementLabel + '")]'); - if(false !== parentNode && parentNode.length === 1) { - parentNode = parentNode[0]; - var parentNodeType = parentNode.node_type; - var parentId = elMap.node[parentNode.name]; - _.each(edges, function(childElementLabel) { - if(null !== elMap["link"][parentElementLabel + - "<->" + childElementLabel] && - typeof elMap["link"][parentElementLabel + - "<->" + childElementLabel] !== "undefined") { - var linkEl = self.getCell(elMap["link"][parentElementLabel + - "<->" + childElementLabel]); - if(null !== linkEl && typeof linkEl !== "undefined") { - linkElements.push(linkEl); - return; - } else { - linkEl = jsonPath(conElements, '$[?(@.id=="' + - elMap["link"][parentElementLabel + - '<->' + childElementLabel] + '")]'); - if(typeof linkEl === "object" && - linkEl.length === 1) { - linkElements.push(linkEl[0]); - return; - } - } - } - var childNode = jsonPath(nodes, '$[?(@.name=="' + - childElementLabel + '")]'); - if(false !== childNode && childNode.length === 1) { - childNode = childNode[0]; - var childNodeType = childNode.node_type; - var childId = elMap.node[childNode["name"]]; - var link_type = parentNodeType.split("-")[0][0] + - parentNodeType.split("-")[1][0] + '-' + - childNodeType.split("-")[0][0] + - childNodeType.split("-")[1][0]; - for(var i=0; i" + parentElementLabel; - var altLinkName = parentElementLabel + - "<->" + childElementLabel; - if((null == elMap["link"][linkName] && - typeof elMap["link"][linkName] == "undefined") && - null == elMap["link"][altLinkName] && - typeof elMap["link"][altLinkName] == "undefined") { - linkElements.push(self.createLink( - link, link_type, parentId, childId)); - var currentLink = - linkElements[linkElements.length-1]; - var currentLinkId = currentLink.id; - conElements.push(currentLink); - elMap.link[linkName] = currentLinkId; - elMap.link[altLinkName] = currentLinkId; - break; - } - } - } - } - }); - } - }); - for(var i=0; i" + endpoint1; - var altLinkName = endpoint1 + "<->" + endpoint0; - var endpoint0Node = jsonPath(nodes, '$[?(@.name=="' + endpoint0 + '")]'); - if(false !== endpoint0Node && endpoint0Node.length === 1) { - endpoint0Node = endpoint0Node[0]; - } else { - continue; - } - var endpoint1Node = jsonPath(nodes, '$[?(@.name=="' + endpoint1 + '")]'); - if(false !== endpoint1Node && endpoint1Node.length === 1) { - endpoint1Node = endpoint1Node[0]; - } else { - continue; - } - var endpoint0NodeType = endpoint0Node.node_type; - var endpoint1NodeType = endpoint1Node.node_type; - var link_type = endpoint0NodeType.split("-")[0][0] + - endpoint0NodeType.split("-")[1][0] + '-' + - endpoint1NodeType.split("-")[0][0] + - endpoint1NodeType.split("-")[1][0]; - if(null != elMap["node"] && typeof elMap["node"] !== "undefined") { - if(null != elMap["node"][endpoint0] && typeof elMap["node"][endpoint0] !== "undefined" && - null != elMap["node"][endpoint1] && typeof elMap["node"][endpoint1] !== "undefined") { - if(null == elMap["link"][linkName] && typeof elMap["link"][linkName] === "undefined" && - null == elMap["link"][altLinkName] && typeof elMap["link"][altLinkName] === "undefined") { - linkElements.push( - self.createLink(link, link_type, elMap["node"][endpoint0], elMap["node"][endpoint1])); - var currentLink = - linkElements[linkElements.length - 1]; - var currentLinkId = currentLink.id; - conElements.push(currentLink); - elMap.link[linkName] = currentLinkId; - elMap.link[altLinkName] = currentLinkId; - } else { - var el = jsonPath(linkElements, '$[?(@.id=="' + linkName + '")]'); - var linkEl = self.getCell(elMap.link[linkName]); - if(false == el && null != linkEl) { - linkElements.push(linkEl); - } else - continue; - } - } else { - continue; - } - } else { - continue; - } - } - this.connectedElements = conElements; - // Links must be added after all the elements. This is because when the links - // are added to the graph, link source/target - // elements must be in the graph already. - return elements.concat(linkElements.unique()); - }, getErrorNodes: function () { return this.uveMissingNodes.concat(this.configMissingNodes); }, - createLink: function (link, link_type, srcId, tgtId) { - var options; - var linkElement; - link.link_type = link_type; - options = { - direction : "bi", - linkType : link.link_type, - linkDetails : link - }; - link['connectionStroke'] = '#637939'; - - options['sourceId'] = srcId; - options['targetId'] = tgtId; - linkElement = new ContrailElement('link', options); - return linkElement; - }, - - createNode: function (node) { - var nodeName = node['name'], - type = node.node_type, - chassis_type = node.chassis_type, - width = 40, - height = 40, - imageLink, element, options, imageName; - var refX, refY; - var labelNodeName = contrail.truncateText(nodeName,20); - switch(chassis_type) { - case "coreswitch": - chassis_type = 'router'; - break; - case "spine": - chassis_type = 'router'; - break; - case "tor": - chassis_type = 'switch'; - break; - case "virtual-machine": - if(node.hasOwnProperty('more_attributes') && - node.more_attributes.hasOwnProperty('vm_name') && - node.more_attributes.vm_name.trim() !== "" && - node.more_attributes.vm_name.trim() !== "-") { - labelNodeName = contrail.truncateText( - node.more_attributes.vm_name.trim(),10); - } else { - labelNodeName = contrail.truncateText(nodeName,10); - } - refY = .9; - break; - } - imageName = getImageName(node); - imageLink = '/img/icons/' + imageName; - options = { - attrs: { - image: { - 'xlink:href': imageLink, - width: width, - height: height - }, - text: { - text: labelNodeName, - "ref-y": refY - } - }, - size: { - width: width, - height: height - }, - nodeDetails: node, - font: { - iconClass: 'icon-contrail-' + chassis_type - } - }; - element = new ContrailElement(type, options); - return element; - }, - prepareData : function (stopAt) { var treeModel = this.tree; var adjList = {}; @@ -472,6 +227,8 @@ define(['contrail-graph-model', 'backbone'],function(ContrailGraphModel, Backbon return "virtual-router"; case "virtual-router": return "virtual-machine"; + case "unknown": + return ""; } }, getChildren : function (parent, child_type) { @@ -545,4 +302,4 @@ define(['contrail-graph-model', 'backbone'],function(ContrailGraphModel, Backbon } }); return UnderlayGraphModel; -}); \ No newline at end of file +}); diff --git a/webroot/monitor/infrastructure/underlay/ui/js/views/SearchFlowFormView.js b/webroot/monitor/infrastructure/underlay/ui/js/views/SearchFlowFormView.js index 6f9dc367d..522581259 100644 --- a/webroot/monitor/infrastructure/underlay/ui/js/views/SearchFlowFormView.js +++ b/webroot/monitor/infrastructure/underlay/ui/js/views/SearchFlowFormView.js @@ -20,8 +20,7 @@ define([ self.renderView4Config($(self.$el).find(queryFormId), this.model, self.getViewConfig(), null, null, null, function (searchFlowFormView) { - var graph = monitorInfraUtils.getUnderlayGraphInstance(); - var graphModel = graph.model; + var graphModel = monitorInfraUtils.getUnderlayGraphModel(); searchFlowFormView.listenTo(graphModel.selectedElement, 'change', function (selectedElement) { updateWhereClause(selectedElement, searchFlowFormView); diff --git a/webroot/monitor/infrastructure/underlay/ui/js/views/SearchFlowResultView.js b/webroot/monitor/infrastructure/underlay/ui/js/views/SearchFlowResultView.js index 55e15423c..cbbf7e96f 100644 --- a/webroot/monitor/infrastructure/underlay/ui/js/views/SearchFlowResultView.js +++ b/webroot/monitor/infrastructure/underlay/ui/js/views/SearchFlowResultView.js @@ -113,9 +113,9 @@ define([ remote: { ajaxConfig: searchFlowRemoteConfig, dataParser: function(response) { - var graphView = monitorInfraUtils - .getUnderlayGraphInstance(); - response['vRouters'] = graphView.model.vRouters; + var graphModel = monitorInfraUtils + .getUnderlayGraphModel(); + response['vRouters'] = graphModel.vRouters; return monitorInfraParsers .parseUnderlayFlowRecords(response); } diff --git a/webroot/monitor/infrastructure/underlay/ui/js/views/TraceFlowResultView.js b/webroot/monitor/infrastructure/underlay/ui/js/views/TraceFlowResultView.js index ae8332abc..5e54739c5 100644 --- a/webroot/monitor/infrastructure/underlay/ui/js/views/TraceFlowResultView.js +++ b/webroot/monitor/infrastructure/underlay/ui/js/views/TraceFlowResultView.js @@ -55,8 +55,8 @@ define([ getViewConfig: function () { var self = this, viewConfig = self.attributes.viewConfig, traceFlowGridColumns = []; - var graphView = $("#"+ctwl.UNDERLAY_GRAPH_ID).data('graphView'); - var underlayGraphModel = graphView.model, traceFlowRemoteConfig = {}; + var underlayGraphModel = $("#"+ctwl.UNDERLAY_GRAPH_ID).data('graphModel'), + traceFlowRemoteConfig = {}; if(self.model.traceflow_radiobtn_name() == 'vRouter') { var vRouterDetails = getSelectedVrouterDetails(self.model); var ip = vRouterDetails['ip']; @@ -218,8 +218,7 @@ define([ }; function getSelectedVrouterDetails (traceFlowFormModel) { - var graphView = $("#"+ctwl.UNDERLAY_GRAPH_ID).data('graphView'); - var graphModel = graphView.model; + var graphModel = $("#"+ctwl.UNDERLAY_GRAPH_ID).data('graphModel'); var vRouterMap = graphModel.vRouterMap; var vRouterData = ifNull(vRouterMap[traceFlowFormModel.vrouter_dropdown_name()], {}); @@ -238,8 +237,7 @@ define([ function doTraceFlow (rowId, formModel) { var flowGrid = $("#" +ctwc.TRACEFLOW_RESULTS_GRID_ID).data('contrailGrid'); - var graphView = monitorInfraUtils.getUnderlayGraphInstance(); - var graphModel = graphView.model; + var graphModel = monitorInfraUtils.getUnderlayGraphModel(); var contextVrouterIp; if(formModel != null && formModel.showvRouter()) contextVrouterIp = @@ -332,8 +330,7 @@ define([ function doReverseTraceFlow (rowId, formModel) { var flowGrid = $("#" +ctwc.TRACEFLOW_RESULTS_GRID_ID).data('contrailGrid'); - var graphView = monitorInfraUtils.getUnderlayGraphInstance(); - var graphModel = graphView.model; + var graphModel = monitorInfraUtils.getUnderlayGraphModel(); var dataItem = ifNull(flowGrid._grid.getDataItem(rowId),{}); var contextVrouterIp = ''; if(formModel != null && formModel.showvRouter()) @@ -464,8 +461,7 @@ define([ } } } - var graphView = monitorInfraUtils.getUnderlayGraphInstance(); - var graphModel = graphView != null ? graphView.model : null; + var graphModel = monitorInfraUtils.getUnderlayGraphModel(); if (graphModel != null) { graphModel.underlayPathReqObj = postData; graphModel.flowPath.set('links',ifNull(response['links'], [])); diff --git a/webroot/monitor/infrastructure/underlay/ui/js/views/UnderlayGraphView.js b/webroot/monitor/infrastructure/underlay/ui/js/views/UnderlayGraphView.js index fc85a599a..63208f966 100644 --- a/webroot/monitor/infrastructure/underlay/ui/js/views/UnderlayGraphView.js +++ b/webroot/monitor/infrastructure/underlay/ui/js/views/UnderlayGraphView.js @@ -1,34 +1,410 @@ /* * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. */ - define([ 'underscore', 'contrail-view', 'underlay-graph-model', - 'graph-view', - 'contrail-list-model', -], function (_, ContrailView, UnderlayGraphModel, GraphView, ContrailListModel) { + 'vis' +], function(_, ContrailView, UnderlayGraphModel, vis) { var UnderlayGraphView = ContrailView.extend({ - render: function () { + network: null, + model : null, + tooltipConfigWidth: 0, + tooltipConfigHeight: 0, + cursorPosition: {}, + style: { + default: { + color: "rgba(85,85,85,1)" + }, + defaultDimlight: { + color: "rgba(85,85,85,0.3)" + }, + defaultSelected: { + color: "rgba(73,138,185,1)" + }, + selectedDimlight: { + color: "rgba(73,138,185,0.3)" + }, + errorNode: { + color: "rgba(185,74,72,1)" + } + }, + cidMap: { + "coreswitch": 1, + "spine": 2, + "tor": 3, + "virtual-router": 4, + "virtual-machine": 5 + }, + nodesDataSet: null, + edgesDataSet: null, + visOptions: { + autoResize: true, + clickToUse: false, + interaction: { + navigationButtons: true, + hover: true, + keyboard: false, + selectConnectedEdges: false, + hoverConnectedEdges: false, + zoomView: false + }, + layout: { + hierarchical: { + direction: 'UD', + sortMethod: 'directed' + }, + improvedLayout: true + }, + /*edges: { + smooth: { + enabled: true, + type: "cubicBezier", + forceDirection: "horizontal", + roundness: .7 //not to be used with dynamic + } + }*/ + edges: { + smooth: { + enabled: true, + type: "dynamic", + forceDirection: "none" + } + } + }, + resetTooltip: function() { + $(".vis-network-tooltip").popover('destroy'); + this.tooltipConfigWidth = 0; + this.tooltipConfigHeight = 0; + }, + render: function() { var self = this, graphTemplate = - contrail.getTemplate4Id(ctwl.TMPL_UNDERLAY_GRAPH_VIEW), + contrail.getTemplate4Id(ctwl.TMPL_UNDERLAY_GRAPH_VIEW), selectorId = '#' + ctwl.UNDERLAY_GRAPH_ID, graphModel = - new UnderlayGraphModel(getUnderlayGraphModelConfig()); + new UnderlayGraphModel(this.getUnderlayGraphModelConfig()); + this.model = graphModel; + this.listenTo(graphModel, "change", function(updatedGraphModel) { + if (contrail.checkIfExist(updatedGraphModel.elementsDataObj)) { + self.addElementsToGraph(updatedGraphModel.elementsDataObj.elements, + updatedGraphModel); + } + }); + graphModel.fetchData(); + self.$el.html(graphTemplate()); - var graphView = new GraphView(getUnderlayGraphViewConfig( - graphModel, selectorId, self)); - $(selectorId).data('graphView', graphView); - graphView.render(); + + $("#"+ctwl.UNDERLAY_GRAPH_ID).data('graphModel', graphModel); + var graphWidth = $(selectorId).width(); + var graphHeight = $(selectorId).height(); + this.nodesDataSet = new vis.DataSet([]); + this.edgesDataSet = new vis.DataSet([]); + var container = document.getElementById(ctwl.UNDERLAY_GRAPH_ID); + this.network = new vis.Network(container, { + nodes: this.nodesDataSet, + edges: this.edgesDataSet + }, + this.visOptions); + var _network = this.network; + this.network.on("blurNode", function(node){ + self.resetTooltip(); + }); + + this.network.on("dragEnd", function(node){ + self.resetTooltip(); + }); + + $(document).bind('mousemove',function(e) { + self.cursorPosition = { + "left": e.pageX, + "top": e.pageY + }; + }); + this.network.on("showPopup", function(elementId){ + var timer = null; + var tooltipConfig = null; + var hoveredElement = _network.canvas.body.nodes[elementId]; + if(!hoveredElement) { //not a node. check if edges with elementId present. + hoveredElement = _network.body.data.edges._data[elementId]; + tooltipConfig = hoveredElement.tooltipConfig; + if(!hoveredElement || !tooltipConfig) + return; //return if not a node or edge or no tooltip config + } else { + tooltipConfig = hoveredElement.options.tooltipConfig; + } + + self.tooltipConfigWidth = tooltipConfig.dimension.width; + self.tooltipConfigHeight = tooltipConfig.dimension.height; + var ttPosition = $(".vis-network-tooltip").offset(); + var cursorPosition = self.cursorPosition; + var diffPosition = { + top: cursorPosition.top, + left: cursorPosition.left - 20 + }; + $('.popover').remove(); + $(".vis-network-tooltip").offset(diffPosition); + var tt = $(".vis-network-tooltip").popover({ + trigger: 'hover', + html: true, + animation: false, + placement: function (context, src) { //src is mouse position + var srcOffset = $(src).offset(), + srcWidth = $(src)[0].getBoundingClientRect().width, + bodyWidth = $('body').width(), + bodyHeight = $('body').height(), + tooltipWidth = self.tooltipConfigWidth; + + $(context).addClass('popover-tooltip'); + $(context).css({ + 'min-width': tooltipWidth + 'px', + 'max-width': tooltipWidth + 'px' + }); + $(context).addClass('popover-tooltip'); + + if (srcOffset.left > tooltipWidth) { + return 'left'; + } else if (bodyWidth - (srcOffset.left) - srcWidth > tooltipWidth){ + return 'right'; + } else if (srcOffset.top > bodyHeight / 2){ + return 'top'; + } else { + return 'bottom'; + } + }, + + title: function () { + return tooltipConfig.title; + }, + content: function () { + return tooltipConfig.content; + }, + container: $('body') + }) + $(".vis-network-tooltip").popover("show"); + $('.popover').find('.btn').on('click', function() { + var actionKey = $(this).data('action'), + actionsCallback = tooltipConfig.actionsCallback(tt); + actionsCallback[actionKey].callback(); + $(".vis-network-tooltip").popover("hide"); + }); + $('.popover').find('i.icon-remove').on('click', function() { + $(".vis-network-tooltip").popover("hide"); + }); + $(".vis-network-tooltip").css({ + 'width': '0px', + 'height': '0px', + 'background-color': 'transparent', + 'border': 'transparent', + 'box-shadow': '0px 0px rgba(255, 255, 255, 0)', + 'fill': 'transparent' + }); + }); + + this.network.on("click", function(params) { + var parameters = params; + timeout = setTimeout(function() { + var params = parameters; + + if (params.nodes.length == 1) { + var clickedElement = _network.canvas.body.nodes[params.nodes[0]]; + self.resetConnectedElements(); + var node = self.nodesDataSet.get(params.nodes[0]); + node.icon.color = self.style.defaultSelected.color; + self.nodesDataSet.update(node); + var elementType = clickedElement.options.type; + switch (elementType) { + case 'PhysicalRouter': + var nodeDetails = clickedElement.options.nodeDetails; + if (nodeDetails['more_attributes']['ifTable'] == '-') + nodeDetails['more_attributes']['ifTable'] = []; + graphModel.selectedElement.set({ + 'nodeType': ctwc.PROUTER, + 'nodeDetail': nodeDetails}); + graphModel.selectedElement.set({ + 'nodeType': '', + 'nodeDetail': {}},{silent:true}); + break; + case 'VirtualRouter': + var nodeDetails = clickedElement.options.nodeDetails; + graphModel.selectedElement.set({ + 'nodeType': ctwc.VROUTER, + 'nodeDetail': nodeDetails}); + graphModel.selectedElement.set({ + 'nodeType': '', + 'nodeDetail': {}},{silent:true}); + break; + case 'VirtualMachine': + var nodeDetails = clickedElement.options.nodeDetails; + graphModel.selectedElement.set({ + 'nodeType': ctwc.VIRTUALMACHINE, + 'nodeDetail': nodeDetails}); + graphModel.selectedElement.set({ + 'nodeType': '', + 'nodeDetail': {}},{silent:true}); + break; + } + } else if (params.edges.length == 1) { + var data = {}; + var linkDetails = _network.body.data.edges._data[params.edges[0]].linkDetails; + var clickedElement = _network.canvas.body.edges[params.edges[0]]; + self.resetConnectedElements(); + var edge = self.edgesDataSet.get(params.edges[0]); + edge.color = self.style.defaultSelected.color; + self.edgesDataSet.update(edge); + var targetElement = clickedElement.to; + var sourceElement = clickedElement.from; + var endpoints = [sourceElement['options']['nodeDetails']['name'], + targetElement['options']['nodeDetails']['name']]; + self.addHighlightToNodesAndLinks( + [targetElement['options']['nodeDetails'], + sourceElement['options']['nodeDetails']], + null, + graphModel); + var linkDetail = {}; + linkDetail['endpoints'] = endpoints; + linkDetail['sourceElement'] = sourceElement['options']['nodeDetails']; + linkDetail['targetElement'] = targetElement['options']['nodeDetails']; + graphModel.selectedElement.set({ + 'nodeType': ctwc.UNDERLAY_LINK, + 'nodeDetail': linkDetail}); + graphModel.selectedElement.set({ + 'nodeType': '', + 'nodeDetail': {}},{silent:true}); + + } else if (params.edges.length == 0 && params.nodes.length == 0) { + $(".vis-network-tooltip").popover("hide"); + } + timeout = null; + }, 300); + }); + + this.network.on("doubleClick", function(params) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + if (params.nodes.length == 1) { + self.removeLinkArrows(); + var dblClickedElement = (_network.findNode(params.nodes[0]))[0]; + var nodeDetails = dblClickedElement.options.nodeDetails; + var elementType = dblClickedElement.options.type; + switch (elementType) { + case 'PhysicalRouter': + var chassis_type = nodeDetails['chassis_type']; + if (chassis_type === "tor") { + graphModel.selectedElement.set({ + 'nodeType': ctwc.PROUTER, + 'nodeDetail': nodeDetails}); + var children = graphModel.getChildren( + nodeDetails['name'], "virtual-router"); + var adjList = _.clone( + graphModel['underlayAdjacencyList']); + if (children.length > 0) { + var childrenName = []; + for (var i = 0; i < children.length; i++) { + childrenName.push(children[i]["name"]); + adjList[children[i]["name"]] = []; + } + adjList[nodeDetails['name']] = childrenName; + graphModel['adjacencyList'] = adjList; + var childElementsArray = self + .createElementsFromAdjacencyList(graphModel); + self.addElementsToGraph(childElementsArray, + graphModel); + self.markErrorNodes(); + self.addDimlightToConnectedElements(); + var thisNode = [nodeDetails]; + self.addHighlightToNodesAndLinks(thisNode, childElementsArray, graphModel); + var graphData = { + nodes: this.nodesDataSet, + edges: this.edgesDataSet + }; + } + } + break; + case 'VirtualRouter': + graphModel.selectedElement.set({ + 'nodeType': ctwc.VROUTER, + 'nodeDetail': nodeDetails}); + var parentNode = null; + if(graphModel.underlayPathIds.length > 0) { + $.each(_network.getConnectedEdges(params.nodes[0]), function(idx, edge_id) { + var connectedNodes = _network.getConnectedNodes(edge_id); + var connectedNode0 = self.nodesDataSet.get(connectedNodes[0]); + var connectedNode1 = self.nodesDataSet.get(connectedNodes[1]); + if(connectedNode0 && + connectedNode0.nodeDetails.node_type == "physical-router") { + parentNode = connectedNode0; + } else if (connectedNode1 && + connectedNode1.nodeDetails.node_type == "physical-router") { + parentNode = connectedNode1; + } + }); + } + var siblings = []; //vrouter siblings + if(parentNode !== null) { + siblings = graphModel.getChildren(parentNode.nodeDetails['name'], + "virtual-router"); + } + var children = graphModel.getChildren(nodeDetails['name'], + "virtual-machine"); + var newAdjList = {}; + var oldAdjList = {}; + if(graphModel['underlayPathIds'].length > 0) { + newAdjList = _.clone(graphModel['underlayAdjacencyList']); + oldAdjList = _.clone(graphModel['underlayAdjacencyList']); + } + else { + newAdjList = _.clone(graphModel['adjacencyList']); + oldAdjList = _.clone(graphModel['adjacencyList']); + } + if (siblings.length > 0) { + var siblingName = []; + for (var i = 0; i < siblings.length; i++) { + if(siblings[i]["name"] !== dblClickedElement.options.nodeDetails.name) { + siblingName.push(siblings[i]["name"]); + newAdjList[siblings[i]["name"]] = []; + } + } + newAdjList[parentNode.nodeDetails['name']] = siblingName; + oldAdjList = _.clone(newAdjList); + oldAdjList[parentNode.nodeDetails['name']] = []; + } + if (children.length > 0) { + var childrenName = []; + for (var i = 0; i < children.length; i++) { + childrenName.push(children[i]["name"]); + newAdjList[children[i]["name"]] = []; + } + newAdjList[nodeDetails['name']] = childrenName; + } else { + newAdjList = oldAdjList; + } + graphModel['adjacencyList'] = newAdjList; + var childElementsArray = self.createElementsFromAdjacencyList(graphModel); + self.addElementsToGraph(childElementsArray, graphModel); + self.addDimlightToConnectedElements(); + var thisNode = [nodeDetails]; + self.addHighlightToNodesAndLinks(thisNode, childElementsArray, graphModel); + self.markErrorNodes(); + graphModel['adjacencyList'] = oldAdjList; + self.removeUnderlayPathIds(); + graphModel['underlayPathIds'] = []; + break; + } + } + }); + // Drawing the underlay path and trace flow for a given flow graphModel.flowPath.on('change:nodes', function () { + self.removeLinkArrows(); var nodes = graphModel.flowPath.get('nodes'); var links = graphModel.flowPath.get('links'); if(nodes.length <=0 || links.length <= 0){ showInfoWindow("Cannot Map the path for selected flow", "Info"); - resetTopology({ + self.resetTopology({ resetBelowTabs: false, model: graphModel }); @@ -62,7 +438,7 @@ define([ } } graphModel['adjacencyList'] = adjList; - var childElementsArray = graphModel.createElementsFromAdjacencyList(); + var childElementsArray = self.createElementsFromAdjacencyList(graphModel); var tors = graphModel['tors']; for(var i=0; i 0) + self.addDimlightToConnectedElements(); for (var i = 0; i < links.length; i++) { var endpoints = links[i].endpoints; var endpoint0 = endpoints[0]; var endpoint1 = endpoints[1]; - var link = elementMap.link[endpoint0 + "<->" + endpoint1]; - if(null == link || typeof link === "undefined") - continue; + var linkName = endpoint0 + "<->" + endpoint1; + var altLinkName = endpoint1 + "<->" + endpoint0; + var link = elementMap.link[linkName]; + var existingLink = null; + var parentNodeExists = elementMap.node[endpoint0]; + var childNodeExists = elementMap.node[endpoint1]; + var parentNode = null; + var childNode = null; + if(null !== parentNodeExists && typeof parentNodeExists !== "undefined") + parentNode = self.nodesDataSet.get(elementMap.node[endpoint0]); + else { + parentNode = jsonPath(graphModel.nodes, '$[?(@.name=="' + + endpoint0 + '")]'); + if (false !== parentNode && parentNode.length === 1) { + parentNode = parentNode[0]; + var parentName = parentNode.name; + var parentNodeType = parentNode.node_type; + var currentEl = self.createNode(parentNode); + graphmodel.conElements.push(currentEl); + var currentElId = currentEl.id; + elementMap.node[parentName] = currentElId; + } + } + if(null !== childNodeExists && typeof childNodeExists !== "undefined") + childNode = self.nodesDataSet.get(elementMap.node[endpoint1]); else { - if(typeof $("g.link[model-id='" + link + "']").find('path.connection-wrap') == "object" && - $("g.link[model-id='" + link + "']").find('path.connection-wrap').length === 1) { - connectionWrapIds.push($("g.link[model-id='" + link + "']").find('path.connection-wrap')[0].id); - $("g.link[model-id='" + link + "']") - .css("opacity", "1"); + childNode = jsonPath(graphModel.nodes, '$[?(@.name=="' + + endpoint0 + '")]'); + if (false !== childNode && childNode.length === 1) { + childNode = childNode[0]; + var childName = childNode.name; + var childNodeType = childNode.node_type; + var currentEl = self.createNode(childNode); + graphmodel.conElements.push(currentEl); + var currentElId = currentEl.id; + elementMap.node[childName] = currentElId; } } + var parentId = parentNode.id; + var parentNodeType = parentNode.nodeDetails.node_type; + var childNodeType = childNode.nodeDetails.node_type; + var childId = childNode.id; + var link_type = parentNodeType.split("-")[0][0] + + parentNodeType.split("-")[1][0] + '-' + + childNodeType.split("-")[0][0] + + childNodeType.split("-")[1][0]; + + var arrowPosition = ""; + if(graphModel.elementMap.node[endpoint0] == parentId) { + arrowPosition = "to"; + } else { + arrowPosition = "from"; + } + + var newLink = self.createLink(links[i], link_type, parentId, childId, true, arrowPosition); + var currentLinkId = newLink.id; + self.edgesDataSet.add(newLink); + elementMap.link[linkName] = currentLinkId; + elementMap.link[altLinkName] = currentLinkId; + connectionWrapIds.push(currentLinkId); } if(connectionWrapIds.length > 0) { graphModel['underlayPathIds'] = connectionWrapIds; - monitorInfraUtils.showFlowPath(connectionWrapIds, null, graphModel); } // When the underlay path is same for earlier flow and // current flow change events are not triggering so we need to // reset the nodes and links to empty array once the path is plotted. + graphModel['adjacencyList'] = graphModel['underlayAdjacencyList']; graphModel.flowPath.set('nodes',[], {silent: true}); graphModel.flowPath.set('links',[], {silent: true}); }); + }, - markers: function () {} - }); - function getUnderlayGraphModelConfig() { - return { - forceFit: false, - rankDir: 'TB', - generateElementsFn: function (response) { - return this.getElementsForUnderlayGraph(response); - }, - remote: { - ajaxConfig: { - url: ctwl.URL_UNDERLAY_TOPOLOGY, - type: 'GET' - }, - successCallback: function (response, underlayGraphModel) { - $('#' + ctwl.GRAPH_LOADING_ID).hide(); - if (contrail.checkIfExist(underlayGraphModel.elementsDataObj)){ - var elements = underlayGraphModel.elementsDataObj.elements; - if (elements.length > 0) { - adjustDimensions(elements); - var markers = - monitorInfraUtils.getMarkersForUnderlay(); - var defs = $('#' + ctwl.UNDERLAY_GRAPH_ID ).find('svg').find('defs'); - for(var i=0; i