Skip to content

Commit

Permalink
Merge pull request #1076 from torchiaf/6057-local-path-storage
Browse files Browse the repository at this point in the history
Host local storage support
  • Loading branch information
torchiaf authored Oct 1, 2024
2 parents b816c9c + 21cbfa6 commit 9cf422b
Show file tree
Hide file tree
Showing 23 changed files with 1,072 additions and 122 deletions.
3 changes: 1 addition & 2 deletions pkg/harvester/components/settings/csi-driver-config.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import LabeledSelect from '@shell/components/form/LabeledSelect';
import InfoBox from '@shell/components/InfoBox';
import { CSI_DRIVER, VOLUME_SNAPSHOT_CLASS } from '../../types';
import { allHash } from '@shell/utils/promise';
const LONGHORN_DRIVER = 'driver.longhorn.io';
import { LONGHORN_DRIVER } from '@shell/models/persistentvolume';
export default {
name: 'HarvesterCsiDriver',
Expand Down
1 change: 1 addition & 0 deletions pkg/harvester/config/harvester-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const ADD_ONS = {
RANCHER_LOGGING: 'rancher-logging',
RANCHER_MONITORING: 'rancher-monitoring',
VM_IMPORT_CONTROLLER: 'vm-import-controller',
LVM_DRIVER: 'lvm.driver.harvesterhci.io'
};

export const CSI_SECRETS = {
Expand Down
1 change: 1 addition & 0 deletions pkg/harvester/config/labels-annotations.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ export const HCI = {
CPU_MANAGER: 'cpumanager',
VM_DEVICE_ALLOCATION_DETAILS: 'harvesterhci.io/deviceAllocationDetails',
SVM_BACKUP_ID: 'harvesterhci.io/svmbackupId',
DISABLE_LONGHORN_V2_ENGINE: 'node.longhorn.io/disable-v2-data-engine'
};
24 changes: 23 additions & 1 deletion pkg/harvester/detail/harvesterhci.io.host/HarvesterHostDisk.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Banner } from '@components/Banner';
import HarvesterDisk from '../../mixins/harvester-disk';
import { RadioGroup } from '@components/Form/Radio';
import { LONGHORN_VERSION_V1 } from '@shell/models/persistentvolume';
export default {
components: {
LabelValue,
Expand Down Expand Up @@ -84,6 +86,20 @@ export default {
return '';
}
},
provisioner() {
let labelKey = `harvester.host.disk.storage.longhorn.${ LONGHORN_VERSION_V1 }.label`;
if (this.value?.blockDevice?.spec?.provisioner.longhorn) {
labelKey = `harvester.host.disk.storage.longhorn.${ this.value.blockDevice.spec.provisioner.longhorn.engineVersion }.label`;
}
if (this.value?.blockDevice?.spec?.provisioner.lvm) {
labelKey = 'harvester.host.disk.storage.lvm.label';
}
return this.t(labelKey);
}
},
methods: {
update() {
Expand Down Expand Up @@ -196,12 +212,18 @@ export default {
:value="value.displayName"
/>
</div>
<div class="col span-4">
<div v-if="value.path" class="col span-4">
<LabelValue
:name="t('harvester.host.disk.path.label')"
:value="value.path"
/>
</div>
<div class="col span-4">
<LabelValue
:name="t('harvester.host.disk.provisioner')"
:value="provisioner"
/>
</div>
</div>
</div>
</template>
Expand Down
3 changes: 1 addition & 2 deletions pkg/harvester/detail/harvesterhci.io.host/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,10 @@ 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) => {
return {
Expand Down
225 changes: 220 additions & 5 deletions pkg/harvester/edit/harvesterhci.io.host/HarvesterDisk.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
<script>
import { allHash } from '@shell/utils/promise';
import { CSI_DRIVER, LONGHORN } 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 { LONGHORN_DRIVER, LONGHORN_VERSION_V1, LONGHORN_VERSION_V2 } from '@shell/models/persistentvolume';
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,
},
Expand All @@ -35,18 +49,94 @@ export default {
type: Array,
default: () => [],
},
node: {
type: Object,
default: () => {
return {};
},
},
mode: {
type: String,
default: 'edit',
},
},
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() {
return {};
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(),
};
},
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;
Expand All @@ -56,6 +146,7 @@ export default {
return this.schedulableCondition.message;
}
},
allowSchedulingOptions() {
return [{
label: this.t('generic.enabled'),
Expand Down Expand Up @@ -87,7 +178,7 @@ export default {
},
isProvisioned() {
return this.blockDevice?.spec.fileSystem.provisioned;
return this.blockDevice?.isProvisioned;
},
forceFormattedDisabled() {
Expand Down Expand Up @@ -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.$modal.show(this.randomStr);
},
hideCreateVolumeGroup() {
this.$modal.hide(this.randomStr);
},
saveCreateVolumeGroup(buttonCb) {
buttonCb(true);
this.value.lvmVolumeGroup = this.volumeGroupDialog;
this.hideCreateVolumeGroup();
},
update() {
this.$emit('input', this.value);
},
Expand All @@ -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"
/>
Expand Down Expand Up @@ -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="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.forceFormatted"
:mode="mode"
Expand All @@ -279,7 +459,42 @@ export default {
</template>
</RadioGroup>
</div>
<div v-if="value.isNew && isLvm" class="col span-6">
<LabeledSelect
v-model="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
:ref="randomStr"
:name="randomStr"
width="30%"
@finish="saveCreateVolumeGroup"
>
<template #title>
{{ t('harvester.host.disk.lvmVolumeGroup.label') }}
</template>
<template #content>
<LabeledInput
v-model="volumeGroupDialog"
:label="t('generic.name')"
class="mb-20"
required
@keydown.native.enter.prevent="()=>{}"
/>
</template>
</ModalWithCard>
</div>
</template>
Expand Down
Loading

0 comments on commit 9cf422b

Please sign in to comment.