dashboard/components/InfoBoxCluster.vue

274 lines
7.6 KiB
Vue

<script>
import { isEmpty } from 'lodash';
import InfoBox from '@/components/InfoBox';
import PercentageBar from '@/components/PercentageBar';
import { parseSi, formatSi, exponentNeeded } from '@/utils/units';
const PARSE_RULES = {
memory: {
format: {
addSuffix: true,
firstSuffix: 'B',
increment: 1000,
maxExponent: 99,
maxPrecision: 2,
minExponent: 0,
startingExponent: 0,
suffix: 'iB',
}
}
};
export default {
components: {
InfoBox,
PercentageBar,
},
props: {
/**
* The cluster for info
*/
cluster: {
type: Object,
required: true,
},
/**
* The node metrics used for parsing CPU/MEM graphs
*/
metrics: {
type: Array,
required: true,
},
/**
* The nodes belonging to this cluster
*/
nodes: {
type: Array,
required: true,
default: () => [],
},
},
computed: {
liveNodeUsage() {
const clusterCapacityCpu = this.cluster?.status?.capacity?.cpu;
return this.getLiveUsage(clusterCapacityCpu, 'cpu');
},
liveNodeMemUsage() {
const clusterCapacityMemory = this.cluster?.status?.capacity?.memory;
const { memory: { format } } = PARSE_RULES;
return this.getLiveUsage(clusterCapacityMemory, 'memory', format);
},
nodeUsageReserved() {
const requested = this.cluster?.status?.requested?.cpu;
const allocatable = this.cluster?.status?.allocatable?.cpu;
return this.getReservedUsage(requested, allocatable);
},
nodeUsageMemReserved() {
const requested = this.cluster?.status?.requested?.memory;
const allocatable = this.cluster?.status?.allocatable?.memory;
const { memory: { format } } = PARSE_RULES;
format.increment = 1024;
return this.getReservedUsage(requested, allocatable, format);
},
nodeUsagePodReserved() {
const { memory: { format } } = PARSE_RULES;
const podCapacity = parseSi(this.cluster?.status?.allocatable?.pods || 0);
const podUsage = parseSi(this.cluster?.status?.requested?.pods || 0);
return {
clusterCapacity: formatSi(podCapacity, { ...format, ...{ addSuffix: false } }),
nodeUsage: formatSi(podUsage, { ...format, ...{ addSuffix: false } }),
percentage: podCapacity === 0 ? 0 : ( podUsage * 100 ) / podCapacity,
};
},
},
methods: {
getReservedUsage(requested = 0, allocatable = 0, formatOpts = {}) {
const parsed = {
requested: parseSi(requested),
allocatable: parseSi(allocatable),
};
const percentage = parsed.allocatable === 0 ? parsed.allocatable : ( parsed.requested * 100 ) / parsed.allocatable;
const increment = formatOpts?.increment ? formatOpts.increment : undefined; // exponentneeded has default for incremeent if not defined
formatOpts = {
...formatOpts,
...{
maxExponent: exponentNeeded(parsed.allocatable, increment),
minExponent: exponentNeeded(parsed.allocatable, increment),
}
};
return {
requested: formatSi(parsed.requested, { ...formatOpts, ...{ addSuffix: false } }),
allocatable: formatSi(parsed.allocatable, formatOpts),
percentage
};
},
getLiveUsage(capacity, field = 'cpu', formatOpts = {}) {
const nodes = this.nodes;
const metrics = this.metrics.filter(n => nodes.find(nd => nd.id === n.id && nd.isWorker));
const normalizedCapacity = parseSi(capacity);
const nodesEachUsage = metrics.map( m => parseSi(m.usage[field]));
const cumulativeUsage = isEmpty(nodesEachUsage) ? 0 : nodesEachUsage.reduce( ( acc, cv ) => acc + cv);
const increment = formatOpts?.increment ? formatOpts.increment : 1024;
if (field === 'memory') {
formatOpts = {
...formatOpts,
...{
maxExponent: exponentNeeded(normalizedCapacity, increment),
minExponent: exponentNeeded(normalizedCapacity, increment),
increment,
}
};
}
const formatedCapacity = formatSi(normalizedCapacity, formatOpts);
const formatedUsage = formatSi(cumulativeUsage, { ...formatOpts, ...{ addSuffix: false } });
const percentage = normalizedCapacity === 0 ? normalizedCapacity : ( cumulativeUsage * 100 ) / normalizedCapacity;
return {
clusterCapacity: formatedCapacity,
nodeUsage: formatedUsage,
percentage,
};
},
}
};
</script>
<template>
<InfoBox>
<div class="info-column">
<label>
<h5>
<t k="infoBoxCluster.cpu" />
</h5>
</label>
<div class="info-column-data mb-10">
<label>
<t
k="infoBoxCluster.reserved"
:numerator="nodeUsageReserved.requested"
:denominator="nodeUsageReserved.allocatable"
/>
</label>
<PercentageBar :value="nodeUsageReserved.percentage" />
</div>
<div class="info-column-data mb-10">
<label>
<t
k="infoBoxCluster.used"
:numerator="liveNodeUsage.nodeUsage"
:denominator="liveNodeUsage.clusterCapacity"
/>
</label>
<PercentageBar :value="liveNodeUsage.percentage" />
</div>
</div>
<div class="info-column">
<label>
<h5>
<t k="infoBoxCluster.memory" />
</h5>
</label>
<div class="info-column-data mb-10">
<label>
<t
k="infoBoxCluster.reserved"
:numerator="nodeUsageMemReserved.requested"
:denominator="nodeUsageMemReserved.allocatable"
/>
</label>
<PercentageBar :value="nodeUsageMemReserved.percentage" />
</div>
<div class="info-column-data mb-10">
<label>
<t
k="infoBoxCluster.used"
:numerator="liveNodeMemUsage.nodeUsage"
:denominator="liveNodeMemUsage.clusterCapacity"
/>
</label>
<PercentageBar :value="liveNodeMemUsage.percentage" />
</div>
</div>
<div class="info-column">
<label>
<h5>
<t k="infoBoxCluster.pods" />
</h5>
</label>
<div class="info-column-data mb-10">
<label>
<t
k="infoBoxCluster.reserved"
:numerator="nodeUsagePodReserved.nodeUsage"
:denominator="nodeUsagePodReserved.clusterCapacity"
/>
</label>
<PercentageBar :value="nodeUsagePodReserved.percentage" />
</div>
</div>
</InfoBox>
</template>
<style lang="scss" scoped>
.info-box {
// reset infobox flex styles
display: grid;
grid-template-columns: 1fr;
flex-grow: 0;
flex-basis: 0;
margin-bottom: 20px;
.info-column {
padding-left: 10%;
&:not(:last-child) {
border-right: 0;
border-bottom: 1px solid var(--tabbed-border);
margin-bottom: 10px;
}
.info-column-data {
display: grid;
grid-template-columns: 1fr 1fr;
align-items: center;
}
> label {
margin-bottom: 5px;
display: inline-block;
}
}
}
@media only screen and (min-width: map-get($breakpoints, '--viewport-7')) {
.info-box {
grid-template-columns: 1fr 1fr 1fr;
.info-column {
.info-column-data {
grid-template-columns: 1fr 1fr;
}
&:not(:last-child) {
border-right: 1px solid var(--tabbed-border);
border-bottom: 0;
margin-bottom: 0;
}
}
}
}
</style>