diff --git a/pkg/harvester-manager/l10n/en-us.yaml b/pkg/harvester-manager/l10n/en-us.yaml index 3db1000d06e..6506b3e03c4 100644 --- a/pkg/harvester-manager/l10n/en-us.yaml +++ b/pkg/harvester-manager/l10n/en-us.yaml @@ -20,3 +20,7 @@ harvesterManager: addLabel: Add Workload Selector topologyKey: placeholder: 'topology.kubernetes.io/zone' + vGpu: + title: VGPUs + label: VGPU type + placeholder: 'Please select a VGPU' diff --git a/pkg/harvester-manager/machine-config/harvester.vue b/pkg/harvester-manager/machine-config/harvester.vue index 03bc0cc45b8..b12dfd47cf2 100644 --- a/pkg/harvester-manager/machine-config/harvester.vue +++ b/pkg/harvester-manager/machine-config/harvester.vue @@ -11,6 +11,7 @@ import InfoBox from '@shell/components/InfoBox'; import Loading from '@shell/components/Loading'; import CreateEditView from '@shell/mixins/create-edit-view'; import LabeledSelect from '@shell/components/form/LabeledSelect'; +import ArrayListSelect from '@shell/components/form/ArrayListSelect'; import { LabeledInput } from '@components/Form/LabeledInput'; import UnitInput from '@shell/components/form/UnitInput'; import YamlEditor from '@shell/components/YamlEditor'; @@ -79,11 +80,13 @@ const SOURCE_TYPE = { IMAGE: 'image', }; +const VGPU_PREFIX = { NVIDIA: 'nvidia.com/' }; + export default { name: 'ConfigComponentHarvester', components: { - Checkbox, draggable, Loading, LabeledSelect, LabeledInput, UnitInput, Banner, YamlEditor, NodeAffinity, PodAffinity, InfoBox + ArrayListSelect, Checkbox, draggable, Loading, LabeledSelect, LabeledInput, UnitInput, Banner, YamlEditor, NodeAffinity, PodAffinity, InfoBox }, mixins: [CreateEditView], @@ -321,6 +324,7 @@ export default { vmAffinity = { affinity: clone(vmAffinityObj) }; + let vGpus = []; let networkData = ''; let userData = ''; let installAgent; @@ -350,6 +354,12 @@ export default { } } + if (this.value.vgpuInfo) { + const vGPURequests = JSON.parse(this.value.vgpuInfo)?.vGPURequests; + + vGpus = vGPURequests?.map((r) => r.deviceName?.replace(VGPU_PREFIX.NVIDIA, '')).filter((r) => r) || []; + } + return { credential: null, vmAffinity, @@ -378,7 +388,8 @@ export default { userDataIsBase64, networkDataIsBase64, vmAffinityIsBase64, - SOURCE_TYPE + SOURCE_TYPE, + vGpus, }; }, @@ -448,6 +459,21 @@ export default { topologyKeyPlaceholder: this.t('harvesterManager.affinity.topologyKey.placeholder') }; }, + + vGpuOptions() { + const vGpus = this.allNodeObjects.reduce((acc, node) => { + const nodeVGpus = Object.keys(node.status.allocatable || {}) + .filter((k) => k.startsWith(VGPU_PREFIX.NVIDIA) && node.status.allocatable[k] > 0) + .map((k) => k.replace(VGPU_PREFIX.NVIDIA, '')) || []; + + return [ + ...acc, + ...nodeVGpus + ]; + }, []); + + return vGpus.filter((x) => !this.vGpus.includes(x)); + } }, watch: { @@ -812,6 +838,19 @@ export default { } }, + updateVGpu() { + const vGPURequests = this.vGpus?.filter((name) => name).reduce((acc, name, i) => ([ + ...acc, + { + name: `vgpu${ i + 1 }`, + deviceName: `${ VGPU_PREFIX.NVIDIA }${ name }` + } + ]) + , []); + + this.value.vgpuInfo = vGPURequests.length > 0 ? JSON.stringify({ vGPURequests }) : ''; + }, + addCloudConfigComment(value) { if (typeof value === 'object' && value !== null) { return `#cloud-config\n${ jsyaml.dump(value) }`; @@ -1262,6 +1301,23 @@ export default { +

+ {{ t("harvesterManager.vGpu.title") }} +

+
+ +
+

{{ t("cluster.credential.harvester.userData.title") }}

diff --git a/shell/components/form/ArrayListSelect.vue b/shell/components/form/ArrayListSelect.vue index 8612d9d2381..b43e8b7442c 100644 --- a/shell/components/form/ArrayListSelect.vue +++ b/shell/components/form/ArrayListSelect.vue @@ -37,7 +37,7 @@ export default { }, addAllowed() { - return this.filteredOptions.length > 0; + return this.arrayListProps?.addAllowed || this.filteredOptions.length > 0; }, defaultAddValue() { @@ -48,7 +48,7 @@ export default { methods: { updateRow(index, value) { this.value.splice(index, 1, value); - this.$emit(value); + this.$emit('input', this.value); }, calculateOptions(value) { const valueOption = this.options.find((o) => o.value === value);