mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-03-21 20:51:45 +00:00
feat: add cpu model selection (#702)
Signed-off-by: Jack Yu <jack.yu@suse.com>
This commit is contained in:
parent
2db7ee7397
commit
c8a613874a
@ -6,6 +6,7 @@ import { Checkbox } from '@components/Form/Checkbox';
|
||||
import CruResource from '@shell/components/CruResource';
|
||||
import NameNsDescription from '@shell/components/form/NameNsDescription';
|
||||
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||
import { set } from '@shell/utils/object';
|
||||
import { Banner } from '@components/Banner';
|
||||
import KeyValue from '@shell/components/form/KeyValue';
|
||||
import NodeScheduling from '@shell/components/form/NodeScheduling';
|
||||
@ -22,6 +23,7 @@ import Reserved from './kubevirt.io.virtualmachine/VirtualMachineReserved';
|
||||
import Volume from './kubevirt.io.virtualmachine/VirtualMachineVolume';
|
||||
import Network from './kubevirt.io.virtualmachine/VirtualMachineNetwork';
|
||||
import CpuMemory from './kubevirt.io.virtualmachine/VirtualMachineCpuMemory';
|
||||
import CpuModel from './kubevirt.io.virtualmachine/VirtualMachineCpuModel';
|
||||
import CloudConfig from './kubevirt.io.virtualmachine/VirtualMachineCloudConfig';
|
||||
import SSHKey from './kubevirt.io.virtualmachine/VirtualMachineSSHKey';
|
||||
|
||||
@ -38,6 +40,7 @@ export default {
|
||||
Network,
|
||||
Checkbox,
|
||||
CpuMemory,
|
||||
CpuModel,
|
||||
CruResource,
|
||||
CloudConfig,
|
||||
LabeledSelect,
|
||||
@ -154,6 +157,18 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateCpuModel(value) {
|
||||
if (!this.spec?.template?.spec?.domain?.cpu) {
|
||||
set(this.spec, 'template.spec.domain.cpu', {});
|
||||
}
|
||||
|
||||
if (value && value !== '') {
|
||||
set(this.spec.template.spec.domain.cpu, 'model', value);
|
||||
} else {
|
||||
delete this.spec.template.spec.domain.cpu.model;
|
||||
}
|
||||
},
|
||||
|
||||
async saveVMT(buttonCb) {
|
||||
this.parseVM();
|
||||
|
||||
@ -436,6 +451,17 @@ export default {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<CpuModel
|
||||
:value="spec.template.spec.domain.cpu?.model || ''"
|
||||
:mode="mode"
|
||||
@update:value="updateCpuModel"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-20">
|
||||
<a
|
||||
v-if="showAdvanced"
|
||||
|
||||
@ -0,0 +1,133 @@
|
||||
<script>
|
||||
import YAML from 'yaml';
|
||||
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||
import { CONFIG_MAP } from '@shell/config/types';
|
||||
import { Banner } from '@components/Banner';
|
||||
|
||||
const CPU_MODEL_CONFIG_MAP_ID = 'harvester-system/node-cpu-model-configuration';
|
||||
|
||||
export default {
|
||||
name: 'HarvesterCpuModel',
|
||||
|
||||
emits: ['update:value'],
|
||||
|
||||
components: {
|
||||
LabeledSelect,
|
||||
Banner
|
||||
},
|
||||
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'create',
|
||||
},
|
||||
},
|
||||
|
||||
async fetch() {
|
||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||
|
||||
try {
|
||||
await this.$store.dispatch(`${ inStore }/find`, { type: CONFIG_MAP, id: CPU_MODEL_CONFIG_MAP_ID });
|
||||
this.fetchError = null;
|
||||
} catch (e) {
|
||||
this.fetchError = this.t('harvester.virtualMachine.cpuModel.fetchError', { error: e.message || e });
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return { fetchError: null };
|
||||
},
|
||||
|
||||
computed: {
|
||||
localValue: {
|
||||
get() {
|
||||
return this.value ?? '';
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:value', val ?? '');
|
||||
}
|
||||
},
|
||||
|
||||
cpuModelConfigMap() {
|
||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||
|
||||
return this.$store.getters[`${ inStore }/byId`](
|
||||
CONFIG_MAP,
|
||||
CPU_MODEL_CONFIG_MAP_ID
|
||||
);
|
||||
},
|
||||
|
||||
cpuModelOptions() {
|
||||
if (!this.cpuModelConfigMap?.data?.cpuModels) {
|
||||
return [{ label: this.t('generic.default'), value: '' }];
|
||||
}
|
||||
|
||||
let cpuModelsData;
|
||||
|
||||
try {
|
||||
cpuModelsData = YAML.parse(this.cpuModelConfigMap.data?.cpuModels || '');
|
||||
} catch (e) {
|
||||
return [{ label: this.t('generic.default'), value: '' }];
|
||||
}
|
||||
|
||||
const options = [];
|
||||
|
||||
options.push({
|
||||
label: this.t('generic.default'),
|
||||
value: ''
|
||||
});
|
||||
|
||||
// Add global models (host-model, host-passthrough)
|
||||
const globalModels = cpuModelsData.globalModels || [];
|
||||
|
||||
globalModels.forEach((modelName) => {
|
||||
options.push({
|
||||
label: modelName,
|
||||
value: modelName
|
||||
});
|
||||
});
|
||||
|
||||
// Add regular models with node count
|
||||
const modelEntries = Object.entries(cpuModelsData.models || {});
|
||||
|
||||
// Sort models alphabetically for consistent display
|
||||
modelEntries.sort((a, b) => a[0].localeCompare(b[0]));
|
||||
|
||||
modelEntries.forEach(([modelName, modelInfo]) => {
|
||||
const readyCount = modelInfo.readyCount || 0;
|
||||
const label = this.t('harvester.virtualMachine.cpuModel.optionLabel', { modelName, count: readyCount });
|
||||
|
||||
options.push({
|
||||
label,
|
||||
value: modelName
|
||||
});
|
||||
});
|
||||
|
||||
return options;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Banner
|
||||
v-if="fetchError"
|
||||
color="error"
|
||||
class="mb-20"
|
||||
>
|
||||
{{ fetchError }}
|
||||
</Banner>
|
||||
<LabeledSelect
|
||||
v-model:value="localValue"
|
||||
:label="t('harvester.virtualMachine.cpuModel.label')"
|
||||
:options="cpuModelOptions"
|
||||
:mode="mode"
|
||||
:disabled="!!fetchError"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -2,7 +2,7 @@
|
||||
import { isEqual } from 'lodash';
|
||||
import { mapGetters } from 'vuex';
|
||||
import Tabbed from '@shell/components/Tabbed';
|
||||
import { clone } from '@shell/utils/object';
|
||||
import { clone, set } from '@shell/utils/object';
|
||||
import Tab from '@shell/components/Tabbed/Tab';
|
||||
import { Checkbox } from '@components/Form/Checkbox';
|
||||
import CruResource from '@shell/components/CruResource';
|
||||
@ -32,6 +32,7 @@ import PciDevices from './VirtualMachinePciDevices/index';
|
||||
import AccessCredentials from './VirtualMachineAccessCredentials';
|
||||
import CloudConfig from './VirtualMachineCloudConfig';
|
||||
import CpuMemory from './VirtualMachineCpuMemory';
|
||||
import CpuModel from './VirtualMachineCpuModel';
|
||||
import Network from './VirtualMachineNetwork';
|
||||
import Volume from './VirtualMachineVolume';
|
||||
import SSHKey from './VirtualMachineSSHKey';
|
||||
@ -57,6 +58,7 @@ export default {
|
||||
SSHKey,
|
||||
Network,
|
||||
CpuMemory,
|
||||
CpuModel,
|
||||
CloudConfig,
|
||||
NodeScheduling,
|
||||
PodAffinity,
|
||||
@ -538,6 +540,18 @@ export default {
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
updateCpuModel(value) {
|
||||
if (!this.spec?.template?.spec?.domain?.cpu) {
|
||||
set(this.spec, 'template.spec.domain.cpu', {});
|
||||
}
|
||||
|
||||
if (value && value !== '') {
|
||||
set(this.spec.template.spec.domain.cpu, 'model', value);
|
||||
} else {
|
||||
delete this.spec.template.spec.domain.cpu.model;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -870,6 +884,16 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<CpuModel
|
||||
v-model:value="cpuModel"
|
||||
:mode="mode"
|
||||
@update:value="updateCpuModel"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-20">
|
||||
<a
|
||||
v-if="showAdvanced"
|
||||
|
||||
@ -617,6 +617,10 @@ harvester:
|
||||
virtualMachine:
|
||||
label: Virtual Machines
|
||||
osType: OS Type
|
||||
cpuModel:
|
||||
label: CPU Model
|
||||
fetchError: 'Failed to load CPU model configuration: {error}'
|
||||
optionLabel: "{modelName} ({count} {count, plural, one {node} other {nodes}})"
|
||||
hotplug:
|
||||
title: Enable CPU and memory hotplug
|
||||
tooltip: The default maximum CPU and maximum memory are {hotPlugTimes} times based on CPU and memory.
|
||||
|
||||
@ -182,6 +182,7 @@ export default {
|
||||
immutableMode: this.realMode === _CREATE ? _CREATE : _VIEW,
|
||||
terminationGracePeriodSeconds: '',
|
||||
cpuPinning: false,
|
||||
cpuModel: '',
|
||||
};
|
||||
},
|
||||
|
||||
@ -394,6 +395,7 @@ export default {
|
||||
const efiPersistentStateEnabled = this.isEFIPersistentStateEnabled(spec);
|
||||
const secureBoot = this.isSecureBoot(spec);
|
||||
const cpuPinning = this.isCpuPinning(spec);
|
||||
const cpuModel = spec.template.spec.domain.cpu?.model || '';
|
||||
|
||||
const secretRef = this.getSecret(spec);
|
||||
const accessCredentials = this.getAccessCredentials(spec);
|
||||
@ -431,6 +433,7 @@ export default {
|
||||
this['tpmPersistentStateEnabled'] = tpmPersistentStateEnabled;
|
||||
this['secureBoot'] = secureBoot;
|
||||
this['cpuPinning'] = cpuPinning;
|
||||
this['cpuModel'] = cpuModel;
|
||||
|
||||
this['hasCreateVolumes'] = hasCreateVolumes;
|
||||
this['networkRows'] = networkRows;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user