From a8f8f0d28818fc866d3ec8b410322f45a582551e Mon Sep 17 00:00:00 2001 From: Andy Lee Date: Fri, 28 Feb 2025 22:51:32 +0800 Subject: [PATCH 1/3] fix: align all memory / storage / quota units to Gi/Mi Signed-off-by: Andy Lee (cherry picked from commit 8f76d5ad30b34778d38eddc5fdb7532699cde11c) --- .../HarvesterHostBasic.vue | 2 +- .../detail/harvesterhci.io.host/index.vue | 2 +- pkg/harvester/dialog/HarvesterQuotaDialog.vue | 2 +- .../edit/harvesterhci.io.host/index.vue | 4 +- pkg/harvester/edit/harvesterhci.io.volume.vue | 1 + .../VirtualMachineCpuMemory.vue | 1 + .../VirtualMachineReserved.vue | 1 + .../VirtualMachineVolume/type/existing.vue | 1 + .../VirtualMachineVolume/type/vmImage.vue | 10 ++-- .../VirtualMachineVolume/type/volume.vue | 1 + .../formatters/HarvesterMemoryUsed.vue | 2 +- .../formatters/HarvesterStorageUsed.vue | 4 +- .../list/harvesterhci.io.dashboard.vue | 52 +++++++++---------- .../harvesterhci.io.virtualmachineimage.js | 8 +-- pkg/harvester/validators/vm.js | 2 +- pkg/harvester/validators/volume.js | 2 +- 16 files changed, 51 insertions(+), 44 deletions(-) diff --git a/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostBasic.vue b/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostBasic.vue index 385f3504..55876ce6 100644 --- a/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostBasic.vue +++ b/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostBasic.vue @@ -121,7 +121,7 @@ export default { memoryUnits() { const exponent = exponentNeeded(this.memoryTotal, 1024); - return `${ UNITS[exponent] }iB`; + return `${ UNITS[exponent] }i`; }, nodeType() { diff --git a/pkg/harvester/detail/harvesterhci.io.host/index.vue b/pkg/harvester/detail/harvesterhci.io.host/index.vue index bf51a2f0..71347e34 100644 --- a/pkg/harvester/detail/harvesterhci.io.host/index.vue +++ b/pkg/harvester/detail/harvesterhci.io.host/index.vue @@ -178,7 +178,7 @@ export default { minExponent: 3, maxExponent: 3, maxPrecision: 2, - suffix: 'iB', + suffix: 'i', }; const longhornDisks = Object.keys(diskStatus).map((key) => { diff --git a/pkg/harvester/dialog/HarvesterQuotaDialog.vue b/pkg/harvester/dialog/HarvesterQuotaDialog.vue index a3851ad9..92da1e76 100644 --- a/pkg/harvester/dialog/HarvesterQuotaDialog.vue +++ b/pkg/harvester/dialog/HarvesterQuotaDialog.vue @@ -92,7 +92,7 @@ export default { :input-exponent="3" :increment="1024" :output-modifier="true" - suffix="GiB" + suffix="Gi" class="mb-20" /> diff --git a/pkg/harvester/edit/harvesterhci.io.host/index.vue b/pkg/harvester/edit/harvesterhci.io.host/index.vue index 4cd03be5..55832e48 100644 --- a/pkg/harvester/edit/harvesterhci.io.host/index.vue +++ b/pkg/harvester/edit/harvesterhci.io.host/index.vue @@ -185,7 +185,7 @@ export default { minExponent: 3, maxExponent: 3, maxPrecision: 2, - suffix: 'iB', + suffix: 'i', }; const longhornDisks = Object.keys(diskStatus).map((key) => { @@ -457,7 +457,7 @@ export default { const devPath = d.spec?.devPath; const deviceType = d.status?.deviceStatus?.details?.deviceType; const sizeBytes = d.status?.deviceStatus?.capacity?.sizeBytes; - const size = formatSi(sizeBytes, { increment: 1024 }); + const size = formatSi(sizeBytes, { increment: 1024, suffix: 'i' }); const parentDevice = d.status?.deviceStatus?.parentDevice; const isChildAdded = this.newDisks.find((newDisk) => newDisk.blockDevice?.status?.deviceStatus?.parentDevice === devPath); const name = d.displayName; diff --git a/pkg/harvester/edit/harvesterhci.io.volume.vue b/pkg/harvester/edit/harvesterhci.io.volume.vue index d5072d32..5c8dc514 100644 --- a/pkg/harvester/edit/harvesterhci.io.volume.vue +++ b/pkg/harvester/edit/harvesterhci.io.volume.vue @@ -377,6 +377,7 @@ export default { :disabled="value?.isLonghornV2 && isEdit" required class="mb-20" + suffix="Gi" @update:value="update" /> diff --git a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue index d91bdcb0..54b71d9f 100644 --- a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue +++ b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue @@ -113,6 +113,7 @@ export default { :output-modifier="true" :disabled="disabled" required + suffix="Gi" class="mb-20" @update:value="change" /> diff --git a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineReserved.vue b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineReserved.vue index 588d5caa..183a2ca3 100644 --- a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineReserved.vue +++ b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineReserved.vue @@ -47,6 +47,7 @@ export default { :input-exponent="2" :increment="1024" :output-modifier="true" + suffix="Mi" @update:value="change" /> diff --git a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/existing.vue b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/existing.vue index 8db5ef9b..fade3d25 100644 --- a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/existing.vue +++ b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/existing.vue @@ -254,6 +254,7 @@ export default { :label="t('harvester.fields.size')" :mode="mode" :disabled="true" + suffix="Gi" @update:value="update" /> diff --git a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/vmImage.vue b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/vmImage.vue index 80250c2a..20f95e75 100644 --- a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/vmImage.vue +++ b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/vmImage.vue @@ -129,13 +129,17 @@ export default { }, imageVirtualSize() { - return this.selectedImage?.virtualSize; + if (this.selectedImage?.virtualSize) { + return this.selectedImage.virtualSize.replace(' ', ''); + } + + return '0'; }, diskSize() { const size = this.value?.size || '0'; - return `${ size.replace('Gi', '') } GB`; + return size; }, imageVirtualSizeInByte() { @@ -332,7 +336,7 @@ export default { :mode="mode" :required="validateRequired" :disable="isLonghornV2" - suffix="GiB" + suffix="Gi" @update:value="update" /> diff --git a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue index ef6fc957..5bb8ec92 100644 --- a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue +++ b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue @@ -258,6 +258,7 @@ export default { :required="validateRequired" :label="t('harvester.fields.size')" :disabled="isLonghornV2" + suffix="Gi" @update:value="update" /> diff --git a/pkg/harvester/formatters/HarvesterMemoryUsed.vue b/pkg/harvester/formatters/HarvesterMemoryUsed.vue index c08df419..d7652897 100644 --- a/pkg/harvester/formatters/HarvesterMemoryUsed.vue +++ b/pkg/harvester/formatters/HarvesterMemoryUsed.vue @@ -51,7 +51,7 @@ export default { memoryUnits() { const exponent = exponentNeeded(this.memoryTotal, 1024); - return `${ UNITS[exponent] }iB`; + return `${ UNITS[exponent] }i`; }, node() { diff --git a/pkg/harvester/formatters/HarvesterStorageUsed.vue b/pkg/harvester/formatters/HarvesterStorageUsed.vue index 5f6a05cc..cb37477d 100644 --- a/pkg/harvester/formatters/HarvesterStorageUsed.vue +++ b/pkg/harvester/formatters/HarvesterStorageUsed.vue @@ -75,13 +75,13 @@ export default { allocatedUnits() { const exponent = exponentNeeded(this.storageStats.total, 1024); - return `${ UNITS[exponent] }iB`; + return `${ UNITS[exponent] }i`; }, usedUnits() { const exponent = exponentNeeded(this.storageStats.maximum, 1024); - return `${ UNITS[exponent] }iB`; + return `${ UNITS[exponent] }i`; }, formatUsed() { diff --git a/pkg/harvester/list/harvesterhci.io.dashboard.vue b/pkg/harvester/list/harvesterhci.io.dashboard.vue index ebf7ce6f..79b98aa0 100644 --- a/pkg/harvester/list/harvesterhci.io.dashboard.vue +++ b/pkg/harvester/list/harvesterhci.io.dashboard.vue @@ -8,9 +8,7 @@ import Banner from '@components/Banner/Banner.vue'; import MessageLink from '@shell/components/MessageLink'; import SortableTable from '@shell/components/SortableTable'; import { allHash, setPromiseResult } from '@shell/utils/promise'; -import { - parseSi, formatSi, exponentNeeded, UNITS, createMemoryValues -} from '@shell/utils/units'; +import { parseSi, formatSi, exponentNeeded, UNITS } from '@shell/utils/units'; import { REASON } from '@shell/config/table-headers'; import { EVENT, METRIC, NODE, SERVICE, PVC, LONGHORN, POD, COUNT, NETWORK_ATTACHMENT @@ -32,17 +30,15 @@ dayjs.extend(utc); dayjs.extend(minMax); const PARSE_RULES = { - memory: { - format: { - addSuffix: true, - firstSuffix: 'B', - increment: 1024, - maxExponent: 99, - maxPrecision: 2, - minExponent: 0, - startingExponent: 0, - suffix: 'iB', - } + format: { + addSuffix: true, + firstSuffix: 'B', + increment: 1024, + maxExponent: 99, + maxPrecision: 2, + minExponent: 0, + startingExponent: 0, + suffix: 'i', } }; @@ -402,13 +398,13 @@ export default { storageUsed() { const stats = this.storageStats; - return this.createMemoryValues(stats.maximum, stats.used); + return this.createDisplayValues(stats.maximum, stats.used); }, storageAllocated() { const stats = this.storageStats; - return this.createMemoryValues(stats.total, stats.scheduled); + return this.createDisplayValues(stats.total, stats.scheduled); }, vmEvents() { @@ -454,7 +450,7 @@ export default { return total + node.memoryReserved; }, 0); - return createMemoryValues(this.memoryTotal, useful); + return this.createDisplayValues(this.memoryTotal, useful); }, availableNodes() { @@ -494,7 +490,7 @@ export default { }, ramUsed() { - return createMemoryValues(this.memoryTotal, this.metricAggregations?.memory); + return this.createDisplayValues(this.memoryTotal, this.metricAggregations?.memory); }, hasMetricNodeSchema() { @@ -516,10 +512,12 @@ export default { }, methods: { - createMemoryValues(total, useful) { + createDisplayValues(total, useful) { const parsedTotal = parseSi((total || '0').toString()); + const parsedUseful = parseSi((useful || '0').toString()); - const format = this.createMemoryFormat(parsedTotal); + const format = this.createFormat(parsedTotal); + const formattedTotal = formatSi(parsedTotal, format); let formattedUseful = formatSi(parsedUseful, { ...format, @@ -538,24 +536,24 @@ export default { useful: Number(parsedUseful), formattedTotal, formattedUseful, - units: this.createMemoryUnits(parsedTotal), + units: this.createUnits(parsedTotal), }; }, - createMemoryFormat(n) { - const exponent = exponentNeeded(n, PARSE_RULES.memory.format.increment); + createFormat(n) { + const exponent = exponentNeeded(n, PARSE_RULES.format.increment); return { - ...PARSE_RULES.memory.format, + ...PARSE_RULES.format, maxExponent: exponent, minExponent: exponent, }; }, - createMemoryUnits(n) { - const exponent = exponentNeeded(n, PARSE_RULES.memory.format.increment); + createUnits(n) { + const exponent = exponentNeeded(n, PARSE_RULES.format.increment); - return `${ UNITS[exponent] }${ PARSE_RULES.memory.format.suffix }`; + return `${ UNITS[exponent] }${ PARSE_RULES.format.suffix }`; }, async fetchClusterResources(type, opt = {}, store) { diff --git a/pkg/harvester/models/harvesterhci.io.virtualmachineimage.js b/pkg/harvester/models/harvesterhci.io.virtualmachineimage.js index 1410775f..50a5cd01 100644 --- a/pkg/harvester/models/harvesterhci.io.virtualmachineimage.js +++ b/pkg/harvester/models/harvesterhci.io.virtualmachineimage.js @@ -243,8 +243,8 @@ export default class HciVmImage extends HarvesterResource { return formatSi(size, { increment: 1024, maxPrecision: 2, - suffix: 'B', - firstSuffix: 'B', + suffix: 'i', + firstSuffix: 'i', }); } @@ -258,8 +258,8 @@ export default class HciVmImage extends HarvesterResource { return formatSi(virtualSize, { increment: 1024, maxPrecision: 2, - suffix: 'B', - firstSuffix: 'B', + suffix: 'i', + firstSuffix: 'i', }); } diff --git a/pkg/harvester/validators/vm.js b/pkg/harvester/validators/vm.js index e3c5378a..22ecad5f 100644 --- a/pkg/harvester/validators/vm.js +++ b/pkg/harvester/validators/vm.js @@ -88,7 +88,7 @@ export function vmDisks(spec, getters, errors, validatorArgs, displayKey, value) } if (typeValue?.spec?.resources?.requests?.storage && !/^([0-9][0-9]{0,8})[a-zA-Z]+$/.test(typeValue?.spec?.resources?.requests?.storage)) { - const message = getters['i18n/t']('harvester.validation.generic.maximumSize', { max: '999999999 GiB' }); + const message = getters['i18n/t']('harvester.validation.generic.maximumSize', { max: '999999999 Gi' }); errors.push(getters['i18n/t']('harvester.validation.generic.tabError', { prefix, message })); } diff --git a/pkg/harvester/validators/volume.js b/pkg/harvester/validators/volume.js index 2f75bc27..e7e4842f 100644 --- a/pkg/harvester/validators/volume.js +++ b/pkg/harvester/validators/volume.js @@ -6,7 +6,7 @@ export function volumeSize(size, getters, errors, validatorArgs, displayKey, val } if (size && !/^([0-9][0-9]{0,8})[a-zA-Z]+$/.test(size)) { - const message = getters['i18n/t']('harvester.validation.generic.maximumSize', { max: '999999999 GiB' }); + const message = getters['i18n/t']('harvester.validation.generic.maximumSize', { max: '999999999 Gi' }); errors.push(message); } From f02074a25ee74eba3a31be3ff21e99ee5647fe12 Mon Sep 17 00:00:00 2001 From: Andy Lee Date: Mon, 3 Mar 2025 16:50:43 +0800 Subject: [PATCH 2/3] Extract variables to utils/unit Signed-off-by: Andy Lee (cherry picked from commit 8db4de1c4a1200f4f303e4444b6435c581187d72) --- pkg/harvester/config/harvester-map.js | 1 + .../detail/harvesterhci.io.host/HarvesterHostBasic.vue | 3 ++- pkg/harvester/dialog/HarvesterQuotaDialog.vue | 5 +++-- pkg/harvester/edit/harvesterhci.io.host/index.vue | 6 +++--- pkg/harvester/edit/harvesterhci.io.volume.vue | 6 ++++-- .../VirtualMachineCpuMemory.vue | 6 ++++-- .../VirtualMachineReserved.vue | 6 +++--- .../VirtualMachineVolume/type/existing.vue | 4 +++- .../VirtualMachineVolume/type/vmImage.vue | 8 +++++--- .../VirtualMachineVolume/type/volume.vue | 6 ++++-- pkg/harvester/formatters/HarvesterMemoryUsed.vue | 4 ++-- pkg/harvester/formatters/HarvesterStorageUsed.vue | 5 +++-- pkg/harvester/list/harvesterhci.io.dashboard.vue | 5 +++-- pkg/harvester/mixins/harvester-vm/index.js | 7 ++++--- .../models/harvesterhci.io.virtualmachineimage.js | 9 +++++---- pkg/harvester/utils/unit.js | 3 +++ pkg/harvester/validators/vm.js | 3 ++- pkg/harvester/validators/volume.js | 4 +++- 18 files changed, 57 insertions(+), 34 deletions(-) create mode 100644 pkg/harvester/utils/unit.js diff --git a/pkg/harvester/config/harvester-map.js b/pkg/harvester/config/harvester-map.js index 796ad222..75f2b5ad 100644 --- a/pkg/harvester/config/harvester-map.js +++ b/pkg/harvester/config/harvester-map.js @@ -1,3 +1,4 @@ +// TODO: delete this not used variable export const MemoryUnit = [{ label: 'Mi', value: 'Mi' diff --git a/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostBasic.vue b/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostBasic.vue index 55876ce6..8ff3d5b5 100644 --- a/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostBasic.vue +++ b/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostBasic.vue @@ -4,6 +4,7 @@ import { formatSi, exponentNeeded, UNITS } from '@shell/utils/units'; import { HCI as HCI_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations'; import { LONGHORN, METRIC } from '@shell/config/types'; import { Banner } from '@components/Banner'; +import { UNIT_SUFFIX } from '../../utils/unit'; import HarvesterCPUUsed from '../../formatters/HarvesterCPUUsed'; import HarvesterMemoryUsed from '../../formatters/HarvesterMemoryUsed'; import HarvesterStorageUsed from '../../formatters/HarvesterStorageUsed'; @@ -121,7 +122,7 @@ export default { memoryUnits() { const exponent = exponentNeeded(this.memoryTotal, 1024); - return `${ UNITS[exponent] }i`; + return `${ UNITS[exponent] }${ UNIT_SUFFIX }`; }, nodeType() { diff --git a/pkg/harvester/dialog/HarvesterQuotaDialog.vue b/pkg/harvester/dialog/HarvesterQuotaDialog.vue index 92da1e76..3129951b 100644 --- a/pkg/harvester/dialog/HarvesterQuotaDialog.vue +++ b/pkg/harvester/dialog/HarvesterQuotaDialog.vue @@ -5,6 +5,7 @@ import { Banner } from '@components/Banner'; import AsyncButton from '@shell/components/AsyncButton'; import UnitInput from '@shell/components/form/UnitInput'; import { exceptionToErrorsArray } from '@shell/utils/error'; +import { GIBIBYTE } from '../utils/unit'; export default { name: 'HarvesterVMQuotaDialog', @@ -29,6 +30,7 @@ export default { data() { return { + GIBIBYTE, totalSnapshotSize: '', errors: [] }; @@ -44,7 +46,6 @@ export default { }, methods: { - close() { this.totalSnapshotSize = ''; this.$emit('close'); @@ -92,7 +93,7 @@ export default { :input-exponent="3" :increment="1024" :output-modifier="true" - suffix="Gi" + :suffix="GIBIBYTE" class="mb-20" /> diff --git a/pkg/harvester/edit/harvesterhci.io.host/index.vue b/pkg/harvester/edit/harvesterhci.io.host/index.vue index 55832e48..6f65c402 100644 --- a/pkg/harvester/edit/harvesterhci.io.host/index.vue +++ b/pkg/harvester/edit/harvesterhci.io.host/index.vue @@ -20,7 +20,7 @@ import Loading from '@shell/components/Loading.vue'; import MessageLink from '@shell/components/MessageLink'; import { ADD_ONS } from '@pkg/harvester/config/harvester-map'; import { PRODUCT_NAME as HARVESTER_PRODUCT } from '@pkg/harvester/config/harvester'; - +import { UNIT_SUFFIX } from '../../utils/unit'; import { _EDIT } from '@shell/config/query-params'; import { sortBy } from '@shell/utils/sort'; import { Banner } from '@components/Banner'; @@ -185,7 +185,7 @@ export default { minExponent: 3, maxExponent: 3, maxPrecision: 2, - suffix: 'i', + suffix: UNIT_SUFFIX, }; const longhornDisks = Object.keys(diskStatus).map((key) => { @@ -457,7 +457,7 @@ export default { const devPath = d.spec?.devPath; const deviceType = d.status?.deviceStatus?.details?.deviceType; const sizeBytes = d.status?.deviceStatus?.capacity?.sizeBytes; - const size = formatSi(sizeBytes, { increment: 1024, suffix: 'i' }); + const size = formatSi(sizeBytes, { increment: 1024, suffix: UNIT_SUFFIX }); const parentDevice = d.status?.deviceStatus?.parentDevice; const isChildAdded = this.newDisks.find((newDisk) => newDisk.blockDevice?.status?.deviceStatus?.parentDevice === devPath); const name = d.displayName; diff --git a/pkg/harvester/edit/harvesterhci.io.volume.vue b/pkg/harvester/edit/harvesterhci.io.volume.vue index 5c8dc514..f9e36d84 100644 --- a/pkg/harvester/edit/harvesterhci.io.volume.vue +++ b/pkg/harvester/edit/harvesterhci.io.volume.vue @@ -21,6 +21,7 @@ import { InterfaceOption, VOLUME_DATA_SOURCE_KIND } from '../config/harvester-ma import { HCI, VOLUME_SNAPSHOT } from '../types'; import { LVM_DRIVER } from '../models/harvester/storage.k8s.io.storageclass'; import { DATA_ENGINE_V2 } from '../models/harvester/persistentvolumeclaim'; +import { GIBIBYTE } from '../utils/unit'; export default { name: 'HarvesterVolume', @@ -86,6 +87,7 @@ export default { imageId, snapshots: [], images: [], + GIBIBYTE }; }, @@ -288,7 +290,7 @@ export default { const imageSize = Math.max(imageResource?.status?.size, imageResource?.status?.virtualSize); if (imageSize) { - this.storage = `${ Math.ceil(imageSize / 1024 / 1024 / 1024) }Gi`; + this.storage = `${ Math.ceil(imageSize / 1024 / 1024 / 1024) }${ GIBIBYTE }`; } } this.update(); @@ -377,7 +379,7 @@ export default { :disabled="value?.isLonghornV2 && isEdit" required class="mb-20" - suffix="Gi" + :suffix="GIBIBYTE" @update:value="update" /> diff --git a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue index 54b71d9f..b71333aa 100644 --- a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue +++ b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue @@ -1,6 +1,7 @@