Skip to content

Commit 650a6fd

Browse files
author
gitlab
committed
Merge branch 'zsv-ldap-3@@2' into 'feature-zsv-5.0.0-vm-support-vtpm-and-secuceboot'
<feature>[kvm]: add online snapshot support for VM host files See merge request zstackio/zstack!9485
2 parents 34ae415 + fc22117 commit 650a6fd

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
@@ -27,6 +27,8 @@
2727
import org.zstack.header.tpm.entity.TpmVO_;
2828
import org.zstack.header.vm.DiskAO;
2929
import org.zstack.header.vm.PreVmInstantiateResourceExtensionPoint;
30+
import org.zstack.header.vm.VmInstanceVO;
31+
import org.zstack.header.vm.VmInstanceVO_;
3032
import org.zstack.header.vm.VmInstanceConstant;
3133
import org.zstack.header.vm.AfterReimageVmInstanceExtensionPoint;
3234
import org.zstack.header.vm.VmInstanceInventory;
@@ -45,6 +47,12 @@
4547
import org.zstack.header.vm.additions.VmHostFileType;
4648
import org.zstack.header.vm.additions.VmHostFileVO;
4749
import org.zstack.header.vm.additions.VmHostFileVO_;
50+
import org.zstack.header.storage.snapshot.ConsistentType;
51+
import org.zstack.header.storage.snapshot.CreateVolumesSnapshotOverlayInnerMsg;
52+
import org.zstack.header.storage.snapshot.TakeVolumesSnapshotOnKvmReply;
53+
import org.zstack.header.storage.snapshot.VolumeSnapshotCreationExtensionPoint;
54+
import org.zstack.header.storage.snapshot.VolumeSnapshotInventory;
55+
import org.zstack.header.storage.snapshot.group.VolumeSnapshotGroupInventory;
4856
import org.zstack.header.volume.VolumeInventory;
4957
import org.zstack.kvm.KVMAgentCommands;
5058
import org.zstack.kvm.KVMAgentCommands.*;
@@ -83,7 +91,8 @@ public class KvmSecureBootExtensions implements KVMStartVmExtensionPoint,
8391
VmPreMigrationExtensionPoint,
8492
AfterReimageVmInstanceExtensionPoint,
8593
VmReleaseResourceExtensionPoint,
86-
VmInstanceMigrateExtensionPoint {
94+
VmInstanceMigrateExtensionPoint,
95+
VolumeSnapshotCreationExtensionPoint {
8796
private static final CLogger logger = Utils.getLogger(KvmSecureBootExtensions.class);
8897

8998
@Autowired
@@ -634,4 +643,86 @@ public void run(MessageReply reply) {
634643
}
635644
});
636645
}
646+
647+
@Override
648+
public void afterVolumeLiveSnapshotGroupCreatedOnBackend(CreateVolumesSnapshotOverlayInnerMsg msg,
649+
TakeVolumesSnapshotOnKvmReply treply,
650+
Completion completion) {
651+
if (treply == null || !treply.isSuccess()) {
652+
completion.success();
653+
return;
654+
}
655+
656+
if (!msg.isBackupHostFileIfNeeded()) {
657+
completion.success();
658+
return;
659+
}
660+
661+
String vmUuid = msg.getLockedVmInstanceUuids().get(0);
662+
String hostUuid = Q.New(VmInstanceVO.class)
663+
.select(VmInstanceVO_.hostUuid)
664+
.eq(VmInstanceVO_.uuid, vmUuid)
665+
.findValue();
666+
667+
List<VmHostFileVO> hostFiles = Q.New(VmHostFileVO.class)
668+
.eq(VmHostFileVO_.vmInstanceUuid, vmUuid)
669+
.eq(VmHostFileVO_.hostUuid, hostUuid)
670+
.list();
671+
672+
if (hostFiles.isEmpty()) {
673+
completion.success();
674+
return;
675+
}
676+
677+
String tempResourceUuid = Platform.getUuid();
678+
679+
SyncVmHostFilesFromHostMsg syncMsg = new SyncVmHostFilesFromHostMsg();
680+
syncMsg.setVmUuid(vmUuid);
681+
syncMsg.setHostUuid(hostUuid);
682+
683+
for (VmHostFileVO file : hostFiles) {
684+
if (file.getType() == VmHostFileType.NvRam) {
685+
syncMsg.setNvRamPath(buildNvramSnapshotBackupFilePath(vmUuid));
686+
} else if (file.getType() == VmHostFileType.TpmState) {
687+
syncMsg.setTpmStateFolder(buildTpmStateSnapshotBackupFilePath(vmUuid));
688+
}
689+
}
690+
691+
syncMsg.setSyncReason("snapshot-group-online-backup");
692+
syncMsg.setSyncToBackup(true);
693+
syncMsg.setBackupResourceUuid(tempResourceUuid);
694+
bus.makeLocalServiceId(syncMsg, VmInstanceConstant.SECURE_BOOT_SERVICE_ID);
695+
bus.send(syncMsg, new CloudBusCallBack(completion) {
696+
@Override
697+
public void run(MessageReply reply) {
698+
if (reply.isSuccess()) {
699+
treply.setHostBackupTempResourceUuid(tempResourceUuid);
700+
logger.debug(String.format("synced backup host files for vm[uuid:%s] to VmHostBackupFileVO[resourceUuid:%s]",
701+
vmUuid, tempResourceUuid));
702+
} else {
703+
logger.warn(String.format("failed to sync backup host files for vm[uuid:%s] during online snapshot, " +
704+
"but tolerated: %s", vmUuid, reply.getError().getReadableDetails()));
705+
}
706+
completion.success();
707+
}
708+
});
709+
}
710+
711+
@Override
712+
public void afterVolumeLiveSnapshotGroupCreationFailsOnBackend(CreateVolumesSnapshotOverlayInnerMsg msg,
713+
TakeVolumesSnapshotOnKvmReply treply) {
714+
// No cleanup needed — backup files on agent side are ephemeral
715+
}
716+
717+
@Override
718+
public void afterVolumeSnapshotGroupCreated(VolumeSnapshotGroupInventory snapshotGroup,
719+
ConsistentType consistentType,
720+
Completion completion) {
721+
completion.success();
722+
}
723+
724+
@Override
725+
public void afterVolumeSnapshotCreated(VolumeSnapshotInventory snapshot, Completion completion) {
726+
completion.success();
727+
}
637728
}

0 commit comments

Comments
 (0)