Add volumeMode dropdown for third-party storage (#197) (#200)

Signed-off-by: Andy Lee <andy.lee@suse.com>
(cherry picked from commit 90c923b480a24c6aafc002fbeb4bf5c107af3762)

Co-authored-by: Andy Lee <andy.lee@suse.com>
This commit is contained in:
mergify[bot] 2025-03-12 14:29:40 +08:00 committed by GitHub
parent 7c1596c965
commit 44f003309c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 92 additions and 6 deletions

View File

@ -50,6 +50,7 @@ export const HCI = {
STORAGE_NETWORK: 'storage-network.settings.harvesterhci.io',
ADDON_EXPERIMENTAL: 'addon.harvesterhci.io/experimental',
VOLUME_ERROR: 'longhorn.io/volume-scheduling-error',
VOLUME_FOR_VM: 'harvesterhci.io/volumeForVirtualMachine',
KVM_AMD_CPU: 'cpu-feature.node.kubevirt.io/svm',
KVM_INTEL_CPU: 'cpu-feature.node.kubevirt.io/vmx',
NODE_MANUFACTURER: 'manufacturer',

View File

@ -7,3 +7,8 @@ export const NETWORK_TYPE = {
L2VLAN: 'L2VlanNetwork',
UNTAGGED: 'UntaggedNetwork'
};
export const VOLUME_MODE = {
BLOCK: 'Block',
FILE_SYSTEM: 'Filesystem'
};

View File

@ -22,6 +22,7 @@ import { HCI, VOLUME_SNAPSHOT } from '../types';
import { LVM_DRIVER } from '../models/harvester/storage.k8s.io.storageclass';
import { DATA_ENGINE_V2 } from '../models/harvester/persistentvolumeclaim';
import { GIBIBYTE } from '../utils/unit';
import { VOLUME_MODE } from '@pkg/harvester/config/types';
export default {
name: 'HarvesterVolume',
@ -73,7 +74,8 @@ export default {
data() {
if (this.mode === _CREATE) {
this.value.spec.volumeMode = 'Block';
// default volumeMode to Block
this.value.spec.volumeMode = VOLUME_MODE.BLOCK;
this.value.spec.accessModes = ['ReadWriteMany'];
}
@ -126,6 +128,10 @@ export default {
return InterfaceOption;
},
volumeModeOptions() {
return Object.values(VOLUME_MODE);
},
imageOption() {
return sortBy(
this.images
@ -179,6 +185,25 @@ export default {
return this.$store.getters[`${ inStore }/all`](STORAGE_CLASS);
},
isLonghornStorageClass() {
const selectedSC = this.storageClasses.find((sc) => sc.name === this.value?.spec?.storageClassName) || {};
return selectedSC && selectedSC.isLonghorn;
},
showVolumeMode() {
// we won't let user choose volumeMode if source = vmimage
if (!this.value.thirdPartyStorageFeatureEnabled || this.isVMImage || !!this.value?.spec?.storageClassName === false) {
return false;
}
if (this.isLonghornStorageClass) {
return false;
}
return true;
},
storageClassOptions() {
return this.storageClasses.filter((s) => !s.parameters?.backingImage).map((s) => {
const label = s.isDefault ? `${ s.name } (${ this.t('generic.default') })` : s.name;
@ -237,7 +262,43 @@ export default {
}
},
watch: {
'source'(neu) {
if (neu === 'url') {
this.setBlockVolumeMode();
this.deleteVolumeForVmAnnotation();
}
},
'value.spec.storageClassName'() {
if (this.isLonghornStorageClass) {
this.setBlockVolumeMode();
this.deleteVolumeForVmAnnotation();
}
},
'value.spec.volumeMode'(neu) {
if (neu === VOLUME_MODE.FILE_SYSTEM) {
this.setVolumeForVmAnnotation();
} else if (neu === VOLUME_MODE.BLOCK ) {
this.deleteVolumeForVmAnnotation();
}
}
},
methods: {
setBlockVolumeMode() {
this.value.spec.volumeMode = VOLUME_MODE.BLOCK;
},
setVolumeForVmAnnotation() {
this.value.setAnnotation(HCI_ANNOTATIONS.VOLUME_FOR_VM, 'true');
},
deleteVolumeForVmAnnotation() {
if (this.value?.metadata?.annotations?.[HCI_ANNOTATIONS.VOLUME_FOR_VM]) {
delete this.value.metadata.annotations[HCI_ANNOTATIONS.VOLUME_FOR_VM];
}
},
getAccessMode() {
if (!this.longhornV2LVMSupport) {
return ['ReadWriteMany'];
@ -359,7 +420,7 @@ export default {
/>
<LabeledSelect
v-if="source === 'blank'"
v-if="isBlank"
v-model:value="value.spec.storageClassName"
:options="storageClassOptions"
:label="t('harvester.storage.storageClass.label')"
@ -369,6 +430,18 @@ export default {
@update:value="update"
/>
<LabeledSelect
v-if="showVolumeMode"
v-model:value="value.spec.volumeMode"
:label="t('harvester.volume.volumeMode')"
:options="volumeModeOptions"
required
:disabled="!isCreate"
:mode="mode"
class="mb-20"
@update:value="update"
/>
<UnitInput
v-model:value="storage"
:label="t('harvester.volume.size')"

View File

@ -17,6 +17,7 @@ import { PLUGIN_DEVELOPER, DEV } from '@shell/store/prefs';
import { SOURCE_TYPE } from '../../../config/harvester-map';
import { PRODUCT_NAME as HARVESTER_PRODUCT } from '../../../config/harvester';
import { HCI } from '../../../types';
import { VOLUME_MODE } from '@pkg/harvester/config/types';
export default {
emits: ['update:value'],
@ -62,7 +63,7 @@ export default {
customVolumeMode: {
type: String,
default: 'Block'
default: VOLUME_MODE.Block
},
customAccessMode: {

View File

@ -791,6 +791,7 @@ harvester:
datasource: Data Source
details: Details
size: Size
volumeMode: Volume Mode
source: Source
kind: Kind
sourceOptions:

View File

@ -26,6 +26,7 @@ import { HCI } from '../../types';
import { parseVolumeClaimTemplates } from '../../utils/vm';
import impl, { QGA_JSON, USB_TABLET } from './impl';
import { GIBIBYTE } from '../../utils/unit';
import { VOLUME_MODE } from '@pkg/harvester/config/types';
const LONGHORN_V2_DATA_ENGINE = 'longhorn-system/v2-data-engine';
@ -261,7 +262,7 @@ export default {
},
customVolumeMode() {
return this.storageClassSetting.volumeMode || 'Block';
return this.storageClassSetting.volumeMode || VOLUME_MODE.BLOCK;
},
customAccessMode() {
@ -463,7 +464,7 @@ export default {
type,
storageClassName: '',
image: this.imageId,
volumeMode: 'Block',
volumeMode: VOLUME_MODE.BLOCK,
isEncrypted,
volumeBackups,
});
@ -522,7 +523,7 @@ export default {
accessMode = pvcResource?.spec?.accessModes?.[0] || 'ReadWriteMany';
size = pvcResource?.spec?.resources?.requests?.storage || '10Gi';
storageClassName = pvcResource?.spec?.storageClassName;
volumeMode = pvcResource?.spec?.volumeMode || 'Block';
volumeMode = pvcResource?.spec?.volumeMode || VOLUME_MODE.BLOCK;
volumeName = pvcResource?.metadata?.name || '';
}

View File

@ -62,6 +62,10 @@ export default class HciStorageClass extends StorageClass {
return this.parameters?.encrypted === 'true';
}
get isLonghorn() {
return this.provisioner === LONGHORN_DRIVER;
}
get isLonghornV1() {
return this.provisioner === LONGHORN_DRIVER && this.longhornVersion === DATA_ENGINE_V1;
}