Skip to content

Commit fc22117

Browse files
author
Zhang Wenhao
committed
<feature>[kvm]: add online snapshot support for VM host files
* Add VmHostFileBackupJob class to define VM host file backup tasks. * Add vmHostFileBackupJobs field to TakeVolumesSnapshotOnKvmMsg and hostBackupTempResourceUuid to TakeVolumesSnapshotOnKvmReply for tracking backup files during online snapshots. * Add snapshot backup path building methods in KVMConstant Implement VolumeSnapshotCreationExtensionPoint in KvmSecureBootExtensions to backup VM host files after online snapshot * Refactor sync logic in KvmSecureBootManager to support syncin to backup files * Add syncToBackup and backupResourceUuid fields to SyncVmHostFilesFromHostMsg. Related: ZSV-11310 Resolves: ZSV-11441 Change-Id: I6e6f7062697867706b616b6c7567707771676179
1 parent 9729c52 commit fc22117

7 files changed

Lines changed: 385 additions & 79 deletions

File tree

header/src/main/java/org/zstack/header/storage/snapshot/TakeVolumesSnapshotOnKvmMsg.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.zstack.header.host.HostMessage;
44
import org.zstack.header.message.NeedReplyMessage;
5+
import org.zstack.header.vm.additions.VmHostFileBackupJob;
56

67
import java.util.List;
78

