diff --git a/pkg/harvester/config/feature-flags.js b/pkg/harvester/config/feature-flags.js
index 2cfeb945..ed611205 100644
--- a/pkg/harvester/config/feature-flags.js
+++ b/pkg/harvester/config/feature-flags.js
@@ -49,6 +49,7 @@ const featuresV142 = [
const featuresV150 = [
...featuresV142,
'tpmPersistentState',
+ 'efiPersistentState',
'untaggedNetworkSetting',
'skipSingleReplicaDetachedVol'
];
diff --git a/pkg/harvester/edit/harvesterhci.io.virtualmachinetemplateversion.vue b/pkg/harvester/edit/harvesterhci.io.virtualmachinetemplateversion.vue
index 477cac13..97e8aee0 100644
--- a/pkg/harvester/edit/harvesterhci.io.virtualmachinetemplateversion.vue
+++ b/pkg/harvester/edit/harvesterhci.io.virtualmachinetemplateversion.vue
@@ -478,7 +478,16 @@ export default {
v-model:value="efiEnabled"
class="check"
type="checkbox"
- :label="t('harvester.virtualMachine.efiEnabled')"
+ :label="t('harvester.virtualMachine.advancedOptions.efiEnabled')"
+ :mode="mode"
+ />
+
+
@@ -487,7 +496,7 @@ export default {
v-model:value="secureBoot"
class="check"
type="checkbox"
- :label="t('harvester.virtualMachine.secureBoot')"
+ :label="t('harvester.virtualMachine.advancedOptions.secureBoot')"
:mode="mode"
/>
diff --git a/pkg/harvester/edit/kubevirt.io.virtualmachine/index.vue b/pkg/harvester/edit/kubevirt.io.virtualmachine/index.vue
index 8e67f575..e7f2bfd0 100644
--- a/pkg/harvester/edit/kubevirt.io.virtualmachine/index.vue
+++ b/pkg/harvester/edit/kubevirt.io.virtualmachine/index.vue
@@ -886,7 +886,16 @@ export default {
v-model:value="efiEnabled"
class="check"
type="checkbox"
- :label="t('harvester.virtualMachine.efiEnabled')"
+ :label="t('harvester.virtualMachine.advancedOptions.efiEnabled')"
+ :mode="mode"
+ />
+
+
@@ -895,7 +904,7 @@ export default {
v-model:value="secureBoot"
class="check"
type="checkbox"
- :label="t('harvester.virtualMachine.secureBoot')"
+ :label="t('harvester.virtualMachine.advancedOptions.secureBoot')"
:mode="mode"
/>
diff --git a/pkg/harvester/l10n/en-us.yaml b/pkg/harvester/l10n/en-us.yaml
index 40599984..2aae4357 100644
--- a/pkg/harvester/l10n/en-us.yaml
+++ b/pkg/harvester/l10n/en-us.yaml
@@ -604,11 +604,12 @@ harvester:
prefix: You must enable CPU Manager for at least one node in
middle: 'host page'
suffix: to enable CPU Pinning for VM
+ efiEnabled: Booting in EFI mode
+ efiPersistentState: EFI Persistent State
+ secureBoot: Secure Boot
usbTip: Provides an absolute pointer device which often helps with getting a consistent mouse cursor position in VNC.
sshTitle: Add Public SSH Key
imageTip: An external URL to the .iso, .img, .qcow2 or .raw that the virtual machine should be created from.
- efiEnabled: Booting in EFI mode
- secureBoot: Secure Boot
volume:
dragTip: Drag and drop volumes, or use the volume's arrows, to change the boot order.
volumeTip: The virtual machine only contains a CD-ROM volume. You may want to add additional disk volumes.
diff --git a/pkg/harvester/mixins/harvester-vm/impl.js b/pkg/harvester/mixins/harvester-vm/impl.js
index ffb0e56a..b1d6df83 100644
--- a/pkg/harvester/mixins/harvester-vm/impl.js
+++ b/pkg/harvester/mixins/harvester-vm/impl.js
@@ -144,6 +144,10 @@ export default {
return !!spec?.template?.spec?.domain?.devices?.tpm?.persistent;
},
+ isEFIPersistentStateEnabled(spec) {
+ return !!spec?.template?.spec?.domain?.firmware?.bootloader?.efi?.persistent;
+ },
+
isSecureBoot(spec) {
return !!spec?.template?.spec?.domain?.firmware?.bootloader?.efi?.secureBoot;
},
diff --git a/pkg/harvester/mixins/harvester-vm/index.js b/pkg/harvester/mixins/harvester-vm/index.js
index 062e57d1..48f1c35d 100644
--- a/pkg/harvester/mixins/harvester-vm/index.js
+++ b/pkg/harvester/mixins/harvester-vm/index.js
@@ -165,6 +165,7 @@ export default {
efiEnabled: false,
tpmEnabled: false,
tpmPersistentStateEnabled: false,
+ efiPersistentStateEnabled: false,
secureBoot: false,
userDataTemplateId: '',
saveUserDataAsClearText: false,
@@ -369,6 +370,7 @@ export default {
const efiEnabled = this.isEfiEnabled(spec);
const tpmEnabled = this.isTpmEnabled(spec);
const tpmPersistentStateEnabled = this.isTPMPersistentStateEnabled(spec);
+ const efiPersistentStateEnabled = this.isEFIPersistentStateEnabled(spec);
const secureBoot = this.isSecureBoot(spec);
const cpuPinning = this.isCpuPinning(spec);
@@ -400,6 +402,7 @@ export default {
this['installUSBTablet'] = installUSBTablet;
this['efiEnabled'] = efiEnabled;
+ this['efiPersistentStateEnabled'] = efiPersistentStateEnabled;
this['tpmEnabled'] = tpmEnabled;
this['tpmPersistentStateEnabled'] = tpmPersistentStateEnabled;
this['secureBoot'] = secureBoot;
@@ -1386,13 +1389,21 @@ export default {
}
},
- setBootMethod(boot = { efi: false, secureBoot: false }) {
- if (boot.efi && boot.secureBoot) {
- set(this.spec.template.spec.domain, 'features.smm.enabled', true);
- set(this.spec.template.spec.domain, 'firmware.bootloader.efi.secureBoot', true);
- } else if (boot.efi && !boot.secureBoot) {
- // set(this.spec.template.spec.domain, 'features.smm.enabled', false);
+ setBootMethod(boot = {
+ efi: false, secureBoot: false, efiPersistentStateEnabled: false
+ }) {
+ if (boot.efi) {
+ set(this.spec.template.spec.domain, 'firmware.bootloader.efi.secureBoot', boot.secureBoot);
+ } else {
+ delete this.spec.template.spec.domain['firmware'];
+ delete this.spec.template.spec.domain.features['smm'];
+ return;
+ }
+
+ if (boot.secureBoot) {
+ set(this.spec.template.spec.domain, 'features.smm.enabled', true);
+ } else {
try {
delete this.spec.template.spec.domain.features.smm['enabled'];
const noKeys = Object.keys(this.spec.template.spec.domain.features.smm).length === 0;
@@ -1401,10 +1412,12 @@ export default {
delete this.spec.template.spec.domain.features['smm'];
}
} catch (e) {}
- set(this.spec.template.spec.domain, 'firmware.bootloader.efi.secureBoot', false);
+ }
+
+ if (boot.efiPersistentStateEnabled) {
+ set(this.spec.template.spec.domain, 'firmware.bootloader.efi.persistent', true);
} else {
- delete this.spec.template.spec.domain['firmware'];
- delete this.spec.template.spec.domain.features['smm'];
+ delete this.spec.template.spec.domain.firmware.bootloader.efi['persistent'];
}
},
@@ -1416,22 +1429,14 @@ export default {
}
},
- setTPM(tpmEnabled) {
+ setTPM({ tpmEnabled = false, tpmPersistentStateEnabled = false } = {}) {
if (tpmEnabled) {
- set(this.spec.template.spec.domain.devices, 'tpm', {});
+ set(this.spec.template.spec.domain.devices, 'tpm', tpmPersistentStateEnabled ? { persistent: true } : {});
} else {
delete this.spec.template.spec.domain.devices['tpm'];
}
},
- setTPMPersistentStateEnabled(tpmPersistentStateEnabled) {
- if (tpmPersistentStateEnabled) {
- set(this.spec.template.spec.domain.devices, 'tpm', { persistent: true });
- } else {
- set(this.spec.template.spec.domain.devices, 'tpm', {});
- }
- },
-
deleteSSHFromUserData(ssh = []) {
const sshAuthorizedKeys = this.getSSHFromUserData(this.userScript);
@@ -1540,11 +1545,21 @@ export default {
},
efiEnabled(val) {
- this.setBootMethod({ efi: val, secureBoot: this.secureBoot });
+ this.setBootMethod({
+ efi: val, secureBoot: this.secureBoot, efiPersistentStateEnabled: this.efiPersistentStateEnabled
+ });
},
secureBoot(val) {
- this.setBootMethod({ efi: this.efiEnabled, secureBoot: val });
+ this.setBootMethod({
+ efi: this.efiEnabled, secureBoot: val, efiPersistentStateEnabled: this.efiPersistentStateEnabled
+ });
+ },
+
+ efiPersistentStateEnabled(val) {
+ this.setBootMethod({
+ efi: this.efiEnabled, secureBoot: this.secureBoot, efiPersistentStateEnabled: val
+ });
},
cpuPinning(value) {
@@ -1552,11 +1567,11 @@ export default {
},
tpmEnabled(val) {
- this.setTPM(val);
+ this.setTPM({ tpmEnabled: val, tpmPersistentStateEnabled: this.tpmPersistentStateEnabled });
},
tpmPersistentStateEnabled(val) {
- this.setTPMPersistentStateEnabled(val);
+ this.setTPM({ tpmEnabled: this.tpmEnabled, tpmPersistentStateEnabled: val });
},
installAgent: {
diff --git a/pkg/harvester/models/harvesterhci.io.virtualmachinetemplateversion.js b/pkg/harvester/models/harvesterhci.io.virtualmachinetemplateversion.js
index fa385dd0..b2036be2 100644
--- a/pkg/harvester/models/harvesterhci.io.virtualmachinetemplateversion.js
+++ b/pkg/harvester/models/harvesterhci.io.virtualmachinetemplateversion.js
@@ -280,4 +280,8 @@ export default class HciVmTemplateVersion extends HarvesterResource {
get tpmPersistentStateFeatureEnabled() {
return this.$rootGetters['harvester-common/getFeatureEnabled']('tpmPersistentState');
}
+
+ get efiPersistentStateFeatureEnabled() {
+ return this.$rootGetters['harvester-common/getFeatureEnabled']('efiPersistentState');
+ }
}
diff --git a/pkg/harvester/models/kubevirt.io.virtualmachine.js b/pkg/harvester/models/kubevirt.io.virtualmachine.js
index 9eea0783..103e32ba 100644
--- a/pkg/harvester/models/kubevirt.io.virtualmachine.js
+++ b/pkg/harvester/models/kubevirt.io.virtualmachine.js
@@ -1179,6 +1179,10 @@ export default class VirtVm extends HarvesterResource {
return this.$rootGetters['harvester-common/getFeatureEnabled']('tpmPersistentState');
}
+ get efiPersistentStateFeatureEnabled() {
+ return this.$rootGetters['harvester-common/getFeatureEnabled']('efiPersistentState');
+ }
+
setInstanceLabels(val) {
if ( !this.spec?.template?.metadata?.labels ) {
set(this, 'spec.template.metadata.labels', {});