Merge pull request #18 from hjacobs/unassigned-pods

Draw unassigned pods / colorize bars
This commit is contained in:
Henning Jacobs
2016-12-19 21:39:14 +01:00
committed by GitHub
4 changed files with 73 additions and 17 deletions

18
app.py
View File

@@ -43,6 +43,7 @@ def get_clusters():
response.raise_for_status() response.raise_for_status()
nodes = [] nodes = []
nodes_by_name = {} nodes_by_name = {}
unassigned_pods = []
for node in response.json()['items']: for node in response.json()['items']:
obj = {'name': node['metadata']['name'], 'labels': node['metadata']['labels'], 'status': node['status'], 'pods': []} obj = {'name': node['metadata']['name'], 'labels': node['metadata']['labels'], 'status': node['status'], 'pods': []}
nodes.append(obj) nodes.append(obj)
@@ -50,14 +51,15 @@ def get_clusters():
response = session.get(urljoin(api_server_url, '/api/v1/pods'), timeout=5) response = session.get(urljoin(api_server_url, '/api/v1/pods'), timeout=5)
response.raise_for_status() response.raise_for_status()
for pod in response.json()['items']: for pod in response.json()['items']:
if 'nodeName' in pod['spec']: obj = {'name': pod['metadata']['name'],
obj = {'name': pod['metadata']['name'], 'namespace': pod['metadata']['namespace'],
'namespace': pod['metadata']['namespace'], 'labels': pod['metadata'].get('labels', {}), 'status': pod['status'], 'containers': []}
'labels': pod['metadata']['labels'], 'status': pod['status'], 'containers': []} for cont in pod['spec']['containers']:
for cont in pod['spec']['containers']: obj['containers'].append({'name': cont['name'], 'image': cont['image'], 'resources': cont['resources']})
obj['containers'].append({'name': cont['name'], 'image': cont['image'], 'resources': cont['resources']}) if 'nodeName' in pod['spec'] and pod['spec']['nodeName'] in nodes_by_name:
# TODO: filter pod attributes
nodes_by_name[pod['spec']['nodeName']]['pods'].append(obj) nodes_by_name[pod['spec']['nodeName']]['pods'].append(obj)
else:
unassigned_pods.append(obj)
try: try:
response = session.get(urljoin(api_server_url, '/api/v1/namespaces/kube-system/services/heapster/proxy/apis/metrics/v1alpha1/nodes'), timeout=5) response = session.get(urljoin(api_server_url, '/api/v1/namespaces/kube-system/services/heapster/proxy/apis/metrics/v1alpha1/nodes'), timeout=5)
@@ -66,7 +68,7 @@ def get_clusters():
nodes_by_name[metrics['metadata']['name']]['usage'] = metrics['usage'] nodes_by_name[metrics['metadata']['name']]['usage'] = metrics['usage']
except: except:
logging.exception('Failed to get metrics') logging.exception('Failed to get metrics')
clusters.append({'api_server_url': api_server_url, 'nodes': nodes}) clusters.append({'api_server_url': api_server_url, 'nodes': nodes, 'unassigned_pods': unassigned_pods})
return json.dumps({'kubernetes_clusters': clusters}, separators=(',',':')) return json.dumps({'kubernetes_clusters': clusters}, separators=(',',':'))

View File

@@ -1,4 +1,5 @@
import Node from './node.js' import Node from './node.js'
import Pod from './pod.js'
const PIXI = require('pixi.js') const PIXI = require('pixi.js')
export default class Cluster extends PIXI.Graphics { export default class Cluster extends PIXI.Graphics {
@@ -24,6 +25,17 @@ export default class Cluster extends PIXI.Graphics {
} }
this.addChild(nodeBox) this.addChild(nodeBox)
} }
for (var pod of this.cluster.unassigned_pods) {
var podBox = new Pod(pod, this.tooltip)
podBox.x = rows[0]
podBox.y = 20
podBox.draw()
this.addChild(podBox)
rows[0] += 20
}
this.lineStyle(2, 0xaaaaff, 1); this.lineStyle(2, 0xaaaaff, 1);
const width = Math.max(rows[0], rows[1]) const width = Math.max(rows[0], rows[1])
this.drawRect(0, 0, width, nodeBox.height * 2 + 30); this.drawRect(0, 0, width, nodeBox.height * 2 + 30);

View File

