Skip to content

Commit efc4fc2

Browse files
author
Zhang Wenhao
committed
<refactor>[kvm]: improve TPM removal by cleaning host files before DB deletion
Refactor the removeTpmFromVm method to split the DB removal flow into three steps for better resource cleanup: 1. Collect VmHostFileVO and VmHostBackupFileVO for TPM state files 2. Send delete commands to hosts to clean up files on disk 3. Remove database records regardless of command success This ensures host files are cleaned up before DB records are deleted. Removed NvRam file deletion to avoid conflicts with secure boot. Related: ZSV-11310 Resolves: ZSV-11622 Change-Id: I7865626a687376746c746a706b74676b6b7a6a71
1 parent 2a5980b commit efc4fc2

1 file changed

Lines changed: 69 additions & 14 deletions

File tree

plugin/kvm/src/main/java/org/zstack/kvm/tpm/KvmTpmManager.java

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@
5353
import org.zstack.header.vm.additions.VmHostFileType;
5454
import org.zstack.header.vm.additions.VmHostFileVO;
5555
import org.zstack.header.vm.additions.VmHostFileVO_;
56+
import org.zstack.header.vm.additions.VmHostFileOperation;
57+
import org.zstack.header.core.ReturnValueCompletion;
58+
import org.zstack.kvm.KVMConstant;
59+
import org.zstack.kvm.KVMAgentCommands;
60+
import org.zstack.kvm.KvmCommandSender;
61+
import org.zstack.kvm.KvmResponseWrapper;
5662
import org.zstack.kvm.tpm.message.CloneVmTpmMsg;
5763
import org.zstack.kvm.tpm.message.CloneVmTpmReply;
5864
import org.zstack.resourceconfig.ResourceConfig;
@@ -62,10 +68,9 @@
6268
import org.zstack.utils.logging.CLogger;
6369

6470
import java.util.ArrayList;
65-
import java.util.HashSet;
71+
import java.util.HashMap;
6672
import java.util.List;
6773
import java.util.Map;
68-
import java.util.Set;
6974

7075
import static org.zstack.compute.vm.VmGlobalConfig.RESET_TPM_AFTER_VM_CLONE;
7176
import static org.zstack.core.Platform.err;
@@ -294,6 +299,7 @@ public String getName() {
294299
static class RemoveTpmFromVmContext {
295300
String vmInstanceUuid;
296301
String tpmUuid;
302+
List<VmHostFileVO> hostFiles;
297303

298304
static RemoveTpmFromVmContext valueOf(RemoveTpmMsg msg) {
299305
RemoveTpmFromVmContext context = new RemoveTpmFromVmContext();
@@ -320,36 +326,85 @@ private void removeTpmFromVm(RemoveTpmFromVmContext context, Completion completi
320326
trigger.next();
321327
})
322328
.build())
329+
.then(Flow.of("collect-vm-host-files")
330+
.handle(trigger -> {
331+
// DO NOT delete NvRam type VmHostFile: Maybe secure boot or other component related.
332+
context.hostFiles = Q.New(VmHostFileVO.class)
333+
.eq(VmHostFileVO_.vmInstanceUuid, context.vmInstanceUuid)
334+
.eq(VmHostFileVO_.type, VmHostFileType.TpmState)
335+
.list();
336+
trigger.next();
337+
})
338+
.build())
339+
.then(Flow.of("send-delete-commands-to-hosts")
340+
.skipIf(data -> context.hostFiles.isEmpty())
341+
.handle(trigger -> {
342+
Map<String, List<VmHostFileVO>> filesByHost = new HashMap<>();
343+
for (VmHostFileVO file : context.hostFiles) {
344+
filesByHost.computeIfAbsent(file.getHostUuid(), k -> new ArrayList<>()).add(file);
345+
}
346+
347+
new While<>(filesByHost.entrySet()).each((entry, whileCompletion) -> {
348+
String hostUuid = entry.getKey();
349+
List<VmHostFileVO> files = entry.getValue();
350+
351+
KVMAgentCommands.WriteVmHostFileContentCmd cmd = new KVMAgentCommands.WriteVmHostFileContentCmd();
352+
List<KVMAgentCommands.VmHostFileTO> fileTOs = new ArrayList<>();
353+
for (VmHostFileVO file : files) {
354+
KVMAgentCommands.VmHostFileTO to = new KVMAgentCommands.VmHostFileTO();
355+
to.setPath(file.getPath());
356+
to.setType(file.getType().toString());
357+
to.setOperation(VmHostFileOperation.Delete.toString());
358+
fileTOs.add(to);
359+
}
360+
cmd.setHostFiles(fileTOs);
361+
362+
new KvmCommandSender(hostUuid).send(cmd, KVMConstant.WRITE_VM_HOST_FILE_PATH, wrapper -> {
363+
KVMAgentCommands.WriteVmHostFileContentResponse rsp =
364+
wrapper.getResponse(KVMAgentCommands.WriteVmHostFileContentResponse.class);
365+
return rsp.isSuccess() ? null : operr("failed to delete host files on host[uuid=%s]", hostUuid);
366+
}, new ReturnValueCompletion<KvmResponseWrapper>(whileCompletion) {
367+
@Override
368+
public void success(KvmResponseWrapper wrapper) {
369+
whileCompletion.done();
370+
}
371+
372+
@Override
373+
public void fail(ErrorCode errorCode) {
374+
logger.warn(String.format("failed to delete host files on host[uuid=%s], but continuing with DB cleanup: %s",
375+
hostUuid, errorCode.getDetails()));
376+
whileCompletion.done();
377+
}
378+
});
379+
}).run(new WhileDoneCompletion(trigger) {
380+
@Override
381+
public void done(ErrorCodeList errorCodeList) {
382+
trigger.next();
383+
}
384+
});
385+
})
386+
.build())
323387
.then(Flow.of("detach-resource-key")
324388
.handle(trigger -> {
325389
tpmKeyBackend.detachKeyProviderFromTpm(context.tpmUuid);
326390
trigger.next();
327391
})
328392
.build())
329-
.then(Flow.of("remove-tpm-db-records")
393+
.then(Flow.of("remove-db-records")
330394
.handle(trigger -> {
331395
new SQLBatch() {
332396
@Override
333397
protected void scripts() {
334-
Set<VmHostFileType> types = new HashSet<>();
335-
types.add(VmHostFileType.TpmState);
336-
337398
sql(TpmVO.class)
338399
.eq(TpmVO_.uuid, context.tpmUuid)
339400
.delete();
340-
341-
boolean needRegisterNvRam = vmTpmManager.needRegisterNvRam(context.vmInstanceUuid);
342-
if (!needRegisterNvRam) {
343-
types.add(VmHostFileType.NvRam);
344-
}
345-
346401
sql(VmHostFileVO.class)
347402
.eq(VmHostFileVO_.vmInstanceUuid, context.vmInstanceUuid)
348-
.in(VmHostFileVO_.type, types)
403+
.eq(VmHostFileVO_.type, VmHostFileType.TpmState)
349404
.delete();
350405
sql(VmHostBackupFileVO.class)
351406
.eq(VmHostBackupFileVO_.resourceUuid, context.vmInstanceUuid)
352-
.in(VmHostBackupFileVO_.type, types)
407+
.eq(VmHostBackupFileVO_.type, VmHostFileType.TpmState)
353408
.delete();
354409
}
355410
}.execute();

0 commit comments

Comments
 (0)