Dynamic sizing nodes (#208)
* dynamic sizing nodes * remove whitespaces
This commit is contained in:
committed by
Henning Jacobs
parent
c352bc444e
commit
8efc01d640
@@ -29,6 +29,13 @@ export default class App {
|
||||
this.clusterStatuses = new Map()
|
||||
this.viewContainerTargetPosition = new PIXI.Point()
|
||||
this.bootstrapping = true
|
||||
|
||||
this.startDrawingPodsAt = 24
|
||||
this.defaultPodsPerRow = 6
|
||||
this.defaultWidthOfNodePx = 105
|
||||
this.defaultHeightOfNodePx = 115
|
||||
this.sizeOfPodPx = 13
|
||||
this.heightOfTopHandlePx = 15
|
||||
}
|
||||
|
||||
parseLocationHash() {
|
||||
|
||||
@@ -14,41 +14,42 @@ export default class Bars extends PIXI.Graphics {
|
||||
draw() {
|
||||
const bars = this
|
||||
|
||||
const barHeight = 92
|
||||
const barHeightPx = bars.entity.cluster.heightOfNodePx - (App.current.heightOfTopHandlePx + 5 + 3)
|
||||
const heightOfNodeWoPaddingPx = bars.entity.cluster.heightOfNodePx - 5
|
||||
|
||||
bars.beginFill(App.current.theme.primaryColor, 0.1)
|
||||
bars.drawRect(5, 110 - barHeight, 15, barHeight)
|
||||
bars.drawRect(5, heightOfNodeWoPaddingPx - barHeightPx, 15, barHeightPx)
|
||||
bars.endFill()
|
||||
|
||||
// CPU
|
||||
const cpuHeight = barHeight / bars.resources.cpu.capacity
|
||||
const cpuHeight = barHeightPx / bars.resources.cpu.capacity
|
||||
bars.interactive = true
|
||||
bars.lineStyle(0, 0xaaffaa, 1)
|
||||
bars.beginFill(getBarColor(bars.resources.cpu.requested, bars.resources.cpu.capacity - bars.resources.cpu.reserved), 1)
|
||||
bars.drawRect(5, 110 - (bars.resources.cpu.requested + bars.resources.cpu.reserved) * cpuHeight, 2.5, (bars.resources.cpu.requested + bars.resources.cpu.reserved) * cpuHeight)
|
||||
bars.drawRect(5, heightOfNodeWoPaddingPx - (bars.resources.cpu.requested + bars.resources.cpu.reserved) * cpuHeight, 2.5, (bars.resources.cpu.requested + bars.resources.cpu.reserved) * cpuHeight)
|
||||
bars.beginFill(getBarColor(bars.resources.cpu.used, bars.resources.cpu.capacity), 1)
|
||||
bars.drawRect(7.5, 110 - bars.resources.cpu.used * cpuHeight, 2.5, bars.resources.cpu.used * cpuHeight)
|
||||
bars.drawRect(7.5, heightOfNodeWoPaddingPx - bars.resources.cpu.used * cpuHeight, 2.5, bars.resources.cpu.used * cpuHeight)
|
||||
bars.endFill()
|
||||
bars.lineStyle(1, App.current.theme.primaryColor, 1)
|
||||
bars.drawRect(5, 110 - bars.resources.cpu.reserved * cpuHeight, 5, bars.resources.cpu.reserved * cpuHeight)
|
||||
bars.drawRect(5, heightOfNodeWoPaddingPx - bars.resources.cpu.reserved * cpuHeight, 5, bars.resources.cpu.reserved * cpuHeight)
|
||||
|
||||
// Memory
|
||||
const scale = bars.resources.memory.capacity / barHeight
|
||||
const scale = bars.resources.memory.capacity / barHeightPx
|
||||
bars.lineStyle(0, 0xaaffaa, 1)
|
||||
bars.beginFill(getBarColor(bars.resources.memory.requested, bars.resources.memory.capacity - bars.resources.memory.reserved), 1)
|
||||
bars.drawRect(14, 110 - (bars.resources.memory.requested + bars.resources.memory.reserved) / scale, 2.5, (bars.resources.memory.requested + bars.resources.memory.reserved) / scale)
|
||||
bars.drawRect(14, heightOfNodeWoPaddingPx - (bars.resources.memory.requested + bars.resources.memory.reserved) / scale, 2.5, (bars.resources.memory.requested + bars.resources.memory.reserved) / scale)
|
||||
bars.beginFill(getBarColor(bars.resources.memory.used, bars.resources.memory.capacity), 1)
|
||||
bars.drawRect(16.5, 110 - bars.resources.memory.used / scale, 2.5, bars.resources.memory.used / scale)
|
||||
bars.drawRect(16.5, heightOfNodeWoPaddingPx - bars.resources.memory.used / scale, 2.5, bars.resources.memory.used / scale)
|
||||
bars.endFill()
|
||||
bars.lineStyle(1, App.current.theme.primaryColor, 1)
|
||||
bars.drawRect(14, 110 - bars.resources.memory.reserved / scale, 5, bars.resources.memory.reserved / scale)
|
||||
bars.drawRect(14, heightOfNodeWoPaddingPx - bars.resources.memory.reserved / scale, 5, bars.resources.memory.reserved / scale)
|
||||
|
||||
bars.lineStyle(1, App.current.theme.primaryColor, 1)
|
||||
for (var i = 0; i < bars.resources.cpu.capacity; i++) {
|
||||
bars.drawRect(5, 110 - (i + 1) * cpuHeight, 5, cpuHeight)
|
||||
bars.drawRect(5, heightOfNodeWoPaddingPx - (i + 1) * cpuHeight, 5, cpuHeight)
|
||||
}
|
||||
|
||||
bars.drawRect(14, 110 - bars.resources.memory.capacity / scale, 5, bars.resources.memory.capacity / scale)
|
||||
bars.drawRect(14, heightOfNodeWoPaddingPx - bars.resources.memory.capacity / scale, 5, bars.resources.memory.capacity / scale)
|
||||
|
||||
bars.on('mouseover', function () {
|
||||
let s = 'CPU: \n'
|
||||
|
||||
@@ -38,7 +38,34 @@ export default class Cluster extends PIXI.Graphics {
|
||||
let workerWidth = 0
|
||||
let workerHeight = 0
|
||||
const workerNodes = []
|
||||
const maxWidth = window.innerWidth - 130
|
||||
|
||||
let maxPods = 0
|
||||
// get the largest number of pods
|
||||
for (const n of Object.values(this.cluster.nodes)) {
|
||||
const podsInNode = Object.values(n.pods).length
|
||||
if (podsInNode >= maxPods) {
|
||||
maxPods = podsInNode
|
||||
}
|
||||
}
|
||||
|
||||
// with maxPods we can calculate the size of all nodes in the cluster
|
||||
this.podsPerRow = Math.max(
|
||||
App.current.defaultPodsPerRow,
|
||||
Math.ceil(Math.sqrt(maxPods))
|
||||
)
|
||||
|
||||
this.widthOfNodePx = Math.max(
|
||||
App.current.defaultWidthOfNodePx,
|
||||
Math.floor(this.podsPerRow * App.current.sizeOfPodPx + App.current.startDrawingPodsAt + 2)
|
||||
)
|
||||
|
||||
this.heightOfNodePx = Math.max(
|
||||
App.current.defaultHeightOfNodePx,
|
||||
Math.floor(this.podsPerRow * App.current.sizeOfPodPx + App.current.heightOfTopHandlePx + (App.current.sizeOfPodPx * 2) + 2)
|
||||
)
|
||||
|
||||
const maxWidth = window.innerWidth - (this.widthOfNodePx * 1.2)
|
||||
|
||||
for (const nodeName of Object.keys(this.cluster.nodes).sort()) {
|
||||
const node = this.cluster.nodes[nodeName]
|
||||
var nodeBox = new Node(node, this, this.tooltip)
|
||||
@@ -47,29 +74,29 @@ export default class Cluster extends PIXI.Graphics {
|
||||
if (masterX > maxWidth) {
|
||||
masterWidth = masterX
|
||||
masterX = left
|
||||
masterY += nodeBox.height + padding
|
||||
masterHeight += nodeBox.height + padding
|
||||
masterY += this.heightOfNodePx + padding
|
||||
masterHeight += this.heightOfNodePx + padding
|
||||
}
|
||||
if (masterHeight == 0) {
|
||||
masterHeight = nodeBox.height + padding
|
||||
masterHeight = this.heightOfNodePx + padding
|
||||
}
|
||||
nodeBox.x = masterX
|
||||
nodeBox.y = masterY
|
||||
masterX += nodeBox.width + padding
|
||||
masterX += this.widthOfNodePx + padding
|
||||
} else {
|
||||
if (workerX > maxWidth) {
|
||||
workerWidth = workerX
|
||||
workerX = left
|
||||
workerY += nodeBox.height + padding
|
||||
workerHeight += nodeBox.height + padding
|
||||
workerY += this.heightOfNodePx + padding
|
||||
workerHeight += this.heightOfNodePx + padding
|
||||
}
|
||||
workerNodes.push(nodeBox)
|
||||
if (workerHeight == 0) {
|
||||
workerHeight = nodeBox.height + padding
|
||||
workerHeight = this.heightOfNodePx + padding
|
||||
}
|
||||
nodeBox.x = workerX
|
||||
nodeBox.y = workerY
|
||||
workerX += nodeBox.width + padding
|
||||
workerX += this.widthOfNodePx + padding
|
||||
}
|
||||
this.addChild(nodeBox)
|
||||
}
|
||||
@@ -95,7 +122,7 @@ export default class Cluster extends PIXI.Graphics {
|
||||
|
||||
const topHandle = this.topHandle = new PIXI.Graphics()
|
||||
topHandle.beginFill(App.current.theme.primaryColor, 1)
|
||||
topHandle.drawRect(0, 0, width, 15)
|
||||
topHandle.drawRect(0, 0, width, App.current.heightOfTopHandlePx)
|
||||
topHandle.endFill()
|
||||
topHandle.interactive = true
|
||||
topHandle.buttonMode = true
|
||||
|
||||
@@ -64,9 +64,11 @@ export default class Node extends PIXI.Graphics {
|
||||
const nodeBox = this
|
||||
const topHandle = new PIXI.Graphics()
|
||||
topHandle.beginFill(App.current.theme.primaryColor, 1)
|
||||
topHandle.drawRect(0, 0, 105, 15)
|
||||
topHandle.drawRect(0, 0, this.cluster.widthOfNodePx, App.current.heightOfTopHandlePx)
|
||||
topHandle.endFill()
|
||||
const ellipsizedNodeName = this.node.name.length > 17 ? this.node.name.substring(0, 17).concat('…') : this.node.name
|
||||
// there is about 2.83 letters per pod
|
||||
const roomForText = Math.floor(2.83 * this.cluster.podsPerRow)
|
||||
const ellipsizedNodeName = this.node.name.length > roomForText ? this.node.name.substring(0, roomForText).concat('…') : this.node.name
|
||||
const text = new PIXI.Text(ellipsizedNodeName, {fontFamily: 'ShareTechMono', fontSize: 10, fill: 0x000000})
|
||||
text.x = 2
|
||||
text.y = 2
|
||||
@@ -74,7 +76,7 @@ export default class Node extends PIXI.Graphics {
|
||||
nodeBox.addChild(topHandle)
|
||||
nodeBox.lineStyle(2, App.current.theme.primaryColor, 1)
|
||||
nodeBox.beginFill(App.current.theme.secondaryColor, 1)
|
||||
nodeBox.drawRect(0, 0, 105, 115)
|
||||
nodeBox.drawRect(0, 0, this.cluster.widthOfNodePx, this.cluster.heightOfNodePx)
|
||||
nodeBox.endFill()
|
||||
nodeBox.lineStyle(2, 0xaaaaaa, 1)
|
||||
topHandle.interactive = true
|
||||
@@ -85,7 +87,7 @@ export default class Node extends PIXI.Graphics {
|
||||
s += '\n ' + key + ': ' + nodeBox.node.labels[key]
|
||||
}
|
||||
nodeBox.tooltip.setText(s)
|
||||
nodeBox.tooltip.position = nodeBox.toGlobal(new PIXI.Point(0, 15))
|
||||
nodeBox.tooltip.position = nodeBox.toGlobal(new PIXI.Point(0, App.current.heightOfTopHandlePx))
|
||||
nodeBox.tooltip.visible = true
|
||||
})
|
||||
topHandle.on('mouseout', function () {
|
||||
@@ -103,33 +105,37 @@ export default class Node extends PIXI.Graphics {
|
||||
|
||||
addPods(sorterFn) {
|
||||
const nodeBox = this
|
||||
let px = 24
|
||||
let py = 20
|
||||
const px = App.current.startDrawingPodsAt
|
||||
const py = App.current.heightOfTopHandlePx + 5
|
||||
let podsCounter = 0
|
||||
let podsKubeSystemCounter = 0
|
||||
const pods = Object.values(this.node.pods).sort(sorterFn)
|
||||
for (const pod of pods) {
|
||||
if (pod.namespace != 'kube-system') {
|
||||
const podBox = Pod.getOrCreate(pod, this.cluster, this.tooltip)
|
||||
podBox.movePodTo(new PIXI.Point(px, py))
|
||||
podBox.movePodTo(
|
||||
new PIXI.Point(
|
||||
// we have a room for this.cluster.podsPerRow pods
|
||||
px + (App.current.sizeOfPodPx * (podsCounter % this.cluster.podsPerRow)),
|
||||
// we just count when to get to another row
|
||||
py + (App.current.sizeOfPodPx * Math.floor(podsCounter / this.cluster.podsPerRow))
|
||||
)
|
||||
)
|
||||
nodeBox.addChild(podBox.draw())
|
||||
px += 13
|
||||
if (px > 90) {
|
||||
px = 24
|
||||
py += 13
|
||||
}
|
||||
}
|
||||
}
|
||||
px = 24
|
||||
py = 100
|
||||
for (const pod of pods) {
|
||||
if (pod.namespace == 'kube-system') {
|
||||
podsCounter++
|
||||
} else {
|
||||
// kube-system pods
|
||||
const podBox = Pod.getOrCreate(pod, this.cluster, this.tooltip)
|
||||
podBox.movePodTo(new PIXI.Point(px, py))
|
||||
podBox.movePodTo(
|
||||
new PIXI.Point(
|
||||
// we have a room for this.cluster.podsPerRow pods
|
||||
px + (App.current.sizeOfPodPx * (podsKubeSystemCounter % this.cluster.podsPerRow)),
|
||||
// like above (for not kube-system pods), but we count from the bottom
|
||||
this.cluster.heightOfNodePx - App.current.sizeOfPodPx - 2 - (App.current.sizeOfPodPx * Math.floor(podsKubeSystemCounter / this.cluster.podsPerRow))
|
||||
)
|
||||
)
|
||||
nodeBox.addChild(podBox.draw())
|
||||
px += 13
|
||||
if (px > 90) {
|
||||
px = 24
|
||||
py -= 13
|
||||
}
|
||||
podsKubeSystemCounter++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import time
|
||||
import random
|
||||
import string
|
||||
|
||||
|
||||
def hash_int(x: int):
|
||||
@@ -37,10 +38,11 @@ def generate_mock_pod(index: int, i: int, j: int):
|
||||
containers = []
|
||||
for k in range(1 + j % 2):
|
||||
# generate "more real data"
|
||||
requests_cpu = random.randint(50, 100)
|
||||
requests_memory = random.randint(256, 512)
|
||||
usage_cpu = requests_cpu + random.randint(-45, 50)
|
||||
usage_memory = requests_memory + random.randint(-128, 128)
|
||||
requests_cpu = random.randint(10, 50)
|
||||
requests_memory = random.randint(64, 256)
|
||||
# with max, we defend ourselves against negative cpu/memory ;)
|
||||
usage_cpu = max(requests_cpu + random.randint(-30, 30), 1)
|
||||
usage_memory = max(requests_memory + random.randint(-64, 128), 1)
|
||||
container = {
|
||||
'name': 'myapp',
|
||||
'image': 'foo/bar/{}'.format(j),
|
||||
@@ -107,12 +109,17 @@ def query_mock_cluster(cluster):
|
||||
usage_cpu += int(c["resources"]["usage"]["cpu"].split("m")[0])
|
||||
usage_memory += int(c["resources"]["usage"]["memory"].split("Mi")[0])
|
||||
|
||||
# generate longer name for a node
|
||||
suffix = ''.join(
|
||||
[random.choice(string.ascii_letters) for n in range(random.randint(1, 20))]
|
||||
)
|
||||
|
||||
node = {
|
||||
'name': 'node-{}'.format(i),
|
||||
'name': f'node-{i}-{suffix}',
|
||||
'labels': labels,
|
||||
'status': {
|
||||
'capacity': {'cpu': '4', 'memory': '32Gi', 'pods': '110'},
|
||||
'allocatable': {'cpu': '3800m', 'memory': '31Gi'}
|
||||
'capacity': {'cpu': '8', 'memory': '64Gi', 'pods': '110'},
|
||||
'allocatable': {'cpu': '7800m', 'memory': '62Gi'}
|
||||
},
|
||||
'pods': pods,
|
||||
# get data from containers (usage)
|
||||
|
||||
Reference in New Issue
Block a user