@@ -23,6 +23,34 @@ export default class Node extends PIXI.Graphics {
return parseInt(match[1]) * factor return parseInt(match[1]) * factor
} }
hsvToRgb(h, s, v) {
var r, g, b, i, f, p, q, t;
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0:
r = v, g = t, b = p; break;
case 1:
r = q, g = v, b = p; break;
case 2:
r = p, g = v, b = t; break;
case 3:
r = p, g = q, b = v; break;
case 4:
r = t, g = p, b = v; break;
case 5:
r = v, g = p, b = q; break;
}
return PIXI.utils.rgb2hex([r, g, b])
}
getBarColor(usage, capacity) {
return this.hsvToRgb(0.4 - (0.4 * (usage / capacity)), 0.6, 1)
}
getResourceUsage() { getResourceUsage() {
const resources = {} const resources = {}
for (var key of Object.keys(this.node.status.capacity)) { for (var key of Object.keys(this.node.status.capacity)) {
@@ -88,22 +116,24 @@ export default class Node extends PIXI.Graphics {
}) })
const resources = this.getResourceUsage() const resources = this.getResourceUsage()
const cpuHeight = 80 / resources.cpu.capacity const cpuHeight = 80 / resources.cpu.capacity
nodeBox.lineStyle(2, 0xaaffaa, 1) nodeBox.lineStyle(0, 0xaaffaa, 1)
nodeBox.beginFill(0xaaffaa, 1) nodeBox.beginFill(this.getBarColor(resources.cpu.requested, resources.cpu.capacity), 1)
nodeBox.drawRect(3, 110 - resources.cpu.requested * cpuHeight, 3, resources.cpu.requested * cpuHeight) nodeBox.drawRect(5, 110 - resources.cpu.requested * cpuHeight, 2.5, resources.cpu.requested * cpuHeight)
nodeBox.drawRect(5, 110 - resources.cpu.used * cpuHeight, 5, resources.cpu.used * cpuHeight) nodeBox.beginFill(this.getBarColor(resources.cpu.used, resources.cpu.capacity), 1)
nodeBox.drawRect(7.5, 110 - resources.cpu.used * cpuHeight, 2.5, resources.cpu.used * cpuHeight)
nodeBox.endFill() nodeBox.endFill()
nodeBox.lineStyle(2, 0xaaaaaa, 1); nodeBox.lineStyle(1, 0xaaaaaa, 1);
for (var i=0; i<resources.cpu.capacity; i++) { for (var i=0; i<resources.cpu.capacity; i++) {
nodeBox.drawRect(5, 110 - (i+1) * cpuHeight, 5, cpuHeight) nodeBox.drawRect(5, 110 - (i+1) * cpuHeight, 5, cpuHeight)
} }
const scale = resources.memory.capacity / 80 const scale = resources.memory.capacity / 80
nodeBox.drawRect(14, 110 - resources.memory.capacity/scale, 5, resources.memory.capacity/scale) nodeBox.drawRect(14, 110 - resources.memory.capacity/scale, 5, resources.memory.capacity/scale)
nodeBox.lineStyle(2, 0xaaffaa, 1) nodeBox.lineStyle(0, 0xaaffaa, 1)
nodeBox.beginFill(0xaaffaa, 1) nodeBox.beginFill(this.getBarColor(resources.memory.requested, resources.memory.capacity), 1)
nodeBox.drawRect(13, 110 - resources.memory.requested/scale, 3, resources.memory.requested/scale) nodeBox.drawRect(14, 110 - resources.memory.requested/scale, 2.5, resources.memory.requested/scale)
nodeBox.drawRect(15, 110 - resources.memory.used/scale, 3, resources.memory.used/scale) nodeBox.beginFill(this.getBarColor(resources.memory.used, resources.memory.capacity), 1)
nodeBox.drawRect(16.5, 110 - resources.memory.used/scale, 2.5, resources.memory.used/scale)
nodeBox.endFill() nodeBox.endFill()
var text = new PIXI.Text('', {fontSize: 10, fill: 0xffffff}) var text = new PIXI.Text('', {fontSize: 10, fill: 0xffffff})
nodeBox.addChild(text) nodeBox.addChild(text)

View File

@@ -0,0 +1,12 @@
# example Pod which cannot be assigned to any node
apiVersion: v1
kind: Pod
metadata:
name: unassigned-test
spec:
# use a node selector which will never match..
nodeSelector:
stuff: x
containers:
- name: test
image: foo