From 5e5c898bede9525ce679d6d7391a079a75339a13 Mon Sep 17 00:00:00 2001 From: Francesco Torchia Date: Tue, 17 Sep 2024 19:51:10 +0200 Subject: [PATCH] Add lvm node selector Signed-off-by: Francesco Torchia --- .../HarvesterHostDisk.vue | 2 +- .../harvesterhci.io.host/HarvesterDisk.vue | 4 +- .../edit/harvesterhci.io.storage/index.vue | 28 ++++++-- .../lvm.driver.harvesterhci.io.vue | 68 +++++++++++++++---- pkg/harvester/l10n/en-us.yaml | 2 + 5 files changed, 83 insertions(+), 21 deletions(-) diff --git a/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostDisk.vue b/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostDisk.vue index 4fed063a261..0a441a6045f 100644 --- a/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostDisk.vue +++ b/pkg/harvester/detail/harvesterhci.io.host/HarvesterHostDisk.vue @@ -87,7 +87,7 @@ export default { } }, - provisioner() { + provisioner() { let labelKey = `harvester.storage.storageClass.longhorn.${ LONGHORN_VERSION_V1 }.label`; if (this.value?.blockDevice?.spec?.provisioner.longhorn) { diff --git a/pkg/harvester/edit/harvesterhci.io.host/HarvesterDisk.vue b/pkg/harvester/edit/harvesterhci.io.host/HarvesterDisk.vue index f388641a0be..ac66a65b559 100644 --- a/pkg/harvester/edit/harvesterhci.io.host/HarvesterDisk.vue +++ b/pkg/harvester/edit/harvesterhci.io.host/HarvesterDisk.vue @@ -242,7 +242,7 @@ export default { :label="t('harvester.host.disk.fileSystem.formatting')" /> @@ -333,6 +333,7 @@ export default { :localized-label="true" :searchable="true" :options="provisioners" + :disabled="isProvisioned" @keydown.native.enter.prevent="()=>{}" /> @@ -367,6 +368,7 @@ export default { :searchable="true" :options="lvmVolumeGroups" :required="true" + :disabled="isProvisioned" @keydown.native.enter.prevent="()=>{}" /> diff --git a/pkg/harvester/edit/harvesterhci.io.storage/index.vue b/pkg/harvester/edit/harvesterhci.io.storage/index.vue index 01addcdd31f..0d3f320d2b7 100644 --- a/pkg/harvester/edit/harvesterhci.io.storage/index.vue +++ b/pkg/harvester/edit/harvesterhci.io.storage/index.vue @@ -22,6 +22,7 @@ import { LONGHORN_DRIVER, LONGHORN_VERSION_V1, LONGHORN_VERSION_V2 } from '@shel import { LVM_DRIVER } from '@shell/models/storage.k8s.io.storageclass'; const LONGHORN_V2_DATA_ENGINE = 'longhorn-system/v2-data-engine'; +export const LVM_TOPOLOGY_LABEL = 'topology.lvm.csi/node'; export default { name: 'HarvesterStorage', @@ -72,7 +73,7 @@ export default { } ]; - const allowedTopologies = clone(this.value.allowedTopologies?.[0]?.matchLabelExpressions || []); + const allowedTopologies = clone(this.value.allowedTopologies?.[0]?.matchLabelExpressions || []).filter((t) => t.key !== LVM_TOPOLOGY_LABEL); this.$set(this.value, 'parameters', this.value.parameters || {}); this.$set(this.value, 'provisioner', this.value.provisioner || LONGHORN_DRIVER); @@ -155,6 +156,10 @@ export default { isLonghornV2() { return this.value.provisioner === LONGHORN_DRIVER && this.longhornVersion === LONGHORN_VERSION_V2; }, + + isLvm() { + return this.value.provisioner === LVM_DRIVER; + }, }, watch: { @@ -165,6 +170,16 @@ export default { parameters.migratable = false; } + if (!this.isLvm) { + const matchLabelExpressions = (this.value.allowedTopologies?.[0]?.matchLabelExpressions || []).filter((t) => t.key !== LVM_TOPOLOGY_LABEL); + + if (matchLabelExpressions.length > 0) { + this.$set(this.value, 'allowedTopologies', [{ matchLabelExpressions }]); + } else { + delete this.value.allowedTopologies; + } + } + this.$set(this.value, 'parameters', parameters); } }, @@ -198,10 +213,15 @@ export default { }, formatAllowedTopoloties() { - const neu = this.allowedTopologies; + const neu = this.allowedTopologies.filter((t) => t.key !== LVM_TOPOLOGY_LABEL); + const lvmMatchExpression = (this.value.allowedTopologies?.[0]?.matchLabelExpressions || []).filter((t) => t.key === LVM_TOPOLOGY_LABEL); if (!neu || neu.length === 0) { - delete this.value.allowedTopologies; + if (lvmMatchExpression.length > 0) { + this.value.allowedTopologies = [{ matchLabelExpressions: lvmMatchExpression }]; + } else { + delete this.value.allowedTopologies; + } return; } @@ -209,7 +229,7 @@ export default { const matchLabelExpressions = neu.filter(R => !!R.key.trim() && (R.values.length > 0 && !R.values.find(V => !V.trim()))); if (matchLabelExpressions.length > 0) { - this.value.allowedTopologies = [{ matchLabelExpressions }]; + this.value.allowedTopologies = [{ matchLabelExpressions: [ ...matchLabelExpressions, ...lvmMatchExpression ] }]; } } } diff --git a/pkg/harvester/edit/harvesterhci.io.storage/provisioners/lvm.driver.harvesterhci.io.vue b/pkg/harvester/edit/harvesterhci.io.storage/provisioners/lvm.driver.harvesterhci.io.vue index 85c8dd42d27..8c37766de91 100644 --- a/pkg/harvester/edit/harvesterhci.io.storage/provisioners/lvm.driver.harvesterhci.io.vue +++ b/pkg/harvester/edit/harvesterhci.io.storage/provisioners/lvm.driver.harvesterhci.io.vue @@ -2,28 +2,29 @@ import KeyValue from '@shell/components/form/KeyValue'; import LabeledSelect from '@shell/components/form/LabeledSelect'; -import { LabeledInput } from '@components/Form/LabeledInput'; -import RadioGroup from '@components/Form/Radio/RadioGroup'; import { allHash } from '@shell/utils/promise'; -import { _CREATE, _VIEW } from '@shell/config/query-params'; -import { LONGHORN } from '@shell/config/types'; import { clone } from '@shell/utils/object'; -import { uniq } from '@shell/utils/array'; -import { LONGHORN_VERSION_V1, LONGHORN_VERSION_V2 } from '@shell/models/persistentvolume'; import { HCI } from '../../../types'; +import { NODE } from '@shell/config/types'; +import { LVM_TOPOLOGY_LABEL } from '../index.vue'; const DEFAULT_PARAMETERS = [ 'type', 'vgName' ]; +const DEFAUL_TOPOLOGIES = [{ + matchLabelExpressions: [{ + key: LVM_TOPOLOGY_LABEL, + values: [] + }] +}]; + export default { components: { KeyValue, LabeledSelect, - LabeledInput, - RadioGroup, }, props: { @@ -45,28 +46,49 @@ export default { const inStore = this.$store.getters['currentProduct'].inStore; await allHash({ + nodes: this.$store.dispatch(`${ inStore }/findAll`, { type: NODE }), lvmVolumeGroups: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.LVM_VOLUME_GROUP }), }); }, data() { + const node = (this.value.allowedTopologies?.[0]?.matchLabelExpressions || []).find((t) => t.key === LVM_TOPOLOGY_LABEL)?.values[0]; + return { volumeGroupTypes: ['striped', 'dm-thin'], - volumeGroupType: null, - volumeGroup: null, - nodeName: 'harvester-node-0' + node, }; }, + watch: { + node(value) { + delete (this.value.parameters.vgName); + + const allowedTopologies = [...DEFAUL_TOPOLOGIES]; + + allowedTopologies[0].matchLabelExpressions[0].values = [value]; + + this.value.allowedTopologies = allowedTopologies; + } + }, + computed: { + nodes() { + const inStore = this.$store.getters['currentProduct'].inStore; + const nodes = this.$store.getters[`${ inStore }/all`](NODE) || []; + + return nodes.map(n => n.name); + }, + volumeGroups() { const inStore = this.$store.getters['currentProduct'].inStore; const lvmVolumeGroups = this.$store.getters[`${ inStore }/all`](HCI.LVM_VOLUME_GROUP) || []; return lvmVolumeGroups - .filter(group => group.spec.nodeName === this.nodeName) + .filter(group => group.spec.nodeName === this.node) .map(g => g.spec.vgName); }, + parameters: { get() { const parameters = clone(this.value?.parameters) || {}; @@ -90,7 +112,24 @@ export default {
+ + +
+
+
+
+
- diff --git a/pkg/harvester/l10n/en-us.yaml b/pkg/harvester/l10n/en-us.yaml index dd3d3f1b97c..4eccdf19f42 100644 --- a/pkg/harvester/l10n/en-us.yaml +++ b/pkg/harvester/l10n/en-us.yaml @@ -1083,6 +1083,8 @@ harvester: label: Volume Group Type lvmVolumeGroup: label: Volume Group Name + node: + label: Node allowedTopologies: title: Allowed Topologies tooltip: Allowed Topologies helps scheduling virtual machines on hosts which match all of below expressions.