package org.ovirt.engine.core.vdsbroker.monitoring;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.ovirt.engine.core.common.businessentities.VmDynamic;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.VmDynamicDao;
import org.ovirt.engine.core.di.Injector;
import org.ovirt.engine.core.vdsbroker.ObjectDescriptor;
import org.ovirt.engine.core.vdsbroker.ResourceManager;
import org.ovirt.engine.core.vdsbroker.VdsManager;
import org.ovirt.engine.core.vdsbroker.vdsbroker.VdsBrokerObjectsBuilder;
import org.ovirt.vdsm.jsonrpc.client.events.EventSubscriber;
import org.reactivestreams.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EventVmStatsRefresher extends VmStatsRefresher {
private static final Logger log = LoggerFactory.getLogger(EventVmStatsRefresher.class);
private Subscription subscription;
@Inject
private VmDynamicDao vmDynamicDao;
private ResourceManager resourceManager;
private PollVmStatsRefresher allVmStatsOnlyRefresher;
@SuppressWarnings("deprecation")
public EventVmStatsRefresher(VdsManager manager) {
super(manager);
// we still want to fetch GetAllVmStats as we did before
allVmStatsOnlyRefresher = Injector.injectMembers(new PollVmStatsRefresher(vdsManager));
resourceManager = ResourceManager.getInstance();
}
@Override
public void startMonitoring() {
allVmStatsOnlyRefresher.startMonitoring();
final String hostname = vdsManager.getVdsHostname();
resourceManager.subscribe(new EventSubscriber(hostname + "|*|VM_status|*") {
@Override
public void onSubscribe(Subscription sub) {
subscription = sub;
subscription.request(1);
}
@Override
public void onNext(Map<String, Object> map) {
try {
long fetchTime = System.nanoTime();
printEventInDebug(map);
List<Pair<VmDynamic, VdsmVm>> vms = convertEvent(map);
if (!vms.isEmpty()) {
getVmsMonitoring().perform(vms, fetchTime, vdsManager, false);
processDevices(vms.stream().map(Pair::getSecond), fetchTime);
}
} finally {
subscription.request(1);
}
}
private void printEventInDebug(Map<String, Object> map) {
if (!log.isDebugEnabled()) {
return;
}
StringBuilder sb = new StringBuilder();
ObjectDescriptor.toStringBuilder(map, sb);
log.debug("processing event for host {} data:\n{}", vdsManager.getVdsName(), sb);
}
@SuppressWarnings("unchecked")
private List<Pair<VmDynamic, VdsmVm>> convertEvent(Map<String, Object> map) {
Double notifyTime = VdsBrokerObjectsBuilder.removeNotifyTimeFromVmStatusEvent(map);
return map.entrySet().stream()
.map(idToMap -> toMonitoredVm(
new Guid(idToMap.getKey()),
(Map<String, Object>) idToMap.getValue(),
notifyTime))
.collect(Collectors.toList());
}
private Pair<VmDynamic, VdsmVm> toMonitoredVm(Guid vmId, Map<String, Object> vmMap, Double notifyTime) {
VmDynamic dbVm = vmDynamicDao.get(vmId);
VdsmVm vdsmVm = dbVm == null ?
createVdsmVm(vmId, vmMap, notifyTime)
: createVdsmVm(dbVm, vmMap, notifyTime);
return new Pair<>(dbVm, vdsmVm);
}
private VdsmVm createVdsmVm(Guid vmId, Map<String, Object> struct, Double notifyTime) {
VmDynamic fakeVm = new VmDynamic();
fakeVm.setId(vmId);
return createVdsmVm(fakeVm, struct, notifyTime);
}
private VdsmVm createVdsmVm(VmDynamic dbVmDynamic, Map<String, Object> struct, Double notifyTime) {
// send a clone of vm dynamic to be overridden with new data
VmDynamic clonedVmDynamic = new VmDynamic(dbVmDynamic);
VdsBrokerObjectsBuilder.updateVMDynamicData(clonedVmDynamic, struct, vdsManager.getCopyVds());
return new VdsmVm(notifyTime)
.setVmDynamic(clonedVmDynamic)
.setDevicesHash(VdsBrokerObjectsBuilder.getVmDevicesHash(struct));
}
@Override
public void onError(Throwable t) {
// communication issue is delivered as a message so we need to request for more
subscription.request(1);
}
@Override
public void onComplete() {
}
});
}
@Override
public void stopMonitoring() {
allVmStatsOnlyRefresher.stopMonitoring();
subscription.cancel();
}
}