feat(xo-web/VM/advanced): VTPM management (#7085)
See #7066 See #6802 See #7074
This commit is contained in:
parent
8752487280
commit
1a1dd0531d
@ -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))
|
- [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
|
- [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))
|
- [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
|
### Bug fixes
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ const messages = {
|
|||||||
esxiImportStopOnErrorDescription: 'Stop on the first error when importing VMs',
|
esxiImportStopOnErrorDescription: 'Stop on the first error when importing VMs',
|
||||||
nImportVmsInParallel: 'Number of VMs to import in parallel',
|
nImportVmsInParallel: 'Number of VMs to import in parallel',
|
||||||
stopOnError: 'Stop on error',
|
stopOnError: 'Stop on error',
|
||||||
|
uuid: 'UUID',
|
||||||
vmSrUsage: 'Storage: {used} used of {total} ({free} free)',
|
vmSrUsage: 'Storage: {used} used of {total} ({free} free)',
|
||||||
|
|
||||||
notDefined: 'Not defined',
|
notDefined: 'Not defined',
|
||||||
@ -1367,6 +1368,9 @@ const messages = {
|
|||||||
logAction: 'Action',
|
logAction: 'Action',
|
||||||
|
|
||||||
// ----- VM advanced tab -----
|
// ----- 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',
|
vmRemoveButton: 'Remove',
|
||||||
vmConvertToTemplateButton: 'Convert to template',
|
vmConvertToTemplateButton: 'Convert to template',
|
||||||
vmSwitchVirtualizationMode: 'Convert to {mode}',
|
vmSwitchVirtualizationMode: 'Convert to {mode}',
|
||||||
@ -1396,9 +1400,12 @@ const messages = {
|
|||||||
srHaTooltip: 'SR used for High Availability',
|
srHaTooltip: 'SR used for High Availability',
|
||||||
nestedVirt: 'Nested virtualization',
|
nestedVirt: 'Nested virtualization',
|
||||||
vmAffinityHost: 'Affinity host',
|
vmAffinityHost: 'Affinity host',
|
||||||
|
vmNeedToBeHalted: 'The VM needs to be halted',
|
||||||
vmVga: 'VGA',
|
vmVga: 'VGA',
|
||||||
vmVideoram: 'Video RAM',
|
vmVideoram: 'Video RAM',
|
||||||
vmNicType: 'NIC type',
|
vmNicType: 'NIC type',
|
||||||
|
vtpm: 'VTPM',
|
||||||
|
vtpmRequireUefi: 'A UEFI boot firmware is necessary to use a VTPM',
|
||||||
noAffinityHost: 'None',
|
noAffinityHost: 'None',
|
||||||
originalTemplate: 'Original template',
|
originalTemplate: 'Original template',
|
||||||
unknownOsName: 'Unknown',
|
unknownOsName: 'Unknown',
|
||||||
@ -1644,8 +1651,10 @@ const messages = {
|
|||||||
newVmNetworkConfigDoc: 'Network config documentation',
|
newVmNetworkConfigDoc: 'Network config documentation',
|
||||||
templateHasBiosStrings: 'The template already contains the BIOS strings',
|
templateHasBiosStrings: 'The template already contains the BIOS strings',
|
||||||
secureBootLinkToDocumentationMessage: 'Click for more information about Guest UEFI Secure Boot.',
|
secureBootLinkToDocumentationMessage: 'Click for more information about Guest UEFI Secure Boot.',
|
||||||
|
seeVtpmDocumentation: 'See VTPM documentation',
|
||||||
vmBootFirmwareIsUefi: 'The boot firmware is UEFI',
|
vmBootFirmwareIsUefi: 'The boot firmware is UEFI',
|
||||||
destroyCloudConfigVdiAfterBoot: 'Destroy cloud config drive after first boot',
|
destroyCloudConfigVdiAfterBoot: 'Destroy cloud config drive after first boot',
|
||||||
|
vtpmNotSupported: 'VTPM is only supported on pools running XCP-ng/XS 8.3 or later.',
|
||||||
|
|
||||||
// ----- Self -----
|
// ----- Self -----
|
||||||
resourceSets: 'Resource sets',
|
resourceSets: 'Resource sets',
|
||||||
|
@ -2155,6 +2155,11 @@ export const deleteAclRule = ({ protocol = undefined, port = undefined, ipRange
|
|||||||
vifId: resolveId(vif),
|
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 -----------------------------------------------------------
|
// Network -----------------------------------------------------------
|
||||||
|
|
||||||
export const editNetwork = (network, props) => _call('network.set', { ...props, id: resolveId(network) })
|
export const editNetwork = (network, props) => _call('network.set', { ...props, id: resolveId(network) })
|
||||||
|
@ -2,6 +2,7 @@ import _ from 'intl'
|
|||||||
import ActionButton from 'action-button'
|
import ActionButton from 'action-button'
|
||||||
import Component from 'base-component'
|
import Component from 'base-component'
|
||||||
import decorate from 'apply-decorators'
|
import decorate from 'apply-decorators'
|
||||||
|
import Copiable from 'copiable'
|
||||||
import defined, { get } from '@xen-orchestra/defined'
|
import defined, { get } from '@xen-orchestra/defined'
|
||||||
import getEventValue from 'get-event-value'
|
import getEventValue from 'get-event-value'
|
||||||
import Icon from 'icon'
|
import Icon from 'icon'
|
||||||
@ -28,8 +29,10 @@ import {
|
|||||||
cloneVm,
|
cloneVm,
|
||||||
convertVmToTemplate,
|
convertVmToTemplate,
|
||||||
createVgpu,
|
createVgpu,
|
||||||
|
createVtpm,
|
||||||
deleteVgpu,
|
deleteVgpu,
|
||||||
deleteVm,
|
deleteVm,
|
||||||
|
deleteVtpm,
|
||||||
editVm,
|
editVm,
|
||||||
getVmsHaValues,
|
getVmsHaValues,
|
||||||
isVmRunning,
|
isVmRunning,
|
||||||
@ -450,9 +453,48 @@ export default class TabAdvanced extends Component {
|
|||||||
|
|
||||||
_onNicTypeChange = value => editVm(this.props.vm, { nicType: value === '' ? null : value })
|
_onNicTypeChange = value => editVm(this.props.vm, { nicType: value === '' ? null : value })
|
||||||
|
|
||||||
|
_getDisabledAddVtpmReason = createSelector(
|
||||||
|
() => this.props.vm,
|
||||||
|
() => this.props.pool,
|
||||||
|
(vm, pool) => {
|
||||||
|
if (!pool.vtpmSupported) {
|
||||||
|
return _('vtpmNotSupported')
|
||||||
|
}
|
||||||
|
if (vm.boot.firmware !== 'uefi') {
|
||||||
|
return _('vtpmRequireUefi')
|
||||||
|
}
|
||||||
|
if (vm.power_state !== 'Halted') {
|
||||||
|
return _('vmNeedToBeHalted')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
_getDisabledDeleteVtpmReason = () => {
|
||||||
|
if (this.props.vm.power_state !== 'Halted') {
|
||||||
|
return _('vmNeedToBeHalted')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleDeleteVtpm = async vtpm => {
|
||||||
|
await confirm({
|
||||||
|
icon: 'delete',
|
||||||
|
title: _('deleteVtpm'),
|
||||||
|
body: <p>{_('deleteVtpmWarning')}</p>,
|
||||||
|
strongConfirm: {
|
||||||
|
messageId: 'deleteVtpm',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return deleteVtpm(vtpm)
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { container, isAdmin, vgpus, vm, vmPool } = this.props
|
const { container, isAdmin, vgpus, vm, vmPool } = this.props
|
||||||
const isWarmMigrationAvailable = getXoaPlan().value >= PREMIUM.value
|
const isWarmMigrationAvailable = getXoaPlan().value >= PREMIUM.value
|
||||||
|
const addVtpmTooltip = this._getDisabledAddVtpmReason()
|
||||||
|
const deleteVtpmTooltip = this._getDisabledDeleteVtpmReason()
|
||||||
|
const isAddVtpmAvailable = addVtpmTooltip === undefined
|
||||||
|
const isDeleteVtpmAvailable = deleteVtpmTooltip === undefined
|
||||||
|
const vtpmId = vm.VTPMs[0]
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Row>
|
<Row>
|
||||||
@ -798,6 +840,59 @@ export default class TabAdvanced extends Component {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</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={deleteVtpmTooltip}>
|
||||||
|
<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' && (
|
{vm.boot.firmware === 'uefi' && (
|
||||||
<tr>
|
<tr>
|
||||||
<th>{_('secureBoot')}</th>
|
<th>{_('secureBoot')}</th>
|
||||||
|
Loading…
Reference in New Issue
Block a user