mirror of https://github.com/rancher/dashboard.git
251 lines
5.7 KiB
JavaScript
251 lines
5.7 KiB
JavaScript
import Vue from 'vue';
|
|
import { formatPercent } from '@/utils/string';
|
|
import { NODE_ROLES, RKE } from '@/config/labels-annotations.js';
|
|
import { METRIC } from '@/config/types';
|
|
import { parseSi } from '@/utils/units';
|
|
import { PRIVATE } from '@/plugins/steve/resource-proxy';
|
|
import findLast from 'lodash/findLast';
|
|
|
|
export default {
|
|
availableActions() {
|
|
const cordon = {
|
|
action: 'cordon',
|
|
enabled: this.isWorker && !this.isCordoned,
|
|
icon: 'icon icon-fw icon-pause',
|
|
label: 'Cordon',
|
|
total: 1,
|
|
bulkable: true
|
|
};
|
|
|
|
const uncordon = {
|
|
action: 'uncordon',
|
|
enabled: this.isWorker && this.isCordoned,
|
|
icon: 'icon icon-fw icon-play',
|
|
label: 'Uncordon',
|
|
total: 1,
|
|
bulkable: true
|
|
};
|
|
|
|
return [
|
|
cordon,
|
|
uncordon,
|
|
...this._standardActions
|
|
];
|
|
},
|
|
|
|
showDetailStateBadge() {
|
|
return true;
|
|
},
|
|
|
|
name() {
|
|
return this.metadata.name;
|
|
},
|
|
|
|
internalIp() {
|
|
const addresses = this.status?.addresses || [];
|
|
|
|
return findLast(addresses, address => address.type === 'InternalIP')?.address;
|
|
},
|
|
|
|
externalIp() {
|
|
const addresses = this.status?.addresses || [];
|
|
const annotationAddress = this.metadata.annotations[RKE.EXTERNAL_IP];
|
|
const statusAddress = findLast(addresses, address => address.type === 'ExternalIP')?.address;
|
|
|
|
return statusAddress || annotationAddress;
|
|
},
|
|
|
|
labels() {
|
|
return this.metadata?.labels || {};
|
|
},
|
|
|
|
isWorker() {
|
|
const { WORKER: worker } = NODE_ROLES;
|
|
|
|
return `${ this.labels[worker] }` === 'true';
|
|
},
|
|
|
|
isControlPlane() {
|
|
const { CONTROL_PLANE: controlPlane } = NODE_ROLES;
|
|
|
|
return `${ this.labels[controlPlane] }` === 'true';
|
|
},
|
|
|
|
isEtcd() {
|
|
const { ETCD: etcd } = NODE_ROLES;
|
|
|
|
return `${ this.labels[etcd] }` === 'true';
|
|
},
|
|
|
|
hasARole() {
|
|
const roleLabelKeys = Object.values(NODE_ROLES);
|
|
|
|
return Object.keys(this.labels)
|
|
.some((labelKey) => {
|
|
const hasRoleLabel = roleLabelKeys.includes(labelKey);
|
|
const isExpectedValue = `${ this.labels[labelKey] }` === 'true';
|
|
|
|
return hasRoleLabel && isExpectedValue;
|
|
});
|
|
},
|
|
|
|
roles() {
|
|
const { isControlPlane, isWorker, isEtcd } = this;
|
|
|
|
if (( isControlPlane && isWorker && isEtcd ) ||
|
|
( !isControlPlane && !isWorker && !isEtcd )) {
|
|
// !isControlPlane && !isWorker && !isEtcd === RKE?
|
|
return 'All';
|
|
}
|
|
// worker+cp, worker+etcd, cp+etcd
|
|
|
|
if (isControlPlane && isWorker) {
|
|
return 'Control Plane, Worker';
|
|
}
|
|
|
|
if (isControlPlane && isEtcd) {
|
|
return 'Control Plane, Etcd';
|
|
}
|
|
|
|
if (isEtcd && isWorker) {
|
|
return 'Etcd, Worker';
|
|
}
|
|
|
|
if (isControlPlane) {
|
|
return 'Control Plane';
|
|
}
|
|
|
|
if (isEtcd) {
|
|
return 'Etcd';
|
|
}
|
|
|
|
if (isWorker) {
|
|
return 'Worker';
|
|
}
|
|
},
|
|
|
|
version() {
|
|
return this.status.nodeInfo.kubeletVersion;
|
|
},
|
|
|
|
cpuUsage() {
|
|
return parseSi(this.$rootGetters['cluster/byId'](METRIC.NODE, this.id)?.usage?.cpu || '0');
|
|
},
|
|
|
|
cpuCapacity() {
|
|
return parseSi(this.status.allocatable.cpu);
|
|
},
|
|
|
|
cpuUsagePercentage() {
|
|
return ((this.cpuUsage * 10000) / this.cpuCapacity).toString();
|
|
},
|
|
|
|
ramUsage() {
|
|
return parseSi(this.$rootGetters['cluster/byId'](METRIC.NODE, this.id)?.usage?.memory || '0');
|
|
},
|
|
|
|
ramCapacity() {
|
|
return parseSi(this.status.capacity.memory);
|
|
},
|
|
|
|
ramUsagePercentage() {
|
|
return ((this.ramUsage * 10000) / this.ramCapacity).toString();
|
|
},
|
|
|
|
podUsage() {
|
|
return calculatePercentage(this.status.allocatable.pods, this.status.capacity.pods);
|
|
},
|
|
|
|
podCapacity() {
|
|
return Number.parseInt(this.status.capacity.pods);
|
|
},
|
|
|
|
podConsumed() {
|
|
return Number.parseInt(this.status.capacity.pods) - Number.parseInt(this.status.allocatable.pods);
|
|
},
|
|
|
|
isPidPressureOk() {
|
|
return this.hasCondition('PIDPressure', 'False');
|
|
},
|
|
|
|
isDiskPressureOk() {
|
|
return this.hasCondition('DiskPressure', 'False');
|
|
},
|
|
|
|
isMemoryPressureOk() {
|
|
return this.hasCondition('MemoryPressure', 'False');
|
|
},
|
|
|
|
isKubeletOk() {
|
|
return this.hasCondition('Ready');
|
|
},
|
|
|
|
isCordoned() {
|
|
return !!this.spec.unschedulable;
|
|
},
|
|
|
|
containerRuntimeVersion() {
|
|
return this.status.nodeInfo.containerRuntimeVersion.replace('docker://', '');
|
|
},
|
|
|
|
containerRuntimeIcon() {
|
|
if ( this.status.nodeInfo.containerRuntimeVersion.includes('docker') ) {
|
|
return 'icon-docker';
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
cordon() {
|
|
return async() => {
|
|
Vue.set(this.spec, 'unschedulable', true);
|
|
await this.save();
|
|
};
|
|
},
|
|
|
|
uncordon() {
|
|
return async() => {
|
|
Vue.set(this.spec, 'unschedulable', false);
|
|
await this.save();
|
|
};
|
|
},
|
|
|
|
state() {
|
|
if ( !this[PRIVATE].isDetailPage && this.isCordoned ) {
|
|
return 'cordoned';
|
|
}
|
|
|
|
return this.metadata?.state?.name || 'unknown';
|
|
},
|
|
|
|
details() {
|
|
return [{
|
|
label: this.t('node.detail.detailTop.ipAddress'),
|
|
formatter: 'CopyToClipboardText',
|
|
content: this.externalIp || this.internalIp
|
|
},
|
|
{
|
|
label: this.t('node.detail.detailTop.version'),
|
|
content: this.version
|
|
},
|
|
{
|
|
label: this.t('node.detail.detailTop.os'),
|
|
content: this.status.nodeInfo.osImage
|
|
},
|
|
{
|
|
label: this.t('node.detail.detailTop.containerRuntime'),
|
|
formatter: 'IconText',
|
|
formatterOpts: { iconClass: this.containerRuntimeIcon },
|
|
content: this.containerRuntimeVersion
|
|
}];
|
|
}
|
|
};
|
|
|
|
function calculatePercentage(allocatable, capacity) {
|
|
const c = Number.parseFloat(capacity);
|
|
const a = Number.parseFloat(allocatable);
|
|
const percent = (((c - a) / c) * 100);
|
|
|
|
return formatPercent(percent);
|
|
}
|