Latest changes from Harvester master - d7d9d4af8a88d677695d7aff47a81d52041dfcca

Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
This commit is contained in:
Francesco Torchia
2024-11-12 11:50:17 +01:00
parent d04cd35a08
commit dc74441d26
46 changed files with 1290 additions and 1624 deletions
@@ -1,22 +1,35 @@
<script>
import { allHash } from '@shell/utils/promise';
import { CSI_DRIVER, LONGHORN, LONGHORN_DRIVER, LONGHORN_VERSION_V1, LONGHORN_VERSION_V2 } from '@shell/config/types';
import { LabeledInput } from '@components/Form/LabeledInput';
import LabelValue from '@shell/components/LabelValue';
import { BadgeState } from '@components/BadgeState';
import { Banner } from '@components/Banner';
import LabeledSelect from '@shell/components/form/LabeledSelect';
import { RadioGroup, RadioButton } from '@components/Form/Radio';
import HarvesterDisk from '../../mixins/harvester-disk';
import Tags from '../../components/DiskTags';
import { HCI } from '../../types';
import { HCI as HCI_LABELS_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations';
import { LONGHORN_SYSTEM } from './index';
import { LVM_DRIVER } from '../../models/harvester/storage.k8s.io.storageclass';
import ModalWithCard from '@shell/components/ModalWithCard';
import { randomStr } from '@shell/utils/string';
import { LONGHORN_V2_DATA_ENGINE } from './index.vue';
import { _EDIT } from '@shell/config/query-params';
const _NEW = '_NEW';
export default {
components: {
LabeledInput,
LabeledSelect,
LabelValue,
BadgeState,
Banner,
RadioGroup,
RadioButton,
ModalWithCard,
Tags,
},
@@ -35,18 +48,95 @@ export default {
type: Array,
default: () => [],
},
node: {
type: Object,
default: () => {
return {};
},
},
mode: {
type: String,
default: 'edit',
},
},
data() {
return {};
async fetch() {
const inStore = this.$store.getters['currentProduct'].inStore;
await allHash({
csiDrivers: this.$store.dispatch(`${ inStore }/findAll`, { type: CSI_DRIVER }),
lvmVolumeGroups: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.LVM_VOLUME_GROUP }),
});
},
data() {
let provisioner = `${ this.value.provisioner || LONGHORN_DRIVER }`;
if (provisioner === LONGHORN_DRIVER) {
provisioner = `${ provisioner }_${ this.value.provisionerVersion || LONGHORN_VERSION_V1 }`;
}
return {
provisioner,
volumeGroupDialog: null,
randomStr: randomStr(10).toLowerCase(),
isOpen: false
};
},
computed: {
provisioners() {
const out = [];
const inStore = this.$store.getters['currentProduct'].inStore;
const csiDrivers = this.$store.getters[`${ inStore }/all`](CSI_DRIVER) || [];
csiDrivers.forEach(({ name }) => {
switch (name) {
case LONGHORN_DRIVER:
out.push({
label: `harvester.host.disk.storage.longhorn.${ LONGHORN_VERSION_V1 }.label`,
value: `${ name }_${ LONGHORN_VERSION_V1 }`,
});
if (this.longhornSystemVersion === LONGHORN_VERSION_V2 || this.value.provisionerVersion === LONGHORN_VERSION_V2) {
out.push({
label: `harvester.host.disk.storage.longhorn.${ LONGHORN_VERSION_V2 }.label`,
value: `${ name }_${ LONGHORN_VERSION_V2 }`,
disabled: this.forceLonghornV1
});
}
break;
case LVM_DRIVER:
out.push({
label: 'harvester.host.disk.storage.lvm.label',
value: name,
});
break;
}
});
return out;
},
lvmVolumeGroups() {
const inStore = this.$store.getters['currentProduct'].inStore;
const lvmVolumeGroups = this.$store.getters[`${ inStore }/all`](HCI.LVM_VOLUME_GROUP) || [];
const out = lvmVolumeGroups.filter(group => group.spec.nodeName === this.node.name).map(g => g.spec.vgName);
out.unshift({
label: this.t('harvester.host.disk.lvmVolumeGroup.create'),
value: _NEW,
});
return out;
},
targetDisk() {
return this.disks.find(disk => disk.name === this.value.name);
},
schedulableTooltipMessage() {
const { name, path } = this.value;
@@ -56,6 +146,7 @@ export default {
return this.schedulableCondition.message;
}
},
allowSchedulingOptions() {
return [{
label: this.t('generic.enabled'),
@@ -87,7 +178,7 @@ export default {
},
isProvisioned() {
return this.blockDevice?.spec.fileSystem.provisioned;
return this.blockDevice?.isProvisioned;
},
forceFormattedDisabled() {
@@ -153,8 +244,83 @@ export default {
isFormatting() {
return this.blockDevice.isFormatting;
},
longhornSystemVersion() {
const inStore = this.$store.getters['currentProduct'].inStore;
const v2DataEngine = this.$store.getters[`${ inStore }/byId`](LONGHORN.SETTINGS, LONGHORN_V2_DATA_ENGINE) || {};
return v2DataEngine.value === 'true' ? LONGHORN_VERSION_V2 : LONGHORN_VERSION_V1;
},
forceLonghornV1() {
return this.node?.labels[HCI_LABELS_ANNOTATIONS.DISABLE_LONGHORN_V2_ENGINE] === 'true';
},
isLvm() {
return this.value.provisioner === LVM_DRIVER;
},
isLonghorn() {
return this.value.provisioner === LONGHORN_DRIVER;
},
isLonghornV1() {
return this.isLonghorn && this.value.provisionerVersion === LONGHORN_VERSION_V1;
},
provisionerTooltip() {
if (
this.mode === _EDIT &&
this.isLonghorn &&
this.longhornSystemVersion === LONGHORN_VERSION_V2 &&
this.forceLonghornV1
) {
return this.t('harvester.storage.storageClass.longhorn.versionTooltip');
}
return null;
}
},
watch: {
provisioner(value) {
this.randomStr = randomStr(10).toLowerCase();
const [provisioner, provisionerVersion] = value?.split('_');
this.value.provisioner = provisioner;
if (provisioner === LONGHORN_DRIVER) {
this.value.provisionerVersion = provisionerVersion || LONGHORN_VERSION_V1;
} else {
this.value.provisionerVersion = undefined;
}
},
'value.lvmVolumeGroup'(neu) {
if (neu === _NEW) {
this.value.lvmVolumeGroup = null;
this.showCreateVolumeGroup();
}
}
},
methods: {
showCreateVolumeGroup() {
this.volumeGroupDialog = null;
this.isOpen = true;
},
hideCreateVolumeGroup() {
this.isOpen = false;
},
saveCreateVolumeGroup(buttonCb) {
buttonCb(true);
this.value.lvmVolumeGroup = this.volumeGroupDialog;
this.hideCreateVolumeGroup();
},
update() {
this.$emit('update:value', this.value);
},
@@ -176,7 +342,7 @@ export default {
:label="t('harvester.host.disk.fileSystem.formatting')"
/>
<Banner
v-else-if="isFormatted && !isCorrupted"
v-else-if="isFormatted && isLonghornV1 && !isCorrupted"
color="info"
:label="formattedBannerLabel"
/>
@@ -256,8 +422,22 @@ export default {
/>
</div>
</div>
<div v-if="(value.isNew && !isFormatted) || isCorrupted" class="row mt-10">
<div class="col span-6">
<div class="row mt-10">
<div :class="`col span-${ value.isNew ? '6': '12' }`">
<LabeledSelect
v-model:value="provisioner"
:mode="mode"
label-key="harvester.host.disk.provisioner"
:localized-label="true"
:searchable="true"
:options="provisioners"
:disabled="isProvisioned || !value.isNew"
:tooltip="provisionerTooltip"
@keydown.native.enter.prevent="()=>{}"
/>
</div>
<div v-if="(value.isNew && isLonghornV1 && !isFormatted) || isCorrupted" class="col span-6">
<RadioGroup
v-model:value="value.forceFormatted"
:mode="mode"
@@ -279,7 +459,44 @@ export default {
</template>
</RadioGroup>
</div>
<div v-if="value.isNew && isLvm" class="col span-6">
<LabeledSelect
v-model:value="value.lvmVolumeGroup"
:mode="mode"
label-key="harvester.host.disk.lvmVolumeGroup.label"
:localized-label="true"
:searchable="false"
:taggable="true"
:multiple="false"
:required="true"
:disabled="isProvisioned"
:options="lvmVolumeGroups"
@keydown.native.enter.prevent="()=>{}"
/>
</div>
</div>
<ModalWithCard
v-if="isOpen"
:ref="randomStr"
:name="randomStr"
width="30%"
@finish="saveCreateVolumeGroup"
@close="hideCreateVolumeGroup"
>
<template #title>
{{ t('harvester.host.disk.lvmVolumeGroup.label') }}
</template>
<template #content>
<LabeledInput
v-model:value="volumeGroupDialog"
:label="t('generic.name')"
class="mb-20"
required
@keydown.native.enter.prevent="()=>{}"
/>
</template>
</ModalWithCard>
</div>
</template>
@@ -9,7 +9,7 @@ import ArrayListGrouped from '@shell/components/form/ArrayListGrouped';
import ButtonDropdown from '@shell/components/ButtonDropdown';
import CreateEditView from '@shell/mixins/create-edit-view';
import { HCI as HCI_LABELS_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations';
import { LONGHORN, SECRET } from '@shell/config/types';
import { LONGHORN, SECRET, LONGHORN_DRIVER, LONGHORN_VERSION_V1, LONGHORN_VERSION_V2 } from '@shell/config/types';
import { allHash } from '@shell/utils/promise';
import { formatSi } from '@shell/utils/units';
import { findBy } from '@shell/utils/array';
@@ -29,9 +29,13 @@ import HarvesterDisk from './HarvesterDisk';
import HarvesterSeeder from './HarvesterSeeder';
import HarvesterKsmtuned from './HarvesterKsmtuned';
import Tags from '../../components/DiskTags';
import { LVM_DRIVER } from '../../models/harvester/storage.k8s.io.storageclass';
import isEqual from 'lodash/isEqual';
export const LONGHORN_SYSTEM = 'longhorn-system';
export const LONGHORN_V2_DATA_ENGINE = 'longhorn-system/v2-data-engine';
export default {
name: 'HarvesterEditNode',
@@ -66,10 +70,11 @@ export default {
const inStore = this.$store.getters['currentProduct'].inStore;
const hash = {
longhornNodes: this.$store.dispatch(`${ inStore }/findAll`, { type: LONGHORN.NODES }),
blockDevices: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.BLOCK_DEVICE }),
addons: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.ADD_ONS }),
secrets: this.$store.dispatch(`${ inStore }/findAll`, { type: SECRET }),
longhornNodes: this.$store.dispatch(`${ inStore }/findAll`, { type: LONGHORN.NODES }),
blockDevices: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.BLOCK_DEVICE }),
addons: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.ADD_ONS }),
secrets: this.$store.dispatch(`${ inStore }/findAll`, { type: SECRET }),
longhornV2DataEngine: this.$store.dispatch(`${ inStore }/find`, { type: LONGHORN.SETTINGS, id: LONGHORN_V2_DATA_ENGINE }),
};
if (this.$store.getters[`${ inStore }/schemaFor`](HCI.INVENTORY)) {
@@ -80,23 +85,25 @@ export default {
const blockDevices = this.$store.getters[`${ inStore }/all`](HCI.BLOCK_DEVICE);
const provisionedBlockDevices = blockDevices.filter((d) => {
const provisioned = d?.spec?.fileSystem?.provisioned;
const isCurrentNode = d?.spec?.nodeName === this.value.id;
const isLonghornMounted = findBy(this.longhornDisks, 'name', d.metadata.name);
return provisioned && isCurrentNode && !isLonghornMounted;
return d?.isProvisioned && isCurrentNode && !isLonghornMounted;
})
.map((d) => {
const corrupted = d?.status?.deviceStatus?.fileSystem?.corrupted;
return {
isNew: true,
name: d?.metadata?.name,
originPath: d?.spec?.fileSystem?.mountPoint,
path: d?.spec?.fileSystem?.mountPoint,
blockDevice: d,
displayName: d?.displayName,
forceFormatted: corrupted ? true : d?.spec?.fileSystem?.forceFormatted || false,
isNew: true,
name: d?.metadata?.name,
originPath: d?.spec?.fileSystem?.mountPoint,
path: d?.spec?.fileSystem?.mountPoint,
blockDevice: d,
displayName: d?.displayName,
forceFormatted: corrupted ? true : d?.spec?.fileSystem?.forceFormatted || false,
provisioner: d?.spec?.provisioner?.lvm ? LVM_DRIVER : LONGHORN_DRIVER,
provisionerVersion: d?.spec?.provisioner?.longhorn?.engineVersion || LONGHORN_VERSION_V1,
lvmVolumeGroup: d?.spec?.provisioner?.lvm?.vgName,
};
});
@@ -160,6 +167,13 @@ export default {
return out;
},
longhornSystemVersion() {
const inStore = this.$store.getters['currentProduct'].inStore;
const v2DataEngine = this.$store.getters[`${ inStore }/byId`](LONGHORN.SETTINGS, LONGHORN_V2_DATA_ENGINE) || {};
return v2DataEngine.value === 'true' ? LONGHORN_VERSION_V2 : LONGHORN_VERSION_V1;
},
longhornDisks() {
const inStore = this.$store.getters['currentProduct'].inStore;
const longhornNode = this.$store.getters[`${ inStore }/byId`](LONGHORN.NODES, `${ LONGHORN_SYSTEM }/${ this.value.id }`);
@@ -180,16 +194,19 @@ export default {
return {
...diskStatus[key],
...diskSpec?.[key],
name: key,
isNew: false,
storageReserved: formatSi(diskSpec[key]?.storageReserved, formatOptions),
storageAvailable: formatSi(diskStatus[key]?.storageAvailable, formatOptions),
storageMaximum: formatSi(diskStatus[key]?.storageMaximum, formatOptions),
storageScheduled: formatSi(diskStatus[key]?.storageScheduled, formatOptions),
name: key,
isNew: false,
storageReserved: formatSi(diskSpec[key]?.storageReserved, formatOptions),
storageAvailable: formatSi(diskStatus[key]?.storageAvailable, formatOptions),
storageMaximum: formatSi(diskStatus[key]?.storageMaximum, formatOptions),
storageScheduled: formatSi(diskStatus[key]?.storageScheduled, formatOptions),
blockDevice,
displayName: blockDevice?.displayName || key,
forceFormatted: blockDevice?.spec?.fileSystem?.forceFormatted || false,
tags: diskSpec?.[key]?.tags || [],
displayName: blockDevice?.displayName || key,
forceFormatted: blockDevice?.spec?.fileSystem?.forceFormatted || false,
tags: diskSpec?.[key]?.tags || [],
provisioner: blockDevice?.spec?.provisioner?.lvm ? LVM_DRIVER : LONGHORN_DRIVER,
provisionerVersion: blockDevice?.spec?.provisioner?.longhorn?.engineVersion || LONGHORN_VERSION_V1,
lvmVolumeGroup: blockDevice?.spec?.provisioner?.lvm?.vgName,
};
});
@@ -197,7 +214,7 @@ export default {
},
showFormattedWarning() {
const out = this.newDisks.filter(d => d.forceFormatted && d.isNew) || [];
const out = this.newDisks.filter(d => d.forceFormatted && d.isNew && d.provisionerVersion === LONGHORN_VERSION_V1) || [];
return out.length > 0;
},
@@ -316,15 +333,18 @@ export default {
this.newDisks.push({
name,
path: mountPoint,
allowScheduling: false,
evictionRequested: false,
storageReserved: 0,
isNew: true,
originPath: disk?.spec?.fileSystem?.mountPoint,
blockDevice: disk,
displayName: disk?.displayName,
path: mountPoint,
allowScheduling: false,
evictionRequested: false,
storageReserved: 0,
isNew: true,
originPath: disk?.spec?.fileSystem?.mountPoint,
blockDevice: disk,
displayName: disk?.displayName,
forceFormatted,
provisioner: LONGHORN_DRIVER,
provisionerVersion: LONGHORN_VERSION_V1,
lvmVolumeGroup: null,
});
},
@@ -338,13 +358,10 @@ export default {
} else if (addDisks.length !== 0 && removeDisks.length === 0) {
const updatedDisks = addDisks.filter((d) => {
const blockDevice = this.$store.getters[`${ inStore }/byId`](HCI.BLOCK_DEVICE, `${ LONGHORN_SYSTEM }/${ d.name }`);
const { provisioned, forceFormatted } = blockDevice.spec.fileSystem;
const { forceFormatted } = blockDevice.spec.fileSystem;
const { provisioner } = blockDevice.spec;
if (provisioned && forceFormatted === d.forceFormatted) {
return false;
} else {
return true;
}
return !(blockDevice.isProvisioned && forceFormatted === d.forceFormatted && isEqual(provisioner, d.provisioner));
});
if (updatedDisks.length === 0) {
@@ -356,16 +373,25 @@ export default {
await Promise.all(addDisks.map((d) => {
const blockDevice = this.$store.getters[`${ inStore }/byId`](HCI.BLOCK_DEVICE, `${ LONGHORN_SYSTEM }/${ d.name }`);
blockDevice.spec.fileSystem.provisioned = true;
blockDevice.spec.provision = true;
blockDevice.spec.fileSystem.forceFormatted = d.forceFormatted;
switch (d.provisioner) {
case LONGHORN_DRIVER:
blockDevice.spec.provisioner = { longhorn: { engineVersion: d.provisionerVersion } };
break;
case LVM_DRIVER:
blockDevice.spec.provisioner = { lvm: { vgName: d.lvmVolumeGroup } };
break;
}
return blockDevice.save();
}));
await Promise.all(removeDisks.map((d) => {
const blockDevice = this.$store.getters[`${ inStore }/byId`](HCI.BLOCK_DEVICE, `${ LONGHORN_SYSTEM }/${ d.name }`);
blockDevice.spec.fileSystem.provisioned = false;
blockDevice.spec.provision = false;
return blockDevice.save();
}));
@@ -418,7 +444,7 @@ export default {
if ((!findBy(this.disks || [], 'name', d.metadata.name) &&
d?.spec?.nodeName === this.value.id &&
(!addedToNodeCondition || addedToNodeCondition?.status === 'False') &&
!d.spec?.fileSystem?.provisioned &&
!d?.isProvisioned &&
!isAdded) ||
isRemoved
) {
@@ -573,6 +599,7 @@ export default {
class="mb-20"
:mode="mode"
:disks="disks"
:node="value"
/>
</template>
<template #add>