@@ -11,6 +12,7 @@
1112
public class TakeVolumesSnapshotOnKvmMsg extends NeedReplyMessage implements HostMessage {
1213
private List<TakeSnapshotsOnKvmJobStruct> snapshotJobs;
1314
private String hostUuid;
15+
private List<VmHostFileBackupJob> vmHostFileBackupJobs;
1416

1517
@Override
1618
public String getHostUuid() {
@@ -28,4 +30,13 @@ public List<TakeSnapshotsOnKvmJobStruct> getSnapshotJobs() {
2830
public void setSnapshotJobs(List<TakeSnapshotsOnKvmJobStruct> snapshotJobs) {
2931
this.snapshotJobs = snapshotJobs;
3032
}
33+
34+
public List<VmHostFileBackupJob> getVmHostFileBackupJobs() {
35+
return vmHostFileBackupJobs;
36+
}
37+
38+
public void setVmHostFileBackupJobs(List<VmHostFileBackupJob> vmHostFileBackupJobs) {
39+
this.vmHostFileBackupJobs = vmHostFileBackupJobs;
40+
}
41+
3142
}

header/src/main/java/org/zstack/header/storage/snapshot/TakeVolumesSnapshotOnKvmReply.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010
public class TakeVolumesSnapshotOnKvmReply extends MessageReply {
1111
private List<TakeSnapshotsOnKvmResultStruct> snapshotsResults;
12+
private String hostBackupTempResourceUuid;
1213

1314
public List<TakeSnapshotsOnKvmResultStruct> getSnapshotsResults() {
1415
return snapshotsResults;
@@ -17,4 +18,12 @@ public List<TakeSnapshotsOnKvmResultStruct> getSnapshotsResults() {
1718
public void setSnapshotsResults(List<TakeSnapshotsOnKvmResultStruct> snapshotsResults) {
1819
this.snapshotsResults = snapshotsResults;
1920
}
21+
22+
public String getHostBackupTempResourceUuid() {
23+
return hostBackupTempResourceUuid;
24+
}
25+
26+
public void setHostBackupTempResourceUuid(String hostBackupTempResourceUuid) {
27+
this.hostBackupTempResourceUuid = hostBackupTempResourceUuid;
28+
}
2029
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.zstack.header.vm.additions;
2+
3+
/**
4+
* @author Zdream
5+
* @date 2026-03-28
6+
* @since 0.0.5
7+
*/
8+
public class VmHostFileBackupJob {
9+
private String srcPath;
10+
private String destPath;
11+
private String type;
12+
13+
public String getSrcPath() {
14+
return srcPath;
15+
}
16+
17+
public void setSrcPath(String srcPath) {
18+
this.srcPath = srcPath;
19+
}
20+
21+
public String getDestPath() {
22+
return destPath;
23+
}
24+
25+
public void setDestPath(String destPath) {
26+
this.destPath = destPath;
27+
}
28+
29+
public String getType() {
30+
return type;
31+
}
32+
33+
public void setType(String type) {
34+
this.type = type;
35+
}
36+
}

plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,25 @@ public static String buildPathForVmHostFileType(VmHostFileType type, String vmUu
219219
}
220220
}
221221

222+
public static final String NV_RAM_SNAPSHOT_BACKUP_FILE_PATH_FORMAT = "/var/lib/libvirt/qemu/nvram/%s-host-files/%s.fd.snapshot-backup";
223+
public static String buildNvramSnapshotBackupFilePath(String vmUuid) {
224+
return String.format(NV_RAM_SNAPSHOT_BACKUP_FILE_PATH_FORMAT, vmUuid, vmUuid);
225+
}
226+
227+
public static final String TPM_STATE_SNAPSHOT_BACKUP_FILE_PATH_FORMAT = "/var/lib/libvirt/swtpm/%s.snapshot-backup/";
228+
public static String buildTpmStateSnapshotBackupFilePath(String vmUuid) {
229+
String vmUuidWithHyphen = vmUuid.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5");
230+
return String.format(TPM_STATE_SNAPSHOT_BACKUP_FILE_PATH_FORMAT, vmUuidWithHyphen);
231+
}
232+
233+
public static String buildSnapshotBackupPathForVmHostFileType(VmHostFileType type, String vmUuid) {
234+
switch (type) {
235+
case NvRam: return buildNvramSnapshotBackupFilePath(vmUuid);
236+
case TpmState: return buildTpmStateSnapshotBackupFilePath(vmUuid);
237+
default: throw new CloudRuntimeException("unsupported VmHostFileType: " + type);
238+
}
239+
}
240+
222241
public static final String DHCP_BIN_FILE_PATH = "/usr/local/zstack/dnsmasq";
223242

224243
enum KvmVmState {

plugin/kvm/src/main/java/org/zstack/kvm/efi/KvmSecureBootExtensions.java

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import org.zstack.header.tpm.entity.TpmVO_;
2727
import org.zstack.header.vm.DiskAO;
2828
import org.zstack.header.vm.PreVmInstantiateResourceExtensionPoint;
29+
import org.zstack.header.vm.VmInstanceVO;
30+
import org.zstack.header.vm.VmInstanceVO_;
2931
import org.zstack.header.vm.VmInstanceConstant;
3032
import org.zstack.header.vm.AfterReimageVmInstanceExtensionPoint;
3133
import org.zstack.header.vm.VmInstanceInventory;
@@ -44,6 +46,12 @@
4446
import org.zstack.header.vm.additions.VmHostFileType;
4547
import org.zstack.header.vm.additions.VmHostFileVO;
4648
import org.zstack.header.vm.additions.VmHostFileVO_;
49+
import org.zstack.header.storage.snapshot.ConsistentType;
50+
import org.zstack.header.storage.snapshot.CreateVolumesSnapshotOverlayInnerMsg;
51+
import org.zstack.header.storage.snapshot.TakeVolumesSnapshotOnKvmReply;
52+
import org.zstack.header.storage.snapshot.VolumeSnapshotCreationExtensionPoint;
53+
import org.zstack.header.storage.snapshot.VolumeSnapshotInventory;
54+
import org.zstack.header.storage.snapshot.group.VolumeSnapshotGroupInventory;
4755
import org.zstack.header.volume.VolumeInventory;
4856
import org.zstack.kvm.KVMAgentCommands;
4957
import org.zstack.kvm.KVMAgentCommands.*;
@@ -82,7 +90,8 @@ public class KvmSecureBootExtensions implements KVMStartVmExtensionPoint,
8290
VmPreMigrationExtensionPoint,
8391
AfterReimageVmInstanceExtensionPoint,
8492
VmReleaseResourceExtensionPoint,
85-
VmInstanceMigrateExtensionPoint {
93+
VmInstanceMigrateExtensionPoint,
94+
VolumeSnapshotCreationExtensionPoint {
8695
private static final CLogger logger = Utils.getLogger(KvmSecureBootExtensions.class);
8796

8897
@Autowired
@@ -614,4 +623,86 @@ public void run(MessageReply reply) {
614623
}
615624
});
616625
}
626+
627+
@Override
628+
public void afterVolumeLiveSnapshotGroupCreatedOnBackend(CreateVolumesSnapshotOverlayInnerMsg msg,
629+
TakeVolumesSnapshotOnKvmReply treply,
630+
Completion completion) {
631+
if (treply == null || !treply.isSuccess()) {
632+
completion.success();
633+
return;
634+
}
635+
636+
if (!msg.isBackupHostFileIfNeeded()) {
637+
completion.success();
638+
return;
639+
}
640+
641+
String vmUuid = msg.getLockedVmInstanceUuids().get(0);
642+
String hostUuid = Q.New(VmInstanceVO.class)
643+
.select(VmInstanceVO_.hostUuid)
644+
.eq(VmInstanceVO_.uuid, vmUuid)
645+
.findValue();
646+
647+
List<VmHostFileVO> hostFiles = Q.New(VmHostFileVO.class)
648+
.eq(VmHostFileVO_.vmInstanceUuid, vmUuid)
649+
.eq(VmHostFileVO_.hostUuid, hostUuid)
650+
.list();
651+
652+
if (hostFiles.isEmpty()) {
653+
completion.success();
654+
return;
655+
}
656+
657+
String tempResourceUuid = Platform.getUuid();
658+
659+
SyncVmHostFilesFromHostMsg syncMsg = new SyncVmHostFilesFromHostMsg();
660+
syncMsg.setVmUuid(vmUuid);
661+
syncMsg.setHostUuid(hostUuid);
662+
663+
for (VmHostFileVO file : hostFiles) {
664+
if (file.getType() == VmHostFileType.NvRam) {
665+
syncMsg.setNvRamPath(buildNvramSnapshotBackupFilePath(vmUuid));
666+
} else if (file.getType() == VmHostFileType.TpmState) {
667+
syncMsg.setTpmStateFolder(buildTpmStateSnapshotBackupFilePath(vmUuid));
668+
}
669+
}
670+
671+
syncMsg.setSyncReason("snapshot-group-online-backup");
672+
syncMsg.setSyncToBackup(true);
673+
syncMsg.setBackupResourceUuid(tempResourceUuid);
674+
bus.makeLocalServiceId(syncMsg, VmInstanceConstant.SECURE_BOOT_SERVICE_ID);
675+
bus.send(syncMsg, new CloudBusCallBack(completion) {
676+
@Override
677+
public void run(MessageReply reply) {
678+
if (reply.isSuccess()) {
679+
treply.setHostBackupTempResourceUuid(tempResourceUuid);
680+
logger.debug(String.format("synced backup host files for vm[uuid:%s] to VmHostBackupFileVO[resourceUuid:%s]",
681+
vmUuid, tempResourceUuid));
682+
} else {
683+
logger.warn(String.format("failed to sync backup host files for vm[uuid:%s] during online snapshot, " +
684+
"but tolerated: %s", vmUuid, reply.getError().getReadableDetails()));
685+
}
686+
completion.success();
687+
}
688+
});
689+
}
690+
691+
@Override
692+
public void afterVolumeLiveSnapshotGroupCreationFailsOnBackend(CreateVolumesSnapshotOverlayInnerMsg msg,
693+
TakeVolumesSnapshotOnKvmReply treply) {
694+
// No cleanup needed — backup files on agent side are ephemeral
695+
}
696+
697+
@Override
698+
public void afterVolumeSnapshotGroupCreated(VolumeSnapshotGroupInventory snapshotGroup,
699+
ConsistentType consistentType,
700+
Completion completion) {
701+
completion.success();
702+
}
703+
704+
@Override
705+
public void afterVolumeSnapshotCreated(VolumeSnapshotInventory snapshot, Completion completion) {
706+
completion.success();
707+
}
617708
}

0 commit comments

Comments
 (0)