diff --git a/index.html b/index.html index 9fb7032..4df3d9f 100644 --- a/index.html +++ b/index.html @@ -29,6 +29,7 @@
diff --git a/script.js b/script.js index 9d04c45..b4f4f42 100644 --- a/script.js +++ b/script.js @@ -33,26 +33,53 @@ var controllers = []; var uses = {}; var groups = {}; +var instance; +var timeoutFunction; +var repainting = false; -var insertByName = function(index, value) { +var insertByNameOrType = function(index, value) { if (!value || !value.metadata.labels || !value.metadata.name) { return; } - // console.log("type = " + value.type + " labels = " + value.metadata.name); - // var list = groups[value.metadata.name]; - var key = value.metadata.labels.name; - var list = groups[key]; - if (!list) { + var key = getNodeKey(value); + addGroupName(key); + if (!isVisibleGroup(key)){ + return; + } + var list = groups[key]; + if (!list) { list = []; groups[key] = list; - } - list.push(value); + } + list.push(value); }; -var groupByName = function() { - $.each(pods.items, insertByName); - $.each(controllers.items, insertByName); - $.each(services.items, insertByName); +function isVisibleGroup(key){ + if ($("input#"+key).length != 0 && $("input#"+key).prop("checked") ){ + return true; + } + return false; +} + +function clearGroupNames(){ + $("group-names").clear(); +} + + +function addGroupName(groupName){ + if ($("input#"+groupName).length == 0){ + $("#group-names").append(""+groupName+""); + } +} + +function getNodeKey(itemNode){ + return (itemNode.metadata.labels.type ? itemNode.metadata.labels.type : itemNode.metadata.labels.name); +} + +var groupByNameOrType = function() { + $.each(pods.items, insertByNameOrType); + $.each(controllers.items, insertByNameOrType); + $.each(services.items, insertByNameOrType); }; var matchesLabelQuery = function(labels, selector) { @@ -69,15 +96,15 @@ var connectControllers = function() { connectUses(); for (var i = 0; i < controllers.items.length; i++) { var controller = controllers.items[i]; - //console.log("controller: " + controller.metadata.name) + //console.log("controller: " + controller.metadata.name) for (var j = 0; j < pods.items.length; j++) { var pod = pods.items[j]; - if (pod.metadata.labels.name == controller.metadata.labels.name) { - if (controller.metadata.labels.version && pod.metadata.labels.version && (controller.metadata.labels.version != pod.metadata.labels.version)) { - continue; - } - //console.log('connect controller: ' + 'controller-' + controller.metadata.name + ' to pod-' + pod.metadata.name); - jsPlumb.connect({ + if (isVisibleGroup(getNodeKey(pod)) && getNodeKey(pod) == getNodeKey(controller)) { + if (controller.metadata.labels.version && pod.metadata.labels.version && (controller.metadata.labels.version != pod.metadata.labels.version)) { + continue; + } + //console.log('connect controller: ' + 'controller-' + controller.metadata.name + ' to pod-' + pod.metadata.name); + instance.connect({ source: 'controller-' + controller.metadata.name, target: 'pod-' + pod.metadata.name, anchors:["Bottom", "Bottom"], @@ -90,12 +117,11 @@ var connectControllers = function() { } for (var i = 0; i < services.items.length; i++) { var service = services.items[i]; - // if (service.metadata.name == 'kubernetes' || service.metadata.name == 'skydns' || service.metadata.name == 'kubernetes-ro') { continue; } for (var j = 0; j < pods.items.length; j++) { var pod = pods.items[j]; - //console.log('connect service: ' + 'service-' + service.metadata.name + ' to pod-' + pod.metadata.name); - if (matchesLabelQuery(pod.metadata.labels, service.spec.selector)) { - jsPlumb.connect( + //console.log('connect service: ' + 'service-' + service.metadata.name + ' to pod-' + pod.metadata.name); + if (isVisibleGroup(getNodeKey(pod)) && matchesLabelQuery(pod.metadata.labels, service.spec.selector)) { + instance.connect( { source: 'service-' + service.metadata.name, target: 'pod-' + pod.metadata.name, @@ -128,20 +154,21 @@ var connectUses = function() { colorIx++; if (colorIx >= colors.length) { colorIx = 0;}; $.each(pods.items, function(i, pod) { - var podKey = pod.metadata.labels.name; - //console.log('connect uses key: ' +key + ', ' + podKey); + var podKey = getNodeKey(pod); + //console.log('connect uses key: ' +key + ', ' + podKey); if (podKey == key) { $.each(list, function(j, serviceId) { - //console.log('connect: ' + 'pod-' + pod.metadata.name + ' to service-' + serviceId); - jsPlumb.connect( + //console.log('connect: ' + 'pod-' + pod.metadata.name + ' to service-' + serviceId); + if ( ($('#service-' + serviceId).length != 0) && ($('#pod-' + pod.metadata.name).length != 0) ){ + instance.connect( { - source: 'pod-' + pod.metadata.name, + source: 'pod-' + pod.metadata.name, target: 'service-' + serviceId, endpoint: "Blank", //anchors:["Bottom", "Top"], - anchors:[[ 0.5, 1, 0, 1, -30, 0 ], "Top"], + anchors:[[ 0.5, 1, 0, 1, -30, 0 ], "Top"], //connector: "Straight", - connector: ["Bezier", { curviness:75 }], + connector: ["Bezier", { curviness:75 }], paintStyle:{lineWidth:2,strokeStyle:color}, overlays:[ [ "Arrow", { width:15, length:30, location: 0.3}], @@ -149,6 +176,12 @@ var connectUses = function() { [ "Arrow", { width:15, length:30, location: 1}], ], }); + + + + }else{ + console.log('Could not connect: ' + 'pod-' + pod.metadata.name + ' to service-' + serviceId + " Are you using meta.label.name of the service as the uses label?"); + } }); } }); @@ -163,7 +196,7 @@ var makeGroupOrder = function() { groupScores[key] = 0; } if (uses[key]) { - value = uses[key]; + value = uses[key]; $.each(value, function(ix, uses_label) { if (!groupScores[uses_label]) { groupScores[uses_label] = 1; @@ -171,6 +204,7 @@ var makeGroupOrder = function() { groupScores[uses_label]++; } }); + groupScores[key]++; } else { if (!groupScores["no-service"]) { groupScores["no-service"] = 1; @@ -179,102 +213,95 @@ var makeGroupOrder = function() { } } }); + var groupOrder = []; $.each(groupScores, function(key, value) { groupOrder.push(key); - }); + }); + groupOrder.sort(function(a, b) { return groupScores[a] - groupScores[b]; }); - - //console.log(groupOrder); return groupOrder; }; var renderNodes = function() { - var y = 25; - var x = 100; - $.each(nodes.items, function(index, value) { - console.log(value); + + $.each(nodes.items, function(index, value) { + console.log(value); var div = $('
'); - var ready = 'not_ready'; - $.each(value.status.conditions, function(index, condition) { - if (condition.type === 'Ready') { - ready = (condition.status === 'True' ? 'ready' : 'not_ready' ) - } - }); + var ready = isComponentReady(value); - var eltDiv = $('
'); - eltDiv.html('Node

' + - truncate(value.metadata.name, 6) + - '
'); - div.append(eltDiv); + var eltDiv = $('
' ); + eltDiv.html('Node

' + truncate(value.metadata.name, 6) + '
'); + + div.append(eltDiv); - var elt = $('.nodesbar'); + var elt = $('.nodesbar'); elt.append(div); - - x += 120; - }); + }); + } var renderGroups = function() { + var elt = $('#sheet'); - var y = 10; - var serviceLeft = 0; var groupOrder = makeGroupOrder(); - var counts = {} + var counts = {} + $.each(groupOrder, function(ix, key) { list = groups[key]; // list = value; - if (!list) { - return; - } - var div = $('
'); - var x = 100; + if (!list) { + return; + } + + var div = $('
'); + var services = $('
'); + var pods = $('
'); + var controllers= $('
'); + + div.append(services); + div.append(pods); + div.append(controllers); + $.each(list, function(index, value) { - //console.log("render groups: " + value.type + ", " + value.metadata.name + ", " + index) + //console.log("render groups: " + value.type + ", " + value.metadata.name + ", " + index) var eltDiv = null; - console.log(value); - var phase = value.status.phase ? value.status.phase.toLowerCase() : ''; + console.log(value); + var phase = value.status.phase ? value.status.phase.toLowerCase() : ''; + if (value.type == "pod") { - if ('deletionTimestamp' in value.metadata) { - phase = 'terminating'; - } - eltDiv = $('
'); + var status = phase; + if (status == 'running'){ + status = isComponentReady(value); + }else if ('deletionTimestamp' in value.metadata) { + status = 'terminating'; + } + + eltDiv = $('
'); eltDiv.html('' + - truncate(value.metadata.name, 8, true) + - (value.metadata.labels.version ? "
" + value.metadata.labels.version : "") + "

" + - "(" + (value.spec.nodeName ? truncate(value.spec.nodeName, 6) : "None") +")" + - '
'); + truncate(value.metadata.name, 8, true) + + (value.metadata.labels.version ? "
" + value.metadata.labels.version : "") + "

" + + "(" + (value.spec.nodeName ? truncate(value.spec.nodeName, 6) : "None") +")" + + ''); + pods.append(eltDiv); } else if (value.type == "service") { - eltDiv = $('
'); + eltDiv = $('
'); eltDiv.html('' + - value.metadata.name + - (value.metadata.labels.version ? "

" + value.metadata.labels.version : "") + - (value.spec.clusterIP ? "

" + value.spec.clusterIP : "") + - (value.status.loadBalancer && value.status.loadBalancer.ingress ? "
" + value.status.loadBalancer.ingress[0].ip + "" : "") + - '
'); + value.metadata.name + + (value.metadata.labels.version ? "

" + value.metadata.labels.version : "") + + (value.spec.clusterIP ? "

" + value.spec.clusterIP : "") + + (value.status.loadBalancer && value.status.loadBalancer.ingress ? "
" + value.status.loadBalancer.ingress[0].ip + "" : "") + + ''); + services.append(eltDiv); } else { - var key = 'controller-' + value.metadata.labels.name; - counts[key] = key in counts ? counts[key] + 1 : 0; - //eltDiv = $('
'); - var minLeft = 900; - var calcLeft = 400 + (value.status.replicas * 130); - var left = minLeft > calcLeft ? minLeft : calcLeft; - eltDiv = $('
'); - eltDiv.html('' + - value.metadata.name + - (value.metadata.labels.version ? "

" + value.metadata.labels.version : "") + - '
'); + eltDiv = $('
'); + eltDiv.html('' + value.metadata.name + + (value.metadata.labels.version ? "

" + value.metadata.labels.version : "") + + '
'); + controllers.append(eltDiv); } - div.append(eltDiv); - x += 130; + }); - y += 400; - serviceLeft += 200; elt.append(div); }); }; @@ -293,16 +320,16 @@ var loadData = function() { var req1 = $.getJSON("/api/v1/pods?labelSelector=visualize%3Dtrue", function( data ) { pods = data; $.each(data.items, function(key, val) { - val.type = 'pod'; - if (val.metadata.labels && val.metadata.labels.uses) { - var key = val.metadata.labels.name; - if (!uses[key]) { - uses[key] = val.metadata.labels.uses.split("_"); - } else { - $.each(val.metadata.labels.uses.split("_"), function(ix, use) { insertUse(key, use); }); - } - } - }); + val.type = 'pod'; + if (val.metadata.labels && val.metadata.labels.uses) { + var key = getNodeKey(val); + if (!uses[key]) { + uses[key] = val.metadata.labels.uses.split("_"); + } else { + $.each(val.metadata.labels.uses.split("_"), function(ix, use) { insertUse(key, use); }); + } + } + }); }); var req2 = $.getJSON("/api/v1/replicationcontrollers?labelSelector=visualize%3Dtrue", function( data ) { @@ -319,9 +346,9 @@ var loadData = function() { //console.log("loadData(): Services"); //console.log(services); $.each(data.items, function(key, val) { - val.type = 'service'; - //console.log("service ID = " + val.metadata.name) - }); + val.type = 'service'; + //console.log("service ID = " + val.metadata.name) + }); }); var req4 = $.getJSON("/api/v1/nodes", function( data ) { @@ -342,36 +369,52 @@ var loadData = function() { return deferred; } -function refresh(instance) { +function refresh() { + + if (repainting){ + return; + } + pods = []; services = []; controllers = []; - nodes = []; + nodes = []; uses = {}; groups = {}; - - + $.when(loadData()).then(function() { - groupByName(); - $('#sheet').empty(); - renderNodes(); - renderGroups(); - connectControllers(); - - setTimeout(function() { - refresh(instance); - }, 2000); + if (!repainting){ + groupByNameOrType(); + instance.reset(); + $('.nodesbar').empty(); + $('.group').empty(); + $('#sheet').empty(); + renderNodes(); + renderGroups(); + connectControllers(); + } }); } +function isComponentReady (component){ + var ready = 'not_ready'; + $.each(component.status.conditions, function(index, condition) { + if (condition.type === 'Ready') { + ready = (condition.status === 'True' ? 'ready' : 'not_ready' ) + } + }); + return ready; +} + jsPlumb.bind("ready", function() { - var instance = jsPlumb.getInstance({ + + instance = jsPlumb.getInstance({ // default drag options DragOptions : { cursor: 'pointer', zIndex:2000 }, // the overlays to decorate each connection with. note that the label overlay uses a function to generate the label text; in this // case it returns the 'labelText' member that we set on each connection in the 'init' method below. ConnectionOverlays : [ - [ "Arrow", { location:1 } ], + //[ "Arrow", { location:1 } ], //[ "Label", { // location:0.1, // id:"label", @@ -381,6 +424,19 @@ jsPlumb.bind("ready", function() { Container:"flowchart-demo" }); - refresh(instance); - jsPlumb.fire("jsPlumbDemoLoaded", instance); - }); + refresh(); + scheduleRefresh(); +}); + +function scheduleRefresh(){ + timeoutFunction= setInterval(function() { + refresh(); + }, 3000); +} + +$( window ).resize(function() { + repainting = true; + instance.repaintEverything(); + repainting = false; +}); + diff --git a/style.css b/style.css index 4198bf3..55fefbf 100644 --- a/style.css +++ b/style.css @@ -5,16 +5,62 @@ .service { background-color: rgb(0,153,57); color: white; + min-width: 130px; + min-height: 100px + height: 100px; + width: 100px; +} + +.group { + padding: 2%; + display: inline; + float: left; + clear: both; + width: 100%; + min-width: 100%; +} + +.services{ + clear: both; + float: left; + display: inline; + position: inherit; + margin: 3%; +} +.pods{ + clear: both; + float: left; + display: inline; + position: inherit; + width: 90%; + min-width: 90%; } +.controllers{ + clear: both; + float: left; + display: inline; + position: inherit; + width: 90%; +} .controller { background-color:rgb(51,105,232); color: white; + min-width: 130px; + min-height: 100px + height: 100px; + width: 100px; + clear: none; + float: right !important; } .pod { + min-width: 100px; + min-height: 100px + height: 100px; width: 100px; background-color:#eeeeef; + margin: 1%; } .pending { @@ -23,12 +69,16 @@ .window { line-height: 1em; - display: table; + display: inline; + float: left; + position: relative !important; } .window span { display: table-cell; vertical-align: middle; + float: none; + display: block; } .logo { @@ -63,15 +113,21 @@ left: 0; right: 0; top: 50px; - height: 200px; + height: 160px; background-color: light-grey; border-bottom: thick solid black; } .not_ready { - background-color: red; + background-color: #FF7F24; } .terminating { background-color: red; } + +#group-names{ + float:right; + padding-right:5%; +} +