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); }