mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-10-01 03:36:04 +08:00
feat: CPU / Memory hotplug support (#413)
* feat: add maxCPU and maxMemory Signed-off-by: Andy Lee <andy.lee@suse.com> * feat: add hotplug dialog Signed-off-by: Andy Lee <andy.lee@suse.com> * feat: add restart message Signed-off-by: Andy Lee <andy.lee@suse.com> * feat: let VM template support cpuMemoryHotplug Signed-off-by: Andy Lee <andy.lee@suse.com> * feat: add feature flag Signed-off-by: Andy Lee <andy.lee@suse.com> * feat: add max-hotplug-ratio setting Signed-off-by: Andy Lee <andy.lee@suse.com> --------- Signed-off-by: Andy Lee <andy.lee@suse.com>
This commit is contained in:
@@ -2,23 +2,44 @@
|
||||
import UnitInput from '@shell/components/form/UnitInput';
|
||||
import InputOrDisplay from '@shell/components/InputOrDisplay';
|
||||
import { GIBIBYTE } from '../../utils/unit';
|
||||
import { Checkbox } from '@components/Form/Checkbox';
|
||||
import { _VIEW } from '@shell/config/query-params';
|
||||
import { HCI } from '../../types';
|
||||
import { allHash } from '@shell/utils/promise';
|
||||
import { HCI_SETTING } from '../../config/settings';
|
||||
|
||||
const DEFAULT_HOT_PLUG_TIMES = 4;
|
||||
|
||||
export default {
|
||||
name: 'HarvesterEditCpuMemory',
|
||||
|
||||
emits: ['updateCpuMemory'],
|
||||
|
||||
components: { UnitInput, InputOrDisplay },
|
||||
components: {
|
||||
UnitInput, InputOrDisplay, Checkbox
|
||||
},
|
||||
|
||||
props: {
|
||||
cpu: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
maxCpu: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
memory: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
maxMemory: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
enableHotPlug: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'create',
|
||||
@@ -29,21 +50,59 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
async fetch() {
|
||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||
|
||||
const res = await allHash({ settings: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.SETTING }) });
|
||||
|
||||
this.settings = res.settings || [];
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
GIBIBYTE,
|
||||
localCpu: this.cpu,
|
||||
localMemory: this.memory
|
||||
localCpu: this.cpu,
|
||||
localMemory: this.memory,
|
||||
maxLocalCpu: this.maxCpu,
|
||||
maxLocalMemory: this.maxMemory,
|
||||
localEnableHotPlug: this.enableHotPlug,
|
||||
settings: []
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
cupDisplay() {
|
||||
isView() {
|
||||
return this.mode === _VIEW;
|
||||
},
|
||||
cpuDisplay() {
|
||||
return `${ this.localCpu } C`;
|
||||
},
|
||||
|
||||
maxCpuDisplay() {
|
||||
return `${ this.maxLocalCpu } C`;
|
||||
},
|
||||
|
||||
memoryDisplay() {
|
||||
return `${ this.localMemory }`;
|
||||
},
|
||||
|
||||
maxMemoryDisplay() {
|
||||
return `${ this.maxLocalMemory }`;
|
||||
},
|
||||
|
||||
cpuMemoryHotplugTooltip() {
|
||||
return this.t('harvester.virtualMachine.hotplug.tooltip', { hotPlugTimes: this.maxHotplugRatio });
|
||||
},
|
||||
|
||||
isCPUMemoryHotPlugFeatureEnabled() {
|
||||
return this.$store.getters['harvester-common/getFeatureEnabled']('cpuMemoryHotplug');
|
||||
},
|
||||
|
||||
maxHotplugRatio() {
|
||||
const maxHotPlugRatioSetting = this.settings.find((s) => s.id === HCI_SETTING.MAX_HOTPLUG_RATIO);
|
||||
const maxPlugRatio = maxHotPlugRatioSetting?.value ? parseInt(maxHotPlugRatioSetting.value, 10) : DEFAULT_HOT_PLUG_TIMES;
|
||||
|
||||
return maxPlugRatio;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -55,71 +114,161 @@ export default {
|
||||
if (neu && !neu.includes('null')) {
|
||||
this.localMemory = neu;
|
||||
}
|
||||
}
|
||||
},
|
||||
maxCpu(neu) {
|
||||
this.maxLocalCpu = neu;
|
||||
},
|
||||
maxMemory(neu) {
|
||||
if (neu && !neu.includes('null')) {
|
||||
this.maxLocalMemory = neu;
|
||||
}
|
||||
},
|
||||
enableHotPlug(neu) {
|
||||
this.localEnableHotPlug = neu;
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
change() {
|
||||
let memory = '';
|
||||
|
||||
if (String(this.localMemory).includes('Gi')) {
|
||||
memory = this.localMemory;
|
||||
hotPlugChanged(neu) {
|
||||
// If hot plug is enabled, we need to update the maxCpu and maxMemory values
|
||||
if (neu) {
|
||||
this.maxLocalCpu = this.localCpu ? this.localCpu * this.maxHotplugRatio : null;
|
||||
this.maxLocalMemory = this.localMemory ? `${ parseInt(this.localMemory, 10) * this.maxHotplugRatio }${ GIBIBYTE }` : null;
|
||||
this.$emit('updateCpuMemory', this.localCpu, this.localMemory, this.maxLocalCpu, this.maxLocalMemory, neu);
|
||||
} else {
|
||||
memory = `${ this.localMemory }${ GIBIBYTE }`;
|
||||
this.$emit('updateCpuMemory', this.localCpu, this.localMemory, '', null, neu);
|
||||
}
|
||||
if (memory.includes('null')) {
|
||||
memory = null;
|
||||
}
|
||||
this.$emit('updateCpuMemory', this.localCpu, memory);
|
||||
},
|
||||
|
||||
changeMemory() {
|
||||
if (this.localEnableHotPlug) {
|
||||
this.maxLocalMemory = this.localMemory ? `${ parseInt(this.localMemory, 10) * this.maxHotplugRatio }${ GIBIBYTE }` : null;
|
||||
}
|
||||
this.$emit('updateCpuMemory', this.localCpu, this.localMemory, this.maxLocalCpu, this.maxLocalMemory, this.localEnableHotPlug);
|
||||
},
|
||||
changeCPU() {
|
||||
if (this.localEnableHotPlug) {
|
||||
this.maxLocalCpu = this.localCpu ? this.localCpu * this.maxHotplugRatio : null;
|
||||
}
|
||||
this.$emit('updateCpuMemory', this.localCpu, this.localMemory, this.maxLocalCpu, this.maxLocalMemory, this.localEnableHotPlug);
|
||||
},
|
||||
changeMaxCPUMemory() {
|
||||
this.$emit('updateCpuMemory', this.localCpu, this.localMemory, this.maxLocalCpu, this.maxLocalMemory, this.localEnableHotPlug);
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col span-6 mb-10">
|
||||
<InputOrDisplay
|
||||
name="CPU"
|
||||
:value="cupDisplay"
|
||||
:mode="mode"
|
||||
>
|
||||
<UnitInput
|
||||
v-model:value="localCpu"
|
||||
label="CPU"
|
||||
suffix="C"
|
||||
:delay="0"
|
||||
required
|
||||
:disabled="disabled"
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col span-6 mb-10">
|
||||
<InputOrDisplay
|
||||
name="CPU"
|
||||
:value="cpuDisplay"
|
||||
:mode="mode"
|
||||
class="mb-20"
|
||||
@update:value="change"
|
||||
/>
|
||||
</InputOrDisplay>
|
||||
class="mb-10"
|
||||
>
|
||||
<UnitInput
|
||||
v-model:value="localCpu"
|
||||
label="CPU"
|
||||
suffix="C"
|
||||
:delay="0"
|
||||
required
|
||||
:disabled="disabled"
|
||||
:mode="mode"
|
||||
class="mb-20"
|
||||
@update:value="changeCPU"
|
||||
/>
|
||||
</InputOrDisplay>
|
||||
</div>
|
||||
<div class="col span-6 mb-10">
|
||||
<InputOrDisplay
|
||||
:name="t('harvester.virtualMachine.input.memory')"
|
||||
:value="memoryDisplay"
|
||||
:mode="mode"
|
||||
>
|
||||
<UnitInput
|
||||
v-model:value="localMemory"
|
||||
:label="t('harvester.virtualMachine.input.memory')"
|
||||
:mode="mode"
|
||||
:input-exponent="3"
|
||||
:delay="0"
|
||||
:increment="1024"
|
||||
:output-modifier="true"
|
||||
:disabled="disabled"
|
||||
required
|
||||
:suffix="GIBIBYTE"
|
||||
class="mb-20"
|
||||
@update:value="changeMemory"
|
||||
/>
|
||||
</InputOrDisplay>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col span-6 mb-10">
|
||||
<InputOrDisplay
|
||||
:name="t('harvester.virtualMachine.input.memory')"
|
||||
:value="memoryDisplay"
|
||||
:mode="mode"
|
||||
>
|
||||
<UnitInput
|
||||
v-model:value="localMemory"
|
||||
:label="t('harvester.virtualMachine.input.memory')"
|
||||
<div
|
||||
v-if="isCPUMemoryHotPlugFeatureEnabled"
|
||||
class="row"
|
||||
>
|
||||
<Checkbox
|
||||
v-model:value="localEnableHotPlug"
|
||||
class="check"
|
||||
type="checkbox"
|
||||
:label="t('harvester.virtualMachine.hotplug.title')"
|
||||
:disabled="isView"
|
||||
@update:value="hotPlugChanged"
|
||||
/>
|
||||
<i
|
||||
v-clean-tooltip="{content: cpuMemoryHotplugTooltip, triggers: ['hover', 'touch', 'focus'] }"
|
||||
v-stripped-aria-label="cpuMemoryHotplugTooltip"
|
||||
class="icon icon-info"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="localEnableHotPlug && isCPUMemoryHotPlugFeatureEnabled"
|
||||
class="row"
|
||||
>
|
||||
<div class="col span-6 mb-10">
|
||||
<InputOrDisplay
|
||||
:name="t('harvester.virtualMachine.input.maxCpu')"
|
||||
:value="maxCpuDisplay"
|
||||
:mode="mode"
|
||||
:input-exponent="3"
|
||||
:delay="0"
|
||||
:increment="1024"
|
||||
:output-modifier="true"
|
||||
:disabled="disabled"
|
||||
required
|
||||
:suffix="GIBIBYTE"
|
||||
class="mb-20"
|
||||
@update:value="change"
|
||||
/>
|
||||
</InputOrDisplay>
|
||||
class="mt-20"
|
||||
>
|
||||
<UnitInput
|
||||
v-model:value="maxLocalCpu"
|
||||
:label="t('harvester.virtualMachine.input.maxCpu')"
|
||||
suffix="C"
|
||||
:delay="0"
|
||||
:disabled="disabled"
|
||||
:mode="mode"
|
||||
class="mt-20"
|
||||
@update:value="changeMaxCPUMemory"
|
||||
/>
|
||||
</InputOrDisplay>
|
||||
</div>
|
||||
<div class="col span-6 mb-10">
|
||||
<InputOrDisplay
|
||||
:name="t('harvester.virtualMachine.input.maxMemory')"
|
||||
:value="maxMemoryDisplay"
|
||||
:mode="mode"
|
||||
class="mt-20"
|
||||
>
|
||||
<UnitInput
|
||||
v-model:value="maxLocalMemory"
|
||||
:label="t('harvester.virtualMachine.input.maxMemory')"
|
||||
:mode="mode"
|
||||
:input-exponent="3"
|
||||
:delay="0"
|
||||
:increment="1024"
|
||||
:output-modifier="true"
|
||||
:disabled="disabled"
|
||||
:suffix="GIBIBYTE"
|
||||
class="mt-20"
|
||||
@update:value="changeMaxCPUMemory"
|
||||
/>
|
||||
</InputOrDisplay>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -240,7 +240,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="mt-20">
|
||||
<LabeledSelect
|
||||
v-model:value="checkedSsh"
|
||||
:label="t('harvester.virtualMachine.input.sshKey')"
|
||||
|
||||
@@ -466,7 +466,9 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
const errors = this.getAccessCredentialsValidation();
|
||||
const cpuMemoryErrors = this.getCPUMemoryValidation();
|
||||
const accessCredentialsErrors = this.getAccessCredentialsValidation();
|
||||
const errors = [...cpuMemoryErrors, ...accessCredentialsErrors];
|
||||
|
||||
if (errors.length > 0) {
|
||||
return Promise.reject(errors);
|
||||
@@ -604,8 +606,11 @@ export default {
|
||||
>
|
||||
<CpuMemory
|
||||
:cpu="cpu"
|
||||
:max-cpu="maxCpu"
|
||||
:memory="memory"
|
||||
:max-memory="maxMemory"
|
||||
:mode="mode"
|
||||
:enable-hot-plug="cpuMemoryHotplugEnabled"
|
||||
@updateCpuMemory="updateCpuMemory"
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user