Skip to content

Commit

Permalink
Bug 2181920: Display "UEFI" for Boot mode for "efi: {}" in yaml
Browse files Browse the repository at this point in the history
This is a followup of kubevirt-ui#1236
introducing the change that "efi: { secureBoot: false }" was written to
VM's yaml when changing Boot mode field value to "UEFI", because that
was correct representation of "UEFI" boot mode (secure boot disabled).

In this commit, the following remaining issues are fixed:

- for existing VM:
-- it shows "UEFI" for Boot mode field in Details for "efi: {}" in the
yaml's bootloader section

- in Create VM wizard:
-- it shows "UEFI" for Boot mode field in Review and create
VirtualMachine screen for "efi: {}" in the yaml's bootloader section

- for existing template:
-- it shows "UEFI" for Boot mode field in Details for "efi: {}" in the
yaml's bootloader section
-- after changing Boot mode field to "UEFI", "efi: {}" occurs in the
yaml (this doesn't happen for existing VMs or when creating a VM)

Fixes https://bugzilla.redhat.com/show_bug.cgi?id=2181920
  • Loading branch information
Hilda Stastna committed May 2, 2023
1 parent 47c28af commit b242624
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import * as React from 'react';
import produce from 'immer';
import React, { ChangeEvent, FC, useMemo, useState } from 'react';

import { V1VirtualMachine, V1VirtualMachineInstance } from '@kubevirt-ui/kubevirt-api/kubevirt';
import TabModal from '@kubevirt-utils/components/TabModal/TabModal';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { ensurePath } from '@kubevirt-utils/utils/utils';
import { Form, FormGroup, Select, SelectOption, SelectVariant } from '@patternfly/react-core';

import { ModalPendingChangesAlert } from '../PendingChanges/ModalPendingChangesAlert/ModalPendingChangesAlert';
import { checkBootModeChanged } from '../PendingChanges/utils/helpers';

import { BootloaderLabel, BootloaderOptionValue } from './utils/constants';
import { getBootloaderFromVM } from './utils/utils';
import { getBootloaderFromVM, updatedVMBootMode } from './utils/utils';

type FirmwareBootloaderModalProps = {
vm: V1VirtualMachine;
Expand All @@ -21,17 +19,17 @@ type FirmwareBootloaderModalProps = {
vmi?: V1VirtualMachineInstance;
};

const FirmwareBootloaderModal: React.FC<FirmwareBootloaderModalProps> = ({
const FirmwareBootloaderModal: FC<FirmwareBootloaderModalProps> = ({
vm,
isOpen,
onClose,
onSubmit,
vmi,
}) => {
const { t } = useKubevirtTranslation();
const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [selectedFirmwareBootloader, setSelectedFirmwareBootloader] =
React.useState<BootloaderOptionValue>(getBootloaderFromVM(vm));
useState<BootloaderOptionValue>(getBootloaderFromVM(vm));

const bootloaderOptions: BootloaderLabel[] = [
{
Expand All @@ -55,39 +53,16 @@ const FirmwareBootloaderModal: React.FC<FirmwareBootloaderModalProps> = ({
},
];

const handleChange = (
event: React.ChangeEvent<HTMLSelectElement>,
value: BootloaderOptionValue,
) => {
const handleChange = (event: ChangeEvent<HTMLSelectElement>, value: BootloaderOptionValue) => {
event.preventDefault();
setSelectedFirmwareBootloader(value);
setIsDropdownOpen(false);
};

const updatedVirtualMachine = React.useMemo(() => {
const updatedVM = produce<V1VirtualMachine>(vm, (vmDraft: V1VirtualMachine) => {
ensurePath(vmDraft, 'spec.template.spec.domain.firmware.bootloader');

ensurePath(vmDraft, 'spec.template.spec.domain.features.smm');
vmDraft.spec.template.spec.domain.features.smm = { enabled: true };

switch (selectedFirmwareBootloader) {
case 'uefi':
vmDraft.spec.template.spec.domain.firmware.bootloader = {
efi: { secureBoot: false },
};
break;
case 'uefiSecure':
vmDraft.spec.template.spec.domain.firmware.bootloader = {
efi: { secureBoot: true },
};
break;
default: // 'bios'
vmDraft.spec.template.spec.domain.firmware.bootloader = { bios: {} };
}
});
return updatedVM;
}, [vm, selectedFirmwareBootloader]);
const updatedVirtualMachine = useMemo(
() => updatedVMBootMode(vm, selectedFirmwareBootloader),
[vm, selectedFirmwareBootloader],
);

return (
<TabModal
Expand Down
41 changes: 39 additions & 2 deletions src/utils/components/FirmwareBootloaderModal/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { TFunction } from 'i18next';
import produce from 'immer';

import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt';
import { ensurePath, isEmpty } from '@kubevirt-utils/utils/utils';

import { BootloaderOptionValue } from './constants';

export const isObjectEmpty = (obj: object): boolean => isEmpty(obj) && obj !== undefined;

export const getBootloaderFromVM = (vm: V1VirtualMachine): BootloaderOptionValue => {
if (vm?.spec?.template?.spec?.domain?.firmware?.bootloader?.efi?.secureBoot) {
const secureBoot = vm?.spec?.template?.spec?.domain?.firmware?.bootloader?.efi;

if (secureBoot?.secureBoot === true || isObjectEmpty(secureBoot)) {
return 'uefiSecure';
}
if (vm?.spec?.template?.spec?.domain?.firmware?.bootloader?.efi) {
if (secureBoot?.secureBoot === false) {
return `uefi`;
}
return 'bios';
Expand All @@ -24,3 +30,34 @@ export const getBootloaderTitleFromVM = (vm: V1VirtualMachine, t: TFunction): st

return titles[bootloader];
};

/**
* A function to return the VirtualMachine object updated with a given boot mode
* @param {V1VirtualMachine} vm - VirtualMachine object
* @param {BootloaderOptionValue} firmwareBootloader - selected boot mode
* @returns {V1VirtualMachine} updated VirtualMachine object
*/
export const updatedVMBootMode = (
vm: V1VirtualMachine,
firmwareBootloader: BootloaderOptionValue,
) =>
produce<V1VirtualMachine>(vm as V1VirtualMachine, (vmDraft: V1VirtualMachine) => {
ensurePath(vmDraft, 'spec.template.spec.domain.firmware.bootloader');
ensurePath(vmDraft, 'spec.template.spec.domain.features.smm');
vmDraft.spec.template.spec.domain.features.smm = { enabled: true };

switch (firmwareBootloader) {
case 'uefi':
vmDraft.spec.template.spec.domain.firmware.bootloader = {
efi: { secureBoot: false },
};
break;
case 'uefiSecure':
vmDraft.spec.template.spec.domain.firmware.bootloader = {
efi: { secureBoot: true },
};
break;
default:
vmDraft.spec.template.spec.domain.firmware.bootloader = { bios: {} };
}
});
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import * as React from 'react';
import React, { ChangeEvent, FC, useMemo, useState } from 'react';
import produce from 'immer';

import { V1Template } from '@kubevirt-ui/kubevirt-api/console';
import {
BootloaderLabel,
BootloaderOptionValue,
} from '@kubevirt-utils/components/FirmwareBootloaderModal/utils/constants';
import { getBootloaderFromVM } from '@kubevirt-utils/components/FirmwareBootloaderModal/utils/utils';
import {
getBootloaderFromVM,
updatedVMBootMode,
} from '@kubevirt-utils/components/FirmwareBootloaderModal/utils/utils';
import TabModal from '@kubevirt-utils/components/TabModal/TabModal';
import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { getTemplateVirtualMachineObject } from '@kubevirt-utils/resources/template';
import { ensurePath } from '@kubevirt-utils/utils/utils';
import { Form, FormGroup, Select, SelectOption, SelectVariant } from '@patternfly/react-core';

type TemplateBootloaderModalProps = {
Expand All @@ -20,18 +22,16 @@ type TemplateBootloaderModalProps = {
onSubmit: (updatedVM: V1Template) => Promise<V1Template | void>;
};

const TemplateBootloaderModal: React.FC<TemplateBootloaderModalProps> = ({
const TemplateBootloaderModal: FC<TemplateBootloaderModalProps> = ({
template,
isOpen,
onClose,
onSubmit,
}) => {
const { t } = useKubevirtTranslation();
const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [selectedFirmwareBootloader, setSelectedFirmwareBootloader] =
React.useState<BootloaderOptionValue>(
getBootloaderFromVM(getTemplateVirtualMachineObject(template)),
);
useState<BootloaderOptionValue>(getBootloaderFromVM(getTemplateVirtualMachineObject(template)));

const bootloaderOptions: BootloaderLabel[] = [
{
Expand All @@ -55,39 +55,20 @@ const TemplateBootloaderModal: React.FC<TemplateBootloaderModalProps> = ({
},
];

const handleChange = (
event: React.ChangeEvent<HTMLSelectElement>,
value: BootloaderOptionValue,
) => {
const handleChange = (event: ChangeEvent<HTMLSelectElement>, value: BootloaderOptionValue) => {
event.preventDefault();
setSelectedFirmwareBootloader(value);
setIsDropdownOpen(false);
};

const updatedTemplate = React.useMemo(() => {
const updatedTemplate = useMemo(() => {
return produce<V1Template>(template, (templateDraft: V1Template) => {
const vmDraft = getTemplateVirtualMachineObject(templateDraft);
ensurePath(vmDraft, 'spec.template.spec.domain.firmware.bootloader');

ensurePath(vmDraft, 'spec.template.spec.domain.features.smm');
vmDraft.spec.template.spec.domain.features.smm = { enabled: true };
const updatedVM = updatedVMBootMode(vmDraft, selectedFirmwareBootloader);

switch (selectedFirmwareBootloader) {
case 'uefi':
vmDraft.spec.template.spec.domain.firmware.bootloader = {
efi: {},
};
break;
case 'uefiSecure':
vmDraft.spec.template.spec.domain.firmware.bootloader = {
efi: { secureBoot: true },
};
break;
default: // 'bios'
vmDraft.spec.template.spec.domain.firmware.bootloader = { bios: {} };
}
vmDraft.spec.template.spec.domain = updatedVM.spec.template.spec.domain;
});
}, [template, selectedFirmwareBootloader]);
}, [selectedFirmwareBootloader, template]);

return (
<TabModal
Expand Down

0 comments on commit b242624

Please sign in to comment.