This is an automated email from the ASF dual-hosted git repository.
bstoyanov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new 38e30a116c1 Add support for vTPM for XenServer and XCP-ng 8.3/8.4
(#12263)
38e30a116c1 is described below
commit 38e30a116c1c7b7011582e4b6c14f541e5be651b
Author: Pearl Dsilva <[email protected]>
AuthorDate: Wed Jan 28 06:12:32 2026 -0500
Add support for vTPM for XenServer and XCP-ng 8.3/8.4 (#12263)
* XenServer 8.4/XCP-ng 8.3: Support vTPM
* fix issue
* add log for windows 11 or other such guests OSs that require vtpm
* remove secure bootmode requirement
* Fix uefi setting on host for xenserver 8.4
---
.../xenserver/resource/CitrixResourceBase.java | 79 ++++++++++++++++++++++
.../wrapper/xenbase/CitrixReadyCommandWrapper.java | 10 ++-
.../wrapper/xenbase/CitrixStartCommandWrapper.java | 8 +++
scripts/vm/hypervisor/xenserver/xenserver84/vmops | 40 ++++++++++-
.../java/com/cloud/api/query/QueryManagerImpl.java | 4 ++
5 files changed, 139 insertions(+), 2 deletions(-)
diff --git
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
index 063a5a18ca2..cdb4d7434ae 100644
---
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
+++
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
@@ -51,6 +51,7 @@ import java.util.concurrent.TimeoutException;
import javax.naming.ConfigurationException;
import javax.xml.parsers.ParserConfigurationException;
+import com.xensource.xenapi.VTPM;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.diagnostics.CopyToSecondaryStorageAnswer;
import org.apache.cloudstack.diagnostics.CopyToSecondaryStorageCommand;
@@ -5826,4 +5827,82 @@ public abstract class CitrixResourceBase extends
ServerResourceBase implements S
public void destroyVm(VM vm, Connection connection) throws
XenAPIException, XmlRpcException {
destroyVm(vm, connection, false);
}
+
+ /**
+ * Configure vTPM (Virtual Trusted Platform Module) support for a VM.
+ * vTPM provides a virtual TPM 2.0 device for VMs, enabling features like
Secure Boot and disk encryption.
+ *
+ * Requirements:
+ * - XenServer/XCP-ng 8.3 (and above)
+ * - UEFI Secure Boot enabled
+ * - VM in halted state
+ *
+ * @param conn XenServer connection
+ * @param vm The VM to configure
+ * @param vmSpec VM specification containing vTPM settings
+ */
+ public void configureVTPM(Connection conn, VM vm, VirtualMachineTO vmSpec)
throws XenAPIException, XmlRpcException {
+ if (vmSpec == null || vmSpec.getDetails() == null) {
+ return;
+ }
+
+ String vtpmEnabled =
vmSpec.getDetails().getOrDefault(VmDetailConstants.VIRTUAL_TPM_ENABLED, null);
+
+ final Map<String, String> platform = vm.getPlatform(conn);
+ if (platform != null) {
+ final String guestRequiresVtpm = platform.get("vtpm");
+ if (guestRequiresVtpm != null &&
Boolean.parseBoolean(guestRequiresVtpm) && !Boolean.parseBoolean(vtpmEnabled)) {
+ logger.warn("Guest OS requires vTPM by default, even if VM
details doesn't have the setting: {}", vmSpec.getName());
+ return;
+ }
+ }
+
+ if (!Boolean.parseBoolean(vtpmEnabled)) {
+ return;
+ }
+
+ String bootMode =
StringUtils.defaultIfEmpty(vmSpec.getDetails().get(ApiConstants.BootType.UEFI.toString()),
null);
+ String bootType = (bootMode == null) ?
ApiConstants.BootType.BIOS.toString() : ApiConstants.BootType.UEFI.toString();
+
+ if (!ApiConstants.BootType.UEFI.toString().equals(bootType)) {
+ logger.warn("vTPM requires UEFI boot mode. Skipping vTPM
configuration for VM: {}", vmSpec.getName());
+ return;
+ }
+
+ try {
+ Set<VTPM> existingVtpms = vm.getVTPMs(conn);
+ if (!existingVtpms.isEmpty()) {
+ logger.debug("vTPM already exists for VM: {}",
vmSpec.getName());
+ return;
+ }
+
+ // Creates vTPM using: xe vtpm-create vm-uuid=<uuid>
+ String vmUuid = vm.getUuid(conn);
+ String result = callHostPlugin(conn, "vmops", "create_vtpm",
"vm_uuid", vmUuid);
+
+ if (result == null || result.isEmpty() ||
result.startsWith("ERROR:") || result.startsWith("EXCEPTION:")) {
+ throw new CloudRuntimeException("Failed to create vTPM,
result: " + result);
+ }
+
+ logger.info("Successfully created vTPM {} for VM: {}",
result.trim(), vmSpec.getName());
+ } catch (Exception e) {
+ logger.warn("Failed to configure vTPM for VM: {}, continuing
without vTPM", vmSpec.getName(), e);
+ }
+ }
+
+ public boolean isVTPMSupported(Connection conn, Host host) {
+ try {
+ Host.Record hostRecord = host.getRecord(conn);
+ String productVersion =
hostRecord.softwareVersion.get("product_version");
+ if (productVersion == null) {
+ return false;
+ }
+ ComparableVersion currentVersion = new
ComparableVersion(productVersion);
+ ComparableVersion minVersion = new ComparableVersion("8.2.0");
+ return currentVersion.compareTo(minVersion) >= 0;
+ } catch (Exception e) {
+ logger.warn("Failed to check vTPM support on host", e);
+ return false;
+ }
+ }
}
diff --git
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixReadyCommandWrapper.java
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixReadyCommandWrapper.java
index c5605e85f94..4f55ae82337 100644
---
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixReadyCommandWrapper.java
+++
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixReadyCommandWrapper.java
@@ -60,12 +60,20 @@ public final class CitrixReadyCommandWrapper extends
CommandWrapper<ReadyCommand
final Set<VM> vms = host.getResidentVMs(conn);
citrixResourceBase.destroyPatchVbd(conn, vms);
+ } catch (final Exception e) {
+ logger.warn("Unable to destroy CD-ROM device for system VMs", e);
+ }
+
+ try {
+ final Host host = Host.getByUuid(conn,
citrixResourceBase.getHost().getUuid());
final Host.Record hr = host.getRecord(conn);
if (isUefiSupported(CitrixHelper.getProductVersion(hr))) {
hostDetails.put(com.cloud.host.Host.HOST_UEFI_ENABLE,
Boolean.TRUE.toString());
}
- } catch (final Exception e) {
+ } catch (Exception e) {
+ logger.warn("Unable to get UEFI support info", e);
}
+
try {
final boolean result = citrixResourceBase.cleanupHaltedVms(conn);
if (!result) {
diff --git
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java
index d448638f028..5c2355a4cec 100644
---
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java
+++
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java
@@ -97,6 +97,14 @@ public final class CitrixStartCommandWrapper extends
CommandWrapper<StartCommand
citrixResourceBase.createVGPU(conn, command, vm, gpuDevice);
}
+ try {
+ if (citrixResourceBase.isVTPMSupported(conn, host)) {
+ citrixResourceBase.configureVTPM(conn, vm, vmSpec);
+ }
+ } catch (Exception e) {
+ logger.warn("Failed to configure vTPM for VM " + vmName + ",
continuing without vTPM", e);
+ }
+
Host.Record record = host.getRecord(conn);
String xenBrand = record.softwareVersion.get("product_brand");
String xenVersion = record.softwareVersion.get("product_version");
diff --git a/scripts/vm/hypervisor/xenserver/xenserver84/vmops
b/scripts/vm/hypervisor/xenserver/xenserver84/vmops
index cf6e6325d68..76d4571ef18 100755
--- a/scripts/vm/hypervisor/xenserver/xenserver84/vmops
+++ b/scripts/vm/hypervisor/xenserver/xenserver84/vmops
@@ -1587,6 +1587,43 @@ def network_rules(session, args):
except:
logging.exception("Failed to network rule!")
+@echo
+def create_vtpm(session, args):
+ util.SMlog("create_vtpm called with args: %s" % str(args))
+
+ try:
+ vm_uuid = args.get('vm_uuid')
+ if not vm_uuid:
+ return "ERROR: vm_uuid parameter is required"
+
+ # Check if vTPM already exists for this VM
+ cmd = ['xe', 'vtpm-list', 'vm-uuid=' + vm_uuid, '--minimal']
+ result = util.pread2(cmd)
+ existing_vtpms = result.strip()
+
+ if existing_vtpms:
+ util.SMlog("vTPM already exists for VM %s: %s" % (vm_uuid,
existing_vtpms))
+ return existing_vtpms.split(',')[0]
+
+ cmd = ['xe', 'vtpm-create', 'vm-uuid=' + vm_uuid]
+ result = util.pread2(cmd)
+ vtpm_uuid = result.strip()
+
+ if vtpm_uuid:
+ util.SMlog("Successfully created vTPM %s for VM %s" % (vtpm_uuid,
vm_uuid))
+ return vtpm_uuid
+ else:
+ return "ERROR: Failed to create vTPM, empty result"
+
+ except CommandException as e:
+ error_msg = "xe command failed: %s" % str(e)
+ util.SMlog("ERROR: %s" % error_msg)
+ return "ERROR: " + error_msg
+ except Exception as e:
+ error_msg = str(e)
+ util.SMlog("ERROR: %s" % error_msg)
+ return "ERROR: " + error_msg
+
if __name__ == "__main__":
XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi,
"preparemigration": preparemigration,
@@ -1604,4 +1641,5 @@ if __name__ == "__main__":
"createFileInDomr":createFileInDomr,
"kill_copy_process":kill_copy_process,
"secureCopyToHost":secureCopyToHost,
- "runPatchScriptInDomr": runPatchScriptInDomr})
+ "runPatchScriptInDomr": runPatchScriptInDomr,
+ "create_vtpm": create_vtpm})
diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
index 1361dbcdab0..6713a7dc07e 100644
--- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
@@ -5440,6 +5440,10 @@ public class QueryManagerImpl extends
MutualExclusiveIdsManagerBase implements Q
options.put(VmDetailConstants.RAM_RESERVATION,
Collections.emptyList());
options.put(VmDetailConstants.VIRTUAL_TPM_ENABLED,
Arrays.asList("true", "false"));
}
+
+ if (HypervisorType.XenServer.equals(hypervisorType)) {
+ options.put(VmDetailConstants.VIRTUAL_TPM_ENABLED,
Arrays.asList("true", "false"));
+ }
}
@Override