Skip to content

Commit f5ae3c9

Browse files
author
Zhang Wenhao
committed
<feature>[kvm]: add VM host file periodic sync tracker
* Introduce VmHostFileTracker component to periodically sync VM host files (NvRam/TpmState) from hosts for running VMs every 30 minutes * The tracker queries all VmHostFileVO records for VMs in Running state and groups the by vmUuid+hostUuid to trigger sync in parallel with concurrency control. Resolves: ZSV-11613 Related: ZSV-11310 Change-Id: I6b767073656d7474686d7a756871626278647167
1 parent 730d061 commit f5ae3c9

3 files changed

Lines changed: 159 additions & 0 deletions

File tree

conf/springConfigXml/Kvm.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,10 @@
277277
<zstack:extension interface="org.zstack.header.vm.VmInstanceMigrateExtensionPoint" />
278278
</zstack:plugin>
279279
</bean>
280+
281+
<bean id="VmHostFileTracker" class="org.zstack.kvm.efi.VmHostFileTracker">
282+
<zstack:plugin>
283+
<zstack:extension interface="org.zstack.header.Component"/>
284+
</zstack:plugin>
285+
</bean>
280286
</beans>
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package org.zstack.kvm.efi;
2+
3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.zstack.core.CoreGlobalProperty;
5+
import org.zstack.core.asyncbatch.While;
6+
import org.zstack.core.cloudbus.CloudBus;
7+
import org.zstack.core.cloudbus.CloudBusCallBack;
8+
import org.zstack.core.cloudbus.ResourceDestinationMaker;
9+
import org.zstack.core.db.Q;
10+
import org.zstack.core.thread.PeriodicTask;
11+
import org.zstack.core.thread.ThreadFacade;
12+
import org.zstack.header.Component;
13+
import org.zstack.header.core.WhileDoneCompletion;
14+
import org.zstack.header.errorcode.ErrorCodeList;
15+
import org.zstack.header.message.MessageReply;
16+
import org.zstack.header.vm.VmInstanceAO_;
17+
import org.zstack.header.vm.VmInstanceConstant;
18+
import org.zstack.header.vm.VmInstanceState;
19+
import org.zstack.header.vm.VmInstanceVO;
20+
import org.zstack.header.vm.additions.VmHostFileType;
21+
import org.zstack.header.vm.additions.VmHostFileVO;
22+
import org.zstack.header.vm.additions.VmHostFileVO_;
23+
import org.zstack.utils.Utils;
24+
import org.zstack.utils.logging.CLogger;
25+
26+
import java.util.ArrayList;
27+
import java.util.List;
28+
import java.util.Map;
29+
import java.util.concurrent.Future;
30+
import java.util.concurrent.TimeUnit;
31+
import java.util.stream.Collectors;
32+
33+
public class VmHostFileTracker implements Component {
34+
private static final CLogger logger = Utils.getLogger(VmHostFileTracker.class);
35+
36+
private static final long SYNC_INTERVAL_SECONDS = TimeUnit.MINUTES.toSeconds(30);
37+
private static final int SYNC_CONCURRENCY = 5;
38+
39+
@Autowired
40+
private ThreadFacade threadFacade;
41+
@Autowired
42+
private CloudBus bus;
43+
@Autowired
44+
private ResourceDestinationMaker destinationMaker;
45+
46+
private Future<Void> trackerThread;
47+
48+
@Override
49+
public boolean start() {
50+
if (CoreGlobalProperty.UNIT_TEST_ON) {
51+
logger.info("VmHostFileTracker is disabled in unit test");
52+
return true;
53+
}
54+
55+
trackerThread = threadFacade.submitPeriodicTask(new PeriodicTask() {
56+
@Override
57+
public TimeUnit getTimeUnit() {
58+
return TimeUnit.SECONDS;
59+
}
60+
61+
@Override
62+
public long getInterval() {
63+
return SYNC_INTERVAL_SECONDS;
64+
}
65+
66+
@Override
67+
public String getName() {
68+
return "vm-host-file-tracker";
69+
}
70+
71+
@Override
72+
public void run() {
73+
logger.info("VmHostFileTracker: starting periodic sync of VM host files");
74+
syncVmHostFiles();
75+
}
76+
});
77+
78+
return true;
79+
}
80+
81+
@Override
82+
public boolean stop() {
83+
if (trackerThread != null) {
84+
trackerThread.cancel(true);
85+
}
86+
return true;
87+
}
88+
89+
private void syncVmHostFiles() {
90+
List<VmHostFileVO> hostFiles = Q.New(VmHostFileVO.class, VmInstanceVO.class)
91+
.table0()
92+
.eq(VmHostFileVO_.vmInstanceUuid).table1(VmInstanceAO_.uuid)
93+
.eq(VmHostFileVO_.hostUuid).table1(VmInstanceAO_.hostUuid)
94+
.selectThisTable()
95+
.table1()
96+
.eq(VmInstanceAO_.state, VmInstanceState.Running)
97+
.list();
98+
99+
if (hostFiles.isEmpty()) {
100+
return;
101+
}
102+
103+
Map<String, List<VmHostFileVO>> grouped = hostFiles.stream()
104+
.collect(Collectors.groupingBy(f -> f.getVmInstanceUuid() + "::" + f.getHostUuid()));
105+
List<List<VmHostFileVO>> groups = new ArrayList<>(grouped.values());
106+
107+
new While<>(groups).step((group, whileCompletion) -> {
108+
VmHostFileVO first = group.get(0);
109+
String vmUuid = first.getVmInstanceUuid();
110+
String hostUuid = first.getHostUuid();
111+
112+
if (!destinationMaker.isManagedByUs(vmUuid)) {
113+
whileCompletion.done();
114+
return;
115+
}
116+
117+
SyncVmHostFilesFromHostMsg syncMsg = new SyncVmHostFilesFromHostMsg();
118+
syncMsg.setHostUuid(hostUuid);
119+
syncMsg.setVmUuid(vmUuid);
120+
121+
for (VmHostFileVO file : group) {
122+
if (file.getType() == VmHostFileType.NvRam) {
123+
syncMsg.setNvRamPath(file.getPath());
124+
} else if (file.getType() == VmHostFileType.TpmState) {
125+
syncMsg.setTpmStateFolder(file.getPath());
126+
}
127+
}
128+
129+
bus.makeLocalServiceId(syncMsg, VmInstanceConstant.SECURE_BOOT_SERVICE_ID);
130+
bus.send(syncMsg, new CloudBusCallBack(whileCompletion) {
131+
@Override
132+
public void run(MessageReply reply) {
133+
if (!reply.isSuccess()) {
134+
logger.warn(String.format("failed to sync VM host file[vmUuid=%s] from host[uuid=%s]: %s",
135+
vmUuid, hostUuid, reply.getError().getReadableDetails()));
136+
}
137+
whileCompletion.done();
138+
}
139+
});
140+
}, SYNC_CONCURRENCY).run(new WhileDoneCompletion(null) {
141+
@Override
142+
public void done(ErrorCodeList errorCodeList) {
143+
// periodic sync round finished, empty callback
144+
}
145+
});
146+
}
147+
}

test/src/test/resources/springConfigXml/Kvm.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,4 +276,10 @@
276276
<zstack:extension interface="org.zstack.header.vm.VmInstanceMigrateExtensionPoint" />
277277
</zstack:plugin>
278278
</bean>
279+
280+
<bean id="VmHostFileTracker" class="org.zstack.kvm.efi.VmHostFileTracker">
281+
<zstack:plugin>
282+
<zstack:extension interface="org.zstack.header.Component"/>
283+
</zstack:plugin>
284+
</bean>
279285
</beans>

0 commit comments

Comments
 (0)