diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 0b01074215f..3dd22b40154 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -11,6 +11,7 @@ - [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)) +- [VM/New] Possibility to create and attach a _VTPM_ to a VM [#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 [#7077](https://github.com/vatesfr/xen-orchestra/pull/7077)) ### Bug fixes diff --git a/packages/xo-server/src/api/vm.mjs b/packages/xo-server/src/api/vm.mjs index 4425b1fe277..e49076e892e 100644 --- a/packages/xo-server/src/api/vm.mjs +++ b/packages/xo-server/src/api/vm.mjs @@ -238,6 +238,11 @@ export const create = defer(async function ($defer, params) { await this.allocIpAddresses(vif.$id, concat(vif.ipv4_allowed, vif.ipv6_allowed)).catch(() => xapi.deleteVif(vif)) } + if (params.createVtpm) { + const vtpmRef = await xapi.VTPM_create({ VM: xapiVm.$ref }) + $defer.onFailure(() => xapi.call('VTPM.destroy', vtpmRef)) + } + if (params.bootAfterCreate) { startVmAndDestroyCloudConfigVdi(xapi, xapiVm, cloudConfigVdiUuid, params) } @@ -258,6 +263,11 @@ create.params = { optional: true, }, + createVtpm: { + type: 'boolean', + default: false, + }, + networkConfig: { type: 'string', optional: true, diff --git a/packages/xo-web/src/common/intl/messages.js b/packages/xo-web/src/common/intl/messages.js index 2ec18f526d1..dedcc456b6e 100644 --- a/packages/xo-web/src/common/intl/messages.js +++ b/packages/xo-web/src/common/intl/messages.js @@ -1582,6 +1582,7 @@ const messages = { createVmModalWarningMessage: "You're about to use a large amount of resources available on the resource set. Are you sure you want to continue?", copyHostBiosStrings: 'Copy host BIOS strings to VM', + enableVtpm: 'Enable VTPM', newVmCreateNewVmOn: 'Create a new VM on {select}', newVmCreateNewVmNoPermission: 'You have no permission to create a VM', newVmInfoPanel: 'Info', @@ -1655,6 +1656,7 @@ const messages = { 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.', + warningVtpmRequired: 'This template requires a VTPM, if you proceed, the VM will likely not be able to boot.', // ----- Self ----- resourceSets: 'Resource sets', diff --git a/packages/xo-web/src/index.scss b/packages/xo-web/src/index.scss index e42fcd720c7..0bd6898aef4 100644 --- a/packages/xo-web/src/index.scss +++ b/packages/xo-web/src/index.scss @@ -100,6 +100,14 @@ $select-input-height: 40px; // Bootstrap input height color: #333; } +.d-inline-flex { + display: inline-flex; +} + +.align-self-center { + align-self: center; +} + // COLORS ====================================================================== .xo-status-running { diff --git a/packages/xo-web/src/xo-app/new-vm/index.js b/packages/xo-web/src/xo-app/new-vm/index.js index b0db70a2bf7..06f9bedea88 100644 --- a/packages/xo-web/src/xo-app/new-vm/index.js +++ b/packages/xo-web/src/xo-app/new-vm/index.js @@ -346,6 +346,7 @@ export default class NewVm extends BaseComponent { seqStart: 1, share: this._getResourceSet()?.shareByDefault ?? false, tags: [], + createVtpm: this._templateNeedsVtpm(), }, callback ) @@ -493,6 +494,7 @@ export default class NewVm extends BaseComponent { bootAfterCreate: state.bootAfterCreate, copyHostBiosStrings: state.hvmBootFirmware !== 'uefi' && !this._templateHasBiosStrings() && state.copyHostBiosStrings, + createVtpm: state.createVtpm, destroyCloudConfigVdiAfterBoot: state.destroyCloudConfigVdiAfterBoot, secureBoot: state.secureBoot, share: state.share, @@ -599,6 +601,7 @@ export default class NewVm extends BaseComponent { }), // settings secureBoot: template.secureBoot, + createVtpm: this._templateNeedsVtpm(), }) if (this._isCoreOs()) { @@ -748,6 +751,8 @@ export default class NewVm extends BaseComponent { template => template && template.virtualizationMode === 'hvm' ) + _templateNeedsVtpm = () => this.props.template?.platform?.vtpm === 'true' + // On change ------------------------------------------------------------------- _onChangeSshKeys = keys => this._setState({ sshKeys: map(keys, key => key.id) }) @@ -881,7 +886,12 @@ export default class NewVm extends BaseComponent { _getRedirectionUrl = id => (this.state.state.multipleVms ? '/home' : `/vms/${id}`) - _handleBootFirmware = value => this._setState({ hvmBootFirmware: value, secureBoot: false }) + _handleBootFirmware = value => + this._setState({ + hvmBootFirmware: value, + secureBoot: false, + createVtpm: value === 'uefi' ? this._templateNeedsVtpm() : false, + }) // MAIN ------------------------------------------------------------------------ @@ -1531,6 +1541,7 @@ export default class NewVm extends BaseComponent { cpuCap, cpusMax, cpuWeight, + createVtpm, destroyCloudConfigVdiAfterBoot, hvmBootFirmware, installMethod, @@ -1565,6 +1576,8 @@ export default class NewVm extends BaseComponent { ) : null + const isVtpmSupported = pool.vtpmSupported + return (
@@ -1769,6 +1782,23 @@ export default class NewVm extends BaseComponent { + + + + + {/* FIXME: link to VTPM documentation when ready */} + {/*   + + + + + */} + {!createVtpm && this._templateNeedsVtpm() && ( + + {_('warningVtpmRequired')} + + )} + ), isAdmin && isHvm && (