Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package org.zstack.compute.vm.devices;

import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.compute.vm.VmSystemTags;
import org.zstack.core.Platform;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.Q;
import org.zstack.header.image.ImageBootMode;
import org.zstack.header.tpm.entity.TpmVO;
import org.zstack.header.tpm.entity.TpmVO_;
import org.zstack.header.vm.additions.VmHostFileType;
import org.zstack.resourceconfig.ResourceConfig;
import org.zstack.resourceconfig.ResourceConfigFacade;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;

import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

import static org.zstack.compute.vm.VmGlobalConfig.ENABLE_UEFI_SECURE_BOOT;
import static org.zstack.header.vm.additions.VmHostFileType.NvRam;
import static org.zstack.header.vm.additions.VmHostFileType.TpmState;
import static org.zstack.utils.CollectionDSL.list;

public class VmTpmManager {
private static final CLogger logger = Utils.getLogger(VmTpmManager.class);
Expand Down Expand Up @@ -58,13 +66,27 @@ public static boolean isUefiBootMode(String bootMode) {
}

public boolean needRegisterNvRam(String vmUuid) {
boolean tpmExists = Q.New(TpmVO.class)
return needRegister(NvRam, vmUuid);
}

public Set<VmHostFileType> vmHostFileTypeNeedRegisterForVm(String vmUuid) {
String bootMode = VmSystemTags.BOOT_MODE.getTokenByResourceUuid(vmUuid, VmSystemTags.BOOT_MODE_TOKEN);
if (!isUefiBootMode(bootMode)) {
return Collections.emptySet();
}

boolean hasTpm = Q.New(TpmVO.class)
.eq(TpmVO_.vmInstanceUuid, vmUuid)
.isExists();
if (tpmExists) {
return true;
if (hasTpm) {
return new HashSet<>(list(NvRam, TpmState));
}
ResourceConfig resourceConfig = resourceConfigFacade.getResourceConfig(ENABLE_UEFI_SECURE_BOOT.getIdentity());
return resourceConfig.getResourceConfigValue(vmUuid, Boolean.class);
return resourceConfig.getResourceConfigValue(vmUuid, Boolean.class) == Boolean.TRUE ?
new HashSet<>(list(NvRam)) : Collections.emptySet();
}

public boolean needRegister(VmHostFileType type, String vmUuid) {
return vmHostFileTypeNeedRegisterForVm(vmUuid).contains(type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.compute.vm.VmGlobalConfig;
import org.zstack.compute.vm.VmSystemTags;
import org.zstack.compute.vm.devices.VmTpmManager;
import org.zstack.core.Platform;
import org.zstack.core.cloudbus.CloudBus;
Expand All @@ -23,8 +22,6 @@
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.message.MessageReply;
import org.zstack.header.tpm.entity.TpmVO;
import org.zstack.header.tpm.entity.TpmVO_;
import org.zstack.header.vm.DiskAO;
import org.zstack.header.vm.PreVmInstantiateResourceExtensionPoint;
import org.zstack.header.vm.VmInstanceVO;
Expand Down Expand Up @@ -79,14 +76,14 @@
import java.util.Map;
import java.util.Objects;

import static org.zstack.compute.vm.VmGlobalConfig.ENABLE_UEFI_SECURE_BOOT;
import static org.zstack.core.Platform.operr;
import static org.zstack.header.vm.additions.VmHostFileSyncReason.PostMigration;
import static org.zstack.header.vm.additions.VmHostFileSyncReason.BeforeHaStart;
import static org.zstack.header.vm.additions.VmHostFileSyncReason.PrepareReRead;
import static org.zstack.header.vm.additions.VmHostFileSyncReason.PrepareRead;
import static org.zstack.header.vm.additions.VmHostFileSyncReason.ResourceRelease;
import static org.zstack.header.vm.additions.VmHostFileSyncReason.SnapshotGroupOnlineBackup;
import static org.zstack.header.vm.additions.VmHostFileType.NvRam;
import static org.zstack.kvm.KVMConstant.*;
import static org.zstack.utils.CollectionDSL.list;

Expand All @@ -107,6 +104,8 @@ public class KvmSecureBootExtensions implements KVMStartVmExtensionPoint,
private ResourceConfigFacade resourceConfigFacade;
@Autowired
private DatabaseFacade databaseFacade;
@Autowired
private KvmVmHostFileFactory vmHostFileFactory;

private final Object hostFileLock = new Object();

Expand Down Expand Up @@ -141,15 +140,15 @@ private void prepareNvRamToStartVmCmd(KVMAgentCommands.StartVmCmd cmd, NvRamSpec
final Timestamp now = Timestamp.from(Instant.now());
VmHostFileVO nvRamFile = Q.New(VmHostFileVO.class)
.eq(VmHostFileVO_.vmInstanceUuid, cmd.getVmInstanceUuid())
.eq(VmHostFileVO_.type, VmHostFileType.NvRam)
.eq(VmHostFileVO_.type, NvRam)
.eq(VmHostFileVO_.hostUuid, host.getUuid())
.find();
if (nvRamFile == null) {
nvRamFile = new VmHostFileVO();
nvRamFile.setUuid(Platform.getUuid());
nvRamFile.setHostUuid(host.getUuid());
nvRamFile.setVmInstanceUuid(cmd.getVmInstanceUuid());
nvRamFile.setType(VmHostFileType.NvRam);
nvRamFile.setType(NvRam);
nvRamFile.setPath(volume.getInstallPath());
nvRamFile.setCreateDate(now);
nvRamFile.setResourceName("NvRam file for " + cmd.getVmInstanceUuid());
Expand Down Expand Up @@ -180,29 +179,17 @@ private void prepareNvRamBeforeMigration(VmInstanceInventory vm, String dstHostU
return;
}

String tpmUuid = Q.New(TpmVO.class)
.eq(TpmVO_.vmInstanceUuid, vm.getUuid())
.select(TpmVO_.uuid)
.findValue();
boolean needRegisterNvRam = tpmUuid != null;
boolean needRegisterNvRam = vmHostFileFactory.needRegister(NvRam, vm.getUuid());
if (!needRegisterNvRam) {
String bootMode = VmSystemTags.BOOT_MODE.getTokenByResourceUuid(vm.getUuid(), VmSystemTags.BOOT_MODE_TOKEN);
if (isUefiBootMode(bootMode)) {
ResourceConfig resourceConfig = resourceConfigFacade.getResourceConfig(ENABLE_UEFI_SECURE_BOOT.getIdentity());
needRegisterNvRam = resourceConfig.getResourceConfigValue(vm.getUuid(), Boolean.class) == Boolean.TRUE;
}

if (!needRegisterNvRam) {
completion.success();
return;
}
completion.success();
return;
}

SimpleFlowChain.of("prepare-nvram-before-vm-" + vm.getUuid() + "-migrate")
.then("prepare-nvram-folder-on-dest-host", trigger -> {
VmHostFileTO to = new VmHostFileTO();
to.setPath(buildNvramFilePath(vm.getUuid()));
to.setType(VmHostFileType.NvRam.toString());
to.setType(NvRam.toString());
to.setOperation(VmHostFileOperation.Prepare.toString());

RewriteVmHostFilesContext context = new RewriteVmHostFilesContext();
Expand Down Expand Up @@ -290,7 +277,7 @@ public void preInstantiateVmResource(VmInstanceSpec spec, Completion completion)
PrepareHostFileContext context = new PrepareHostFileContext();
context.hostUuid = spec.getDestHost().getUuid();
context.vmUuid = spec.getVmInventory().getUuid();
context.type = VmHostFileType.NvRam;
context.type = NvRam;
context.backupUuid = nvRamSpec.getBackupFileUuid();
context.syncReason = "pre-instantiate VM resource";
prepareHostFileOnHost(context, completion);
Expand Down Expand Up @@ -349,7 +336,7 @@ public void run(FlowTrigger trigger, Map data) {
syncMsg.setVmUuid(context.vmUuid);
syncMsg.setSyncReason(PrepareRead.reason(context.syncReason));

if (vmHostFile.getType() == VmHostFileType.NvRam) {
if (vmHostFile.getType() == NvRam) {
context.path = vmHostFile.getPath();
syncMsg.setNvRamPath(context.path);
} else if (vmHostFile.getType() == VmHostFileType.TpmState) {
Expand Down Expand Up @@ -471,7 +458,7 @@ public void run(FlowTrigger trigger, Map data) {
syncMsg.setVmUuid(context.vmUuid);
syncMsg.setSyncReason(PrepareReRead.reason(context.syncReason));

if (context.type == VmHostFileType.NvRam) {
if (context.type == NvRam) {
syncMsg.setNvRamPath(context.path);
} else if (context.type == VmHostFileType.TpmState) {
syncMsg.setTpmStateFolder(context.path);
Expand Down Expand Up @@ -574,7 +561,7 @@ public void releaseVmResource(VmInstanceSpec spec, Completion completion) {
syncMsg.setSyncReason(ResourceRelease.reason());

for (VmHostFileVO file : vmHostFiles) {
if (file.getType() == VmHostFileType.NvRam) {
if (file.getType() == NvRam) {
syncMsg.setNvRamPath(file.getPath());
} else if (file.getType() == VmHostFileType.TpmState) {
syncMsg.setTpmStateFolder(file.getPath());
Expand Down Expand Up @@ -633,7 +620,7 @@ public void beforeHaStartVmInstance(String vmUuid, String judgerClassName, List<
syncMsg.setSyncReason(BeforeHaStart.reason());

for (VmHostFileVO file : vmHostFiles) {
if (file.getType() == VmHostFileType.NvRam) {
if (file.getType() == NvRam) {
syncMsg.setNvRamPath(file.getPath());
} else if (file.getType() == VmHostFileType.TpmState) {
syncMsg.setTpmStateFolder(file.getPath());
Expand Down Expand Up @@ -699,7 +686,7 @@ public void afterMigrateVm(VmInstanceInventory inv, String srcHostUuid, NoErrorC
syncMsg.setSyncReason(PostMigration.reason());

for (VmHostFileVO file : vmHostFiles) {
if (file.getType() == VmHostFileType.NvRam) {
if (file.getType() == NvRam) {
syncMsg.setNvRamPath(file.getPath());
} else if (file.getType() == VmHostFileType.TpmState) {
syncMsg.setTpmStateFolder(file.getPath());
Expand Down Expand Up @@ -759,7 +746,7 @@ public void afterVolumeLiveSnapshotGroupCreatedOnBackend(CreateVolumesSnapshotOv
syncMsg.setHostUuid(hostUuid);

for (VmHostFileVO file : hostFiles) {
if (file.getType() == VmHostFileType.NvRam) {
if (file.getType() == NvRam) {
syncMsg.setNvRamPath(buildNvramSnapshotBackupFilePath(vmUuid));
} else if (file.getType() == VmHostFileType.TpmState) {
syncMsg.setTpmStateFolder(buildTpmStateSnapshotBackupFilePath(vmUuid));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.zstack.core.cloudbus.EventCallback;
import org.zstack.core.cloudbus.EventFacadeImpl;
import org.zstack.core.cloudbus.MessageSafe;
import org.zstack.core.cloudbus.ResourceDestinationMaker;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.Q;
import org.zstack.core.db.SQL;
Expand All @@ -27,8 +28,6 @@
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.message.Message;
import org.zstack.header.message.MessageReply;
import org.zstack.header.tpm.entity.TpmVO;
import org.zstack.header.tpm.entity.TpmVO_;
import org.zstack.header.vm.VmCanonicalEvents;
import org.zstack.header.vm.VmInstanceConstant;
import org.zstack.header.vm.VmInstanceVO;
Expand Down Expand Up @@ -76,7 +75,6 @@
import java.util.Set;
import java.util.function.Function;

import static org.zstack.compute.vm.VmGlobalConfig.ENABLE_UEFI_SECURE_BOOT;
import static org.zstack.compute.vm.VmGlobalConfig.RESET_TPM_AFTER_VM_CLONE;
import static org.zstack.core.Platform.operr;
import static org.zstack.header.vm.additions.VmHostFileSyncReason.PostClone;
Expand Down Expand Up @@ -104,6 +102,8 @@ public class KvmSecureBootManager extends AbstractService {
private KvmVmHostFileFactory vmHostFileFactory;
@Autowired
private TimeHelper timeHelper;
@Autowired
private ResourceDestinationMaker resourceDestinationMaker;

@Override
public boolean start() {
Expand All @@ -118,10 +118,27 @@ public boolean stop() {

@SuppressWarnings("rawtypes")
private void setupCanonicalEvents() {
eventFacade.on(VmCanonicalEvents.VM_LIBVIRT_REPORT_START, new EventCallback<Object>() {
@Override
protected void run(Map tokens, Object data) {
String vmUuid = (String) data;
boolean managedByMe = resourceDestinationMaker.isManagedByUs(vmUuid);
if (!managedByMe) {
return;
}
markVmHostFilesChanged(vmUuid);
}
});

eventFacade.on(VmCanonicalEvents.VM_LIBVIRT_REPORT_SHUTDOWN, new EventCallback<Object>() {
@Override
protected void run(Map tokens, Object data) {
String vmUuid = (String) data;
boolean managedByMe = resourceDestinationMaker.isManagedByUs(vmUuid);
if (!managedByMe) {
return;
}

Tuple tuple = Q.New(VmInstanceVO.class)
.select(VmInstanceVO_.hostUuid, VmInstanceVO_.lastHostUuid)
.eq(VmInstanceVO_.uuid, vmUuid)
Expand All @@ -134,6 +151,7 @@ protected void run(Map tokens, Object data) {
if (hostUuid == null) {
hostUuid = (String) tuple.get(1);
}
markVmHostFilesChanged(vmUuid, hostUuid);

List<VmHostFileVO> hostFiles = Q.New(VmHostFileVO.class)
.eq(VmHostFileVO_.vmInstanceUuid, vmUuid)
Expand Down Expand Up @@ -173,6 +191,55 @@ public void run(MessageReply reply) {
});
}

/**
* Preemptive judgment: when a VM with TPM (or enabled secure boot) starts or shuts down,
* the NvRam/TpmState data must have changed, so mark the corresponding
* VmHostFileVO.changeDate to current time.
*/
private void markVmHostFilesChanged(String vmUuid) {
Tuple tuple = Q.New(VmInstanceVO.class)
.select(VmInstanceVO_.hostUuid, VmInstanceVO_.lastHostUuid)
.eq(VmInstanceVO_.uuid, vmUuid)
.findTuple();
if (tuple == null) {
return;
}

String hostUuid = (String) tuple.get(0);
if (hostUuid == null) {
hostUuid = (String) tuple.get(1);
}
if (hostUuid == null) {
return;
}

markVmHostFilesChanged(vmUuid, hostUuid);
}

private void markVmHostFilesChanged(String vmUuid, String hostUuid) {
if (hostUuid == null) {
return;
}

final Set<VmHostFileType> types = vmHostFileFactory.vmHostFileTypeNeedRegisterForVm(vmUuid);
if (types.isEmpty()) {
return;
}

Timestamp now = new Timestamp(timeHelper.getCurrentTimeMillis());
long updated = SQL.New(VmHostFileVO.class)
.eq(VmHostFileVO_.vmInstanceUuid, vmUuid)
.eq(VmHostFileVO_.hostUuid, hostUuid)
.in(VmHostFileVO_.type, types)
.set(VmHostFileVO_.changeDate, now)
.update();

if (updated > 0) {
logger.debug(String.format("preemptively marked VmHostFiles as changed for VM[uuid:%s] on host[uuid:%s], %d records updated",
vmUuid, hostUuid, updated));
}
}

@Override
public String getId() {
return bus.makeLocalServiceId(VmInstanceConstant.SECURE_BOOT_SERVICE_ID);
Expand Down Expand Up @@ -473,22 +540,21 @@ protected void scripts() {
private void handle(CloneVmHostFileMsg msg) {
CloneVmHostFileReply reply = new CloneVmHostFileReply();

boolean hasTpm = Q.New(TpmVO.class)
.eq(TpmVO_.vmInstanceUuid, msg.getSrcVmUuid())
.isExists();
ResourceConfig resourceConfig = resourceConfigFacade.getResourceConfig(ENABLE_UEFI_SECURE_BOOT.getIdentity());
boolean secureBoot = resourceConfig.getResourceConfigValue(msg.getSrcVmUuid(), Boolean.class);
if (!hasTpm && !secureBoot) {
final Set<VmHostFileType> types = vmHostFileFactory.vmHostFileTypeNeedRegisterForVm(msg.getSrcVmUuid());
if (types.isEmpty()) {
bus.reply(msg, reply);
return;
}

CloneVmHostFileContext context = new CloneVmHostFileContext();
context.typesNeedClone.add(VmHostFileType.NvRam);
if (hasTpm) {
if (types.contains(VmHostFileType.NvRam)) {
context.typesNeedClone.add(VmHostFileType.NvRam);
}

if (types.contains(VmHostFileType.TpmState)) {
boolean resetTpm;
if (msg.getResetTpm() == null) {
resourceConfig = resourceConfigFacade.getResourceConfig(RESET_TPM_AFTER_VM_CLONE.getIdentity());
ResourceConfig resourceConfig = resourceConfigFacade.getResourceConfig(RESET_TPM_AFTER_VM_CLONE.getIdentity());
resetTpm = resourceConfig.getResourceConfigValue(msg.getSrcVmUuid(), Boolean.class);
} else {
resetTpm = msg.getResetTpm();
Expand Down
Loading