package org.ovirt.engine.core.vdsbroker.monitoring;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.ovirt.engine.core.common.businessentities.VmDynamic;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.common.vdscommands.GetVmStatsVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
import org.ovirt.engine.core.common.vdscommands.VdsIdAndVdsVDSCommandParametersBase;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.dao.VmDynamicDao;
import org.ovirt.engine.core.vdsbroker.ResourceManager;
import org.ovirt.engine.core.vdsbroker.VdsManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* in-charge of fetching vms list together with the db counter-part
* and store for analysis on VdsManager
*/
public class VmsListFetcher {
protected VdsManager vdsManager;
protected List<Pair<VmDynamic, VdsmVm>> changedVms;
protected Map<Guid, VdsmVm> vdsmVms;
private Map<Guid, VmDynamic> dbVms;
// dependencies
private DbFacade dbFacade;
private ResourceManager resourceManager;
private static final Logger log = LoggerFactory.getLogger(VmsListFetcher.class);
public VmsListFetcher(VdsManager vdsManager) {
this.vdsManager = vdsManager;
this.dbFacade = DbFacade.getInstance();
this.resourceManager = ResourceManager.getInstance();
}
public VmsListFetcher(VdsManager vdsManager, DbFacade dbFacade, ResourceManager resourceManager) {
this.vdsManager = vdsManager;
this.dbFacade = dbFacade;
this.resourceManager = resourceManager;
}
@SuppressWarnings("unchecked")
public boolean fetch() {
VDSReturnValue pollReturnValue = poll();
if (pollReturnValue.getSucceeded()) {
vdsmVms = (Map<Guid, VdsmVm>) pollReturnValue.getReturnValue();
onFetchVms();
return true;
} else {
onError();
return false;
}
}
protected VDSReturnValue poll() {
return getResourceManager().runVdsCommand(
VDSCommandType.List,
new VdsIdAndVdsVDSCommandParametersBase(vdsManager.getCopyVds()));
}
protected void onFetchVms() {
dbVms = getVmDynamicDao().getAllRunningForVds(vdsManager.getVdsId()).stream()
.collect(Collectors.toMap(VmDynamic::getId, Function.identity()));
changedVms = new ArrayList<>();
filterVms();
gatherNonRunningVms(dbVms);
saveLastVmsList(vdsmVms);
}
private void saveLastVmsList(Map<Guid, VdsmVm> vdsmVms) {
List<VmDynamic> vms = new ArrayList<>(vdsmVms.size());
for (VdsmVm vmInternalData : this.vdsmVms.values()) {
if (dbVms.containsKey(vmInternalData.getVmDynamic().getId())) {
vms.add(vmInternalData.getVmDynamic());
}
}
vdsManager.setLastVmsList(vms);
}
protected void onError() {
dbVms = Collections.emptyMap();
vdsmVms = Collections.emptyMap();
}
protected void filterVms() {
for (VdsmVm vdsmVm : vdsmVms.values()) {
VmDynamic dbVm = dbVms.get(vdsmVm.getVmDynamic().getId());
gatherChangedVms(dbVm, vdsmVm);
}
}
protected void gatherChangedVms(VmDynamic dbVm, VdsmVm vdsmVm) {
if (statusChanged(dbVm, vdsmVm.getVmDynamic())) {
VDSReturnValue vmStats =
getResourceManager().runVdsCommand(
VDSCommandType.GetVmStats,
new GetVmStatsVDSCommandParameters(vdsManager.getVdsId(), vdsmVm.getVmDynamic().getId()));
if (vmStats.getSucceeded()) {
changedVms.add(new Pair<>(dbVm, (VdsmVm) vmStats.getReturnValue()));
} else {
if (dbVm != null) {
log.error(
"failed to fetch VM '{}' stats. status remain unchanged ({})",
dbVm.getId(),
dbVm.getStatus());
}
}
}
}
private void gatherNonRunningVms(Map<Guid, VmDynamic> dbVms) {
for (VmDynamic dbVm : dbVms.values()) {
if (!vdsmVms.containsKey(dbVm.getId())) {
// non running vms are also treated as changed VMs
changedVms.add(new Pair<>(dbVm, null));
}
}
}
private boolean statusChanged(VmDynamic dbVm, VmDynamic vdsmVm) {
return dbVm == null || (dbVm.getStatus() != vdsmVm.getStatus());
}
public VmDynamicDao getVmDynamicDao() {
return dbFacade.getVmDynamicDao();
}
public ResourceManager getResourceManager() {
return resourceManager;
}
public Collection<VdsmVm> getVdsmVms() {
return vdsmVms.values();
}
public List<Pair<VmDynamic, VdsmVm>> getChangedVms() {
return changedVms;
}
}