Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(xo-web/VM/advanced): VTPM management #7085

Merged
merged 5 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [Host/Advanced] Allow to force _Smart reboot_ if some resident VMs have the suspend operation blocked [Forum#7136](https://xcp-ng.org/forum/topic/7136/suspending-vms-during-host-reboot/23) (PR [#7025](https://github.com/vatesfr/xen-orchestra/pull/7025))
- [Plugin/backup-report] Errors are now listed in XO tasks
- [PIF] Show network name in PIF selectors (PR [#7081](https://github.com/vatesfr/xen-orchestra/pull/7081))
- [VM/Advanced] Possibility to create/delete VTPM [#7066](https://github.com/vatesfr/xen-orchestra/issues/7066) [Forum#6578](https://xcp-ng.org/forum/topic/6578/xcp-ng-8-3-public-alpha/109) (PR [#7085](https://github.com/vatesfr/xen-orchestra/pull/7085))

### Bug fixes

Expand Down
9 changes: 9 additions & 0 deletions packages/xo-web/src/common/intl/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const messages = {
esxiImportStopOnErrorDescription: 'Stop on the first error when importing VMs',
nImportVmsInParallel: 'Number of VMs to import in parallel',
stopOnError: 'Stop on error',
uuid: 'UUID',
vmSrUsage: 'Storage: {used} used of {total} ({free} free)',

notDefined: 'Not defined',
Expand Down Expand Up @@ -1367,6 +1368,9 @@ const messages = {
logAction: 'Action',

// ----- VM advanced tab -----
createVtpm: 'Create a VTPM',
deleteVtpm: 'Delete the VTPM',
deleteVtpmWarning: 'If the VTPM is in use, removing it will result in a dangerous data loss. Are you sure you want to remove the VTPM?',
vmRemoveButton: 'Remove',
vmConvertToTemplateButton: 'Convert to template',
vmSwitchVirtualizationMode: 'Convert to {mode}',
Expand Down Expand Up @@ -1396,9 +1400,12 @@ const messages = {
srHaTooltip: 'SR used for High Availability',
nestedVirt: 'Nested virtualization',
vmAffinityHost: 'Affinity host',
vmNeedToBeHalted: 'The VM need to be halted',
MathieuRA marked this conversation as resolved.
Show resolved Hide resolved
vmVga: 'VGA',
vmVideoram: 'Video RAM',
vmNicType: 'NIC type',
vtpm: 'VTPM',
vtpmRequireUefi: 'A UEFI boot firmware is necessary to use a VTPM',
noAffinityHost: 'None',
originalTemplate: 'Original template',
unknownOsName: 'Unknown',
Expand Down Expand Up @@ -1644,8 +1651,10 @@ const messages = {
newVmNetworkConfigDoc: 'Network config documentation',
templateHasBiosStrings: 'The template already contains the BIOS strings',
secureBootLinkToDocumentationMessage: 'Click for more information about Guest UEFI Secure Boot.',
seeVtpmDocumentation: 'See VTPM documentation',
vmBootFirmwareIsUefi: 'The boot firmware is UEFI',
destroyCloudConfigVdiAfterBoot: 'Destroy cloud config drive after first boot',
vtpmNotSupported: 'VTPM is only supported on pools running XCP-ng/XS 8.3 or later.',

// ----- Self -----
resourceSets: 'Resource sets',
Expand Down
5 changes: 5 additions & 0 deletions packages/xo-web/src/common/xo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2149,6 +2149,11 @@ export const deleteAclRule = ({ protocol = undefined, port = undefined, ipRange
vifId: resolveId(vif),
})

// VTPM -----------------------------------------------------------

export const createVtpm = vm => _call('vtpm.create', { id: resolveId(vm) })
export const deleteVtpm = vtpm => _call('vtpm.destroy', { id: resolveId(vtpm) })

// Network -----------------------------------------------------------

export const editNetwork = (network, props) => _call('network.set', { ...props, id: resolveId(network) })
Expand Down
91 changes: 91 additions & 0 deletions packages/xo-web/src/xo-app/vm/tab-advanced.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import _ from 'intl'
import ActionButton from 'action-button'
import Component from 'base-component'
import decorate from 'apply-decorators'
import Copiable from 'copiable'
import defined, { get } from '@xen-orchestra/defined'
import getEventValue from 'get-event-value'
import Icon from 'icon'
Expand All @@ -28,8 +29,10 @@ import {
cloneVm,
convertVmToTemplate,
createVgpu,
createVtpm,
deleteVgpu,
deleteVm,
deleteVtpm,
editVm,
getVmsHaValues,
isVmRunning,
Expand Down Expand Up @@ -450,9 +453,44 @@ export default class TabAdvanced extends Component {

_onNicTypeChange = value => editVm(this.props.vm, { nicType: value === '' ? null : value })

_isAddVtpmAvailable = createSelector(
() => this.props.vm,
() => this.props.pool,
(vm, pool) => pool.vtpmSupported && vm.boot.firmware === 'uefi' && vm.power_state === 'Halted'
)

_getAddVtpmTooltip = createSelector(
() => this.props.vm,
() => this.props.pool,
(vm, pool) =>
!pool.vtpmSupported
? _('vtpmNotSupported')
: vm.boot.firmware !== 'uefi'
? _('vtpmRequireUefi')
: vm.power_state !== 'Halted'
? _('vmNeedToBeHalted')
: undefined
)
pdonias marked this conversation as resolved.
Show resolved Hide resolved

_handleDeleteVtpm = async vtpm => {
await confirm({
icon: 'delete',
title: _('deleteVtpm'),
body: <p>{_('deleteVtpmWarning')}</p>,
strongConfirm: {
messageId: 'deleteVtpm',
},
})
return deleteVtpm(vtpm)
}

render() {
const { container, isAdmin, vgpus, vm, vmPool } = this.props
const isWarmMigrationAvailable = getXoaPlan().value >= PREMIUM.value
const isAddVtpmAvailable = this._isAddVtpmAvailable()
const isDeleteVtpmAvailable = vm.power_state === 'Halted'
const addVtpmTooltip = this._getAddVtpmTooltip()
const vtpmId = vm.VTPMs[0]
return (
<Container>
<Row>
Expand Down Expand Up @@ -798,6 +836,59 @@ export default class TabAdvanced extends Component {
</td>
</tr>
)}
<tr>
<th>{_('vtpm')}</th>
<td>
{/*
FIXME: add documentation link
<a
className='text-muted'
href='#'
rel='noopener noreferrer'
style={{ display: 'block' }}
target='_blank'
>
<Icon icon='info' /> {_('seeVtpmDocumentation')}
</a> */}
{vtpmId === undefined ? (
<Tooltip content={addVtpmTooltip}>
<ActionButton
btnStyle='primary'
disabled={!isAddVtpmAvailable}
handler={createVtpm}
handlerParam={vm}
icon='add'
>
{_('createVtpm')}
</ActionButton>
</Tooltip>
) : (
<div>
<Tooltip content={!isDeleteVtpmAvailable ? _('vmNeedToBeHalted') : undefined}>
<ActionButton
btnStyle='danger'
disabled={!isDeleteVtpmAvailable}
handler={this._handleDeleteVtpm}
handlerParam={vtpmId}
icon='delete'
>
{_('deleteVtpm')}
</ActionButton>
</Tooltip>
<table className='table mt-1'>
<tbody>
<tr>
<th>{_('uuid')}</th>
<Copiable tagName='td' data={vtpmId}>
{vtpmId.slice(0, 4)}
</Copiable>
</tr>
</tbody>
</table>
</div>
)}
</td>
</tr>
{vm.boot.firmware === 'uefi' && (
<tr>
<th>{_('secureBoot')}</th>
Expand Down