From 27a9b413e1dc76dfb3ae7f2bf3eb53806d9216c8 Mon Sep 17 00:00:00 2001 From: patricklai Date: Thu, 15 Sep 2022 16:24:19 +0800 Subject: [PATCH] fix(#515): fix k8s unit transform --- .../Recommend/ResourcesRecommend/index.tsx | 12 +- pkg/web/src/utils/transformK8sUnit.ts | 151 ++++++++++++++++++ 2 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 pkg/web/src/utils/transformK8sUnit.ts diff --git a/pkg/web/src/pages/Recommend/ResourcesRecommend/index.tsx b/pkg/web/src/pages/Recommend/ResourcesRecommend/index.tsx index 93245a50a..cae44e4b1 100644 --- a/pkg/web/src/pages/Recommend/ResourcesRecommend/index.tsx +++ b/pkg/web/src/pages/Recommend/ResourcesRecommend/index.tsx @@ -14,7 +14,8 @@ import { useNavigate } from 'react-router-dom'; import JsYaml from 'js-yaml'; import { useTranslation } from 'react-i18next'; import { Prism } from '@mantine/prism'; -import { copyToClipboard } from "../../../utils/copyToClipboard"; +import { copyToClipboard } from '../../../utils/copyToClipboard'; +import { K8SUNIT, transformK8sUnit } from 'utils/transformK8sUnit'; const Editor = React.lazy(() => import('components/common/Editor')); @@ -51,7 +52,6 @@ export const SelectTable = () => { const filterResult = recommendation .filter((recommendation) => { - console.log(recommendation); if (filterParams?.name) { return new RegExp(`${filterParams.name}.*`).test(recommendation.name); } @@ -144,7 +144,6 @@ export const SelectTable = () => { title: t('当前资源(容器/CPU/Memory)'), colKey: 'status.currentInfo', cell({ row }) { - console.log('row', row); if (typeof row.status.currentInfo === 'string') { const containers = JSON.parse(row?.status?.currentInfo).spec?.template?.spec?.containers || []; if (containers.length > 0) { @@ -167,7 +166,6 @@ export const SelectTable = () => { title: t('推荐资源(容器/CPU/Memory)'), colKey: 'status.recommendedInfo', cell({ row }) { - console.log('row', row); if (typeof row.status.recommendedValue !== 'string') { const containers = row?.status?.recommendedValue?.resourceRequest?.containers || []; if (containers.length > 0) { @@ -175,7 +173,7 @@ export const SelectTable = () => { {containers.map((o: any, i: number) => ( - {o.containerName} / {o.target.cpu} / {Math.floor(parseFloat(o.target.memory) / 1048576)}Mi + {o.containerName} / {o.target.cpu} / {transformK8sUnit(o.target.memory, K8SUNIT.Mi)}Mi ))} @@ -289,7 +287,7 @@ export const SelectTable = () => { onClick={async () => { try { await copyToClipboard( - `patchData=\`kubectl get recommend ${currentSelection?.metadata?.name} -n ${currentSelection?.spec?.targetRef?.namespace} -o jsonpath='{.status.recommendedInfo}'\`;kubectl patch ${currentSelection?.spec?.targetRef?.kind} ${currentSelection?.spec?.targetRef?.name} -n ${currentSelection?.spec?.targetRef?.namespace} --patch \"\${patchData}\"`, + `patchData=\`kubectl get recommend ${currentSelection?.metadata?.name} -n ${currentSelection?.spec?.targetRef?.namespace} -o jsonpath='{.status.recommendedInfo}'\`;kubectl patch ${currentSelection?.spec?.targetRef?.kind} ${currentSelection?.spec?.targetRef?.name} -n ${currentSelection?.spec?.targetRef?.namespace} --patch "\${patchData}"`, ); await MessagePlugin.success('Copy command to clipboard.'); } catch (err) { @@ -307,7 +305,7 @@ export const SelectTable = () => { }} > - {`patchData=\`kubectl get recommend ${currentSelection?.metadata?.name} -n ${currentSelection?.spec?.targetRef?.namespace} -o jsonpath='{.status.recommendedInfo}'\`\nkubectl patch ${currentSelection?.spec?.targetRef?.kind} ${currentSelection?.spec?.targetRef?.name} -n ${currentSelection?.spec?.targetRef?.namespace} --patch \"\${patchData}\"`} + {`patchData=\`kubectl get recommend ${currentSelection?.metadata?.name} -n ${currentSelection?.spec?.targetRef?.namespace} -o jsonpath='{.status.recommendedInfo}'\`\nkubectl patch ${currentSelection?.spec?.targetRef?.kind} ${currentSelection?.spec?.targetRef?.name} -n ${currentSelection?.spec?.targetRef?.namespace} --patch "\${patchData}"`} diff --git a/pkg/web/src/utils/transformK8sUnit.ts b/pkg/web/src/utils/transformK8sUnit.ts new file mode 100644 index 000000000..71ca388c2 --- /dev/null +++ b/pkg/web/src/utils/transformK8sUnit.ts @@ -0,0 +1,151 @@ +export enum K8SUNIT { + m = 'm', + /** 核 */ + unit = 'unit', + K = 'k', + M = 'M', + G = 'G', + T = 'T', + P = 'P', + E = 'E', + Ki = 'Ki', + Mi = 'Mi', + Gi = 'Gi', + Ti = 'Ti', + Pi = 'Pi', + Ei = 'Ei', +} + +const UNITS1024 = [K8SUNIT.m, K8SUNIT.unit, K8SUNIT.Ki, K8SUNIT.Mi, K8SUNIT.Gi, K8SUNIT.Ti, K8SUNIT.Pi, K8SUNIT.Ei]; +const UNITS1000 = [K8SUNIT.m, K8SUNIT.unit, K8SUNIT.K, K8SUNIT.M, K8SUNIT.G, K8SUNIT.T, K8SUNIT.P, K8SUNIT.E]; + +const UNITS1024_MAP_TO_UNITS1000: Partial> = { + [K8SUNIT.Ki]: K8SUNIT.K, + [K8SUNIT.Mi]: K8SUNIT.M, + [K8SUNIT.Gi]: K8SUNIT.G, + [K8SUNIT.Ti]: K8SUNIT.T, + [K8SUNIT.Pi]: K8SUNIT.P, + [K8SUNIT.Ei]: K8SUNIT.E, +}; + +const UNITS1000_MAP_TO_UNITS1024: Partial> = { + [K8SUNIT.K]: K8SUNIT.Ki, + [K8SUNIT.M]: K8SUNIT.Mi, + [K8SUNIT.G]: K8SUNIT.Gi, + [K8SUNIT.T]: K8SUNIT.Ti, + [K8SUNIT.P]: K8SUNIT.Pi, + [K8SUNIT.E]: K8SUNIT.Ei, +}; + +/** + * 进行单位换算 + * 实现k8s数值各单位之间的相互转换 + * @param {string} value + * @param {number} step + * @param {number} toFixed + */ +function transformField(_value: string, step: number, toFixed: number, units: K8SUNIT[], targetUnit: K8SUNIT) { + const reg = /^(\d+(\.\d{1,5})?)([A-Za-z]+)?$/; + let value; + let unitBase; + if (reg.test(_value)) { + [value, unitBase] = [+RegExp.$1, RegExp.$3]; + if (unitBase === '') { + unitBase = K8SUNIT.unit; + } + } else { + return '0'; + } + + // 由于m到单位1是1000进制 + const mIndex = units.indexOf(K8SUNIT.m); + let i = units.indexOf(unitBase as K8SUNIT); + let targetI = units.indexOf(targetUnit); + if (step) { + if (targetI >= i) { + while (i < targetI) { + value /= i + 1 <= mIndex ? 1000 : step; + i += 1; + } + } else { + while (targetI < i) { + value *= i - 1 <= mIndex ? 1000 : step; + targetI += 1; + } + } + } + + let svalue; + if (value > 1) { + svalue = value.toFixed(toFixed); + svalue = svalue.replace(/0+$/, ''); + svalue = svalue.replace(/\.$/, ''); + } else if (value) { + // 如果数值很小,保留toFixed位有效数字 + let tens = 0; + let v = Math.abs(value); + while (v < 1) { + v *= 10; + tens += 1; + } + svalue = value.toFixed(tens + toFixed - 1); + svalue = svalue.replace(/0+$/, ''); + svalue = svalue.replace(/\.$/, ''); + } else { + svalue = value; + } + return String(svalue); +} + +function valueTrans1000(value: string, targetUnit: K8SUNIT) { + return transformField(value, 1000, 3, UNITS1000, targetUnit); +} + +function valueTrans1024(value: string, targetUnit: K8SUNIT) { + return transformField(value, 1024, 3, UNITS1024, targetUnit); +} + +export function transformK8sUnit(data: string, targetUnit: K8SUNIT) { + let finalData = 0; + const requestValue: string = data ?? ''; + const reg = /^(\d+(\.\d{1,2})?)([A-Za-z]+)?$/; + let unitBase; + + if (reg.test(requestValue)) { + unitBase = RegExp.$3; + } + + const isBase1000 = unitBase ? UNITS1000.includes(unitBase as K8SUNIT) : false; + const isTarget1000 = UNITS1000.includes(targetUnit); + + if (requestValue) { + if (isBase1000 && isTarget1000) { + // 1G 轉 M + finalData = +valueTrans1000(requestValue, targetUnit); + } else if (!isBase1000 && !isTarget1000) { + // 1Gi 轉 Mi + finalData = +valueTrans1024(requestValue, targetUnit); + } else if (isBase1000 && !isTarget1000) { + // 1G 轉 Mi + const newTargetUnit = UNITS1024_MAP_TO_UNITS1000[targetUnit]; + if (newTargetUnit) { + finalData = +(+valueTrans1000(requestValue, newTargetUnit) / 1.024).toFixed(3); + } else { + // targetUnit為m 或 unit + finalData = +valueTrans1000(requestValue, targetUnit); + } + } else if (!isBase1000 && isTarget1000) { + // 1Gi 轉 M + const newTargetUnit = UNITS1000_MAP_TO_UNITS1024[targetUnit]; // 先將Gi轉成Mi + if (newTargetUnit) { + finalData = +(+valueTrans1024(requestValue, newTargetUnit) * 1.024).toFixed(3); + } else { + finalData = +valueTrans1024(requestValue, targetUnit); + } + } + } else { + finalData = 0; + } + + return finalData; +}