Skip to content

Commit 8b1fc3a

Browse files
committed
XenServer 8.4/XCP-ng 8.3: Support vTPM
1 parent cfe9602 commit 8b1fc3a

File tree

4 files changed

+126
-1
lines changed

4 files changed

+126
-1
lines changed

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import javax.naming.ConfigurationException;
5252
import javax.xml.parsers.ParserConfigurationException;
5353

54+
import com.xensource.xenapi.VTPM;
5455
import org.apache.cloudstack.api.ApiConstants;
5556
import org.apache.cloudstack.diagnostics.CopyToSecondaryStorageAnswer;
5657
import org.apache.cloudstack.diagnostics.CopyToSecondaryStorageCommand;
@@ -5826,4 +5827,78 @@ public void destroyVm(VM vm, Connection connection, boolean forced) throws XenAP
58265827
public void destroyVm(VM vm, Connection connection) throws XenAPIException, XmlRpcException {
58275828
destroyVm(vm, connection, false);
58285829
}
5830+
5831+
/**
5832+
* Configure vTPM (Virtual Trusted Platform Module) support for a VM.
5833+
* vTPM provides a virtual TPM 2.0 device for VMs, enabling features like Secure Boot and disk encryption.
5834+
*
5835+
* Requirements:
5836+
* - XenServer/XCP-ng 8.3 (and above)
5837+
* - UEFI Secure Boot enabled
5838+
* - VM in halted state
5839+
*
5840+
* @param conn XenServer connection
5841+
* @param vm The VM to configure
5842+
* @param vmSpec VM specification containing vTPM settings
5843+
*/
5844+
public void configureVTPM(Connection conn, VM vm, VirtualMachineTO vmSpec) throws XenAPIException, XmlRpcException {
5845+
if (vmSpec == null || vmSpec.getDetails() == null) {
5846+
return;
5847+
}
5848+
5849+
String vtpmEnabled = vmSpec.getDetails().getOrDefault(VmDetailConstants.VIRTUAL_TPM_ENABLED, null);
5850+
if (!Boolean.parseBoolean(vtpmEnabled)) {
5851+
return;
5852+
}
5853+
5854+
String bootMode = StringUtils.defaultIfEmpty(vmSpec.getDetails().get(ApiConstants.BootType.UEFI.toString()), null);
5855+
String bootType = (bootMode == null) ? ApiConstants.BootType.BIOS.toString() : ApiConstants.BootType.UEFI.toString();
5856+
5857+
if (!ApiConstants.BootType.UEFI.toString().equals(bootType)) {
5858+
logger.warn("vTPM requires UEFI boot mode. Skipping vTPM configuration for VM: {}", vmSpec.getName());
5859+
return;
5860+
}
5861+
5862+
if (!ApiConstants.BootMode.SECURE.name().equals(bootMode)) {
5863+
logger.warn("PEARL - bootMode=" + bootMode);
5864+
logger.warn("vTPM requires UEFI Secure Boot to be enabled. Skipping vTPM configuration for VM: {}", vmSpec.getName());
5865+
return;
5866+
}
5867+
5868+
try {
5869+
Set<VTPM> existingVtpms = vm.getVTPMs(conn);
5870+
if (!existingVtpms.isEmpty()) {
5871+
logger.debug("vTPM already exists for VM: {}", vmSpec.getName());
5872+
return;
5873+
}
5874+
5875+
// Creates vTPM using: xe vtpm-create vm-uuid=<uuid>
5876+
String vmUuid = vm.getUuid(conn);
5877+
String result = callHostPlugin(conn, "vmops", "create_vtpm", "vm_uuid", vmUuid);
5878+
5879+
if (result == null || result.isEmpty() || result.startsWith("ERROR:") || result.startsWith("EXCEPTION:")) {
5880+
throw new CloudRuntimeException("Failed to create vTPM, result: " + result);
5881+
}
5882+
5883+
logger.info("Successfully created vTPM {} for VM: {}", result.trim(), vmSpec.getName());
5884+
} catch (Exception e) {
5885+
logger.warn("Failed to configure vTPM for VM: {}, continuing without vTPM", vmSpec.getName(), e);
5886+
}
5887+
}
5888+
5889+
public boolean isVTPMSupported(Connection conn, Host host) {
5890+
try {
5891+
Host.Record hostRecord = host.getRecord(conn);
5892+
String productVersion = hostRecord.softwareVersion.get("product_version");
5893+
if (productVersion == null) {
5894+
return false;
5895+
}
5896+
ComparableVersion currentVersion = new ComparableVersion(productVersion);
5897+
ComparableVersion minVersion = new ComparableVersion("8.2.0");
5898+
return currentVersion.compareTo(minVersion) >= 0;
5899+
} catch (Exception e) {
5900+
logger.warn("Failed to check vTPM support on host", e);
5901+
return false;
5902+
}
5903+
}
58295904
}

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ public Answer execute(final StartCommand command, final CitrixResourceBase citri
9797
citrixResourceBase.createVGPU(conn, command, vm, gpuDevice);
9898
}
9999

100+
try {
101+
if (citrixResourceBase.isVTPMSupported(conn, host)) {
102+
citrixResourceBase.configureVTPM(conn, vm, vmSpec);
103+
}
104+
} catch (Exception e) {
105+
logger.warn("Failed to configure vTPM for VM " + vmName + ", continuing without vTPM", e);
106+
}
107+
100108
Host.Record record = host.getRecord(conn);
101109
String xenBrand = record.softwareVersion.get("product_brand");
102110
String xenVersion = record.softwareVersion.get("product_version");

scripts/vm/hypervisor/xenserver/xenserver84/vmops

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1587,6 +1587,43 @@ def network_rules(session, args):
15871587
except:
15881588
logging.exception("Failed to network rule!")
15891589

1590+
@echo
1591+
def create_vtpm(session, args):
1592+
util.SMlog("create_vtpm called with args: %s" % str(args))
1593+
1594+
try:
1595+
vm_uuid = args.get('vm_uuid')
1596+
if not vm_uuid:
1597+
return "ERROR: vm_uuid parameter is required"
1598+
1599+
# Check if vTPM already exists for this VM
1600+
cmd = ['xe', 'vtpm-list', 'vm-uuid=' + vm_uuid, '--minimal']
1601+
result = util.pread2(cmd)
1602+
existing_vtpms = result.strip()
1603+
1604+
if existing_vtpms:
1605+
util.SMlog("vTPM already exists for VM %s: %s" % (vm_uuid, existing_vtpms))
1606+
return existing_vtpms.split(',')[0] # Return first vTPM UUID
1607+
1608+
cmd = ['xe', 'vtpm-create', 'vm-uuid=' + vm_uuid]
1609+
result = util.pread2(cmd)
1610+
vtpm_uuid = result.strip()
1611+
1612+
if vtpm_uuid:
1613+
util.SMlog("Successfully created vTPM %s for VM %s" % (vtpm_uuid, vm_uuid))
1614+
return vtpm_uuid
1615+
else:
1616+
return "ERROR: Failed to create vTPM, empty result"
1617+
1618+
except CommandException as e:
1619+
error_msg = "xe command failed: %s" % str(e)
1620+
util.SMlog("ERROR: %s" % error_msg)
1621+
return "ERROR: " + error_msg
1622+
except Exception as e:
1623+
error_msg = str(e)
1624+
util.SMlog("ERROR: %s" % error_msg)
1625+
return "ERROR: " + error_msg
1626+
15901627
if __name__ == "__main__":
15911628
XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi,
15921629
"preparemigration": preparemigration,
@@ -1604,4 +1641,5 @@ if __name__ == "__main__":
16041641
"createFileInDomr":createFileInDomr,
16051642
"kill_copy_process":kill_copy_process,
16061643
"secureCopyToHost":secureCopyToHost,
1607-
"runPatchScriptInDomr": runPatchScriptInDomr})
1644+
"runPatchScriptInDomr": runPatchScriptInDomr,
1645+
"create_vtpm": create_vtpm})

server/src/main/java/com/cloud/api/query/QueryManagerImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5400,6 +5400,10 @@ private void fillVMOrTemplateDetailOptions(final Map<String, List<String>> optio
54005400
options.put(VmDetailConstants.RAM_RESERVATION, Collections.emptyList());
54015401
options.put(VmDetailConstants.VIRTUAL_TPM_ENABLED, Arrays.asList("true", "false"));
54025402
}
5403+
5404+
if (HypervisorType.XenServer.equals(hypervisorType)) {
5405+
options.put(VmDetailConstants.VIRTUAL_TPM_ENABLED, Arrays.asList("true", "false"));
5406+
}
54035407
}
54045408

54055409
@Override

0 commit comments

Comments
 (0)