Skip to content

Commit

Permalink
Force UEFI Bios if required to enable TPM (#1636)
Browse files Browse the repository at this point in the history
In order to enable TPM, the VM needs to use UEFI firmware.
Currently oVirt supports 2 types of UEFI firmwares:
1. standard - 'q35_ovmf'
2. secure - 'q35_secure_boot'

As requested in [1], we should force 'q35_ovmf' firmware type if the
current firmware prevents enabling TPM:
1. in 'create VM' scenario - override the cluster defaults
2. in 'edit VM' scenario  - override previous value

Known issues:
1. if firmware is different than cluster defaults then a warning icon
   is displayed in the Web Admin UI -> VM details -> General tab
2. in VM Portal it's not possible to revert firmware to previous value
   which prevents some OS configurations i.e. Windows XP

[1] #1596 (comment)

Reference-Url: #1596
  • Loading branch information
rszwajko authored Dec 15, 2022
1 parent 52b126e commit 96a70c4
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/components/CreateVmWizard/CreateVmWizard.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const DEFAULT_STATE = {
threads: 1,
},
tpmEnabled: undefined,
biosType: undefined,
},
network: {
nics: [],
Expand Down
1 change: 1 addition & 0 deletions src/components/CreateVmWizard/dataPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const BASIC_DATA_SHAPE = {

operatingSystemId: PropTypes.string,
tpmEnabled: PropTypes.bool,
biosType: PropTypes.string,
memory: PropTypes.number, // in MiB
cpus: PropTypes.number,
optimizedFor: PropTypes.oneOf(['desktop', 'server', 'high_performance']),
Expand Down
3 changes: 3 additions & 0 deletions src/components/CreateVmWizard/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getDefaultOSByArchitecture,
isWindows,
isTpmRequired,
forceUefiBios,
} from '_/helpers'

const handleClusterIdChange = (clusterId, { blankTemplateId, defaultValues, clusters, templates, operatingSystems, storageDomains, defaultGeneralTimezone, defaultWindowsTimezone, locale }) => {
Expand Down Expand Up @@ -74,6 +75,7 @@ const handleProvisionSourceChange = (provisionSource, { defaultValues, defaultGe
changes.templateId = undefined
changes.operatingSystemId = verifyOsIdToCluster(defaultValues.operatingSystemId, clusterId, { clusters, operatingSystems })
changes.tpmEnabled = isTpmRequired(changes.operatingSystemId, operatingSystems) || undefined
changes.biosType = forceUefiBios({ operatingSystemId: changes.operatingSystemId, operatingSystems, clusterId, clusters })
changes.memory = defaultValues.memory
changes.cpus = defaultValues.cpus
changes.topology = defaultValues.topology
Expand Down Expand Up @@ -102,6 +104,7 @@ const handleTemplateIdChange = (templateId, defaultOptimizedFor, { templates, op
.get('id')
changes.operatingSystemId = verifyOsIdToCluster(suggestedOs, clusterId, { clusters, operatingSystems })
changes.tpmEnabled = isTpmRequired(changes.operatingSystemId, operatingSystems) || undefined
changes.biosType = forceUefiBios({ operatingSystemId: changes.operatingSystemId, operatingSystems, clusterId, clusters })
// Check template's timezone compatibility with the template's OS, set the timezone corresponding to the template's OS
changes.timeZone = checkTimeZone(changes.operatingSystemId, changes.templateId, { defaultGeneralTimezone, defaultWindowsTimezone, templates, operatingSystems })
changes.cloudInitEnabled = template.getIn(['cloudInit', 'enabled'])
Expand Down
5 changes: 3 additions & 2 deletions src/components/CreateVmWizard/steps/BasicSettings.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { localeCompare, isTpmRequired } from '_/helpers'
import { localeCompare, isTpmRequired, forceUefiBios } from '_/helpers'
import { withMsg } from '_/intl'
import { isNumberInRange } from '_/utils'
import { BASIC_DATA_SHAPE } from '../dataPropTypes'
Expand Down Expand Up @@ -316,13 +316,14 @@ class BasicSettings extends React.Component {

case 'operatingSystemId': {
changes[field] = value
const { data: { templateId } } = this.props
const { data: { templateId }, operatingSystems, clusters, data } = this.props
changes.timeZone = checkTimeZone(value, templateId, this.props)
// only when changing the OS from one Windows to other Windows
changes.initTimezone = this.props.data.cloudInitEnabled && this.props.data.enableInitTimezone && isOsWindows(value, this.props.operatingSystems)
? this.props.data.lastInitTimezone // set the sysprep timezone as the last selected sysprep timezone
: ''
changes.tpmEnabled = isTpmRequired(value, this.props.operatingSystems) || undefined
changes.biosType = forceUefiBios({ operatingSystemId: value, operatingSystems, clusterId: data.clusterId, clusters })
break
}

Expand Down
9 changes: 9 additions & 0 deletions src/components/VmDetails/cards/DetailsCard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import {
userFormatOfBytes,
buildMessageFromRecord,
getTpmChange,
isUefiBios,
isTpmRequired,
UEFI_BIOS,
} from '_/helpers'
import { enumMsg, MsgContext, withMsg } from '_/intl'
import { isNumber, isNumberInRange } from '_/utils'
Expand Down Expand Up @@ -279,6 +282,7 @@ class DetailsCard extends React.Component {
operatingSystems,
clusters,
templates,
vm,
} = this.props

for (let change = changeQueue.shift(); change; change = changeQueue.shift()) {
Expand Down Expand Up @@ -389,6 +393,10 @@ class DetailsCard extends React.Component {
const tpmChange = getTpmChange(os.get('id'), operatingSystems)
updates = updates.set('tpmEnabled', tpmChange)
this.tpmUpdate = true
updates = updates.set(
'biosType',
isTpmRequired(value, operatingSystems) && !isUefiBios(vm.get('biosType')) ? UEFI_BIOS : undefined
)
const timeZoneName = updates.getIn(['timeZone', 'name'])
const isWindowsTimeZone = timezones.find(timezone => timezone.id === timeZoneName)
const isWindowsVm = isWindows(os.get('name'))
Expand Down Expand Up @@ -605,6 +613,7 @@ class DetailsCard extends React.Component {
if (tpmEnabled !== stateVm.get('tpmEnabled')) {
vmUpdates.tpmEnabled = stateVm.get('tpmEnabled')
}
vmUpdates.biosType = stateVm.get('biosType')
}

if (this.trackUpdates.memory) {
Expand Down
5 changes: 5 additions & 0 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,3 +339,8 @@ export const getTpmChange = (operatingSystemId, operatingSystems) => {
return undefined
}
}

export const UEFI_BIOS = 'q35_ovmf'
export const isUefiBios = (biosType) => biosType === UEFI_BIOS || biosType === 'q35_secure_boot'
export const forceUefiBios = ({ operatingSystemId, operatingSystems, clusters, clusterId }) =>
isTpmRequired(operatingSystemId, operatingSystems) && !isUefiBios(clusters?.getIn([clusterId, 'biosType'])) ? UEFI_BIOS : undefined
9 changes: 6 additions & 3 deletions src/ovirtapi/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ const VM = {
creationTime: convertEpoch(vm.creation_time),
startPaused: convertBool(vm.start_paused),
tpmEnabled: vm.tpm_enabled !== undefined ? convertBool(vm.tpm_enabled) : undefined,
biosType: vm?.bios?.type ?? undefined,

stateless: vm.stateless === 'true',

Expand Down Expand Up @@ -320,9 +321,10 @@ const VM = {
utc_offset: vm.timeZone.offset,
},

bios: 'bootMenuEnabled' in vm
? { boot_menu: { enabled: toApiBoolean(vm.bootMenuEnabled) } }
: undefined,
bios: {
boot_menu: 'bootMenuEnabled' in vm ? { enabled: toApiBoolean(vm.bootMenuEnabled) } : undefined,
type: vm.biosType ?? undefined,
},

// NOTE: Disable cloudInit by sending "initialization: {}"
initialization: vm.cloudInit && (
Expand Down Expand Up @@ -840,6 +842,7 @@ const Cluster = {

const c: Object = {
id: cluster.id,
biosType: cluster.bios_type,
name: cluster.name,
version: `${cluster.version.major}.${cluster.version.minor}`,
dataCenterId: cluster.data_center && cluster.data_center.id,
Expand Down
1 change: 1 addition & 0 deletions src/sagas/vmChanges.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ function* composeAndCreateVm ({ payload: { basic, nics, disks }, meta: { correla
utc_offset: basic.timeZone.offset,
},
tpm_enabled: basic.tpmEnabled,
bios: basic.biosType ? { type: basic.biosType } : undefined,

initialization: basic.cloudInitEnabled
? {
Expand Down

0 comments on commit 96a70c4

Please sign in to comment.