package org.ovirt.engine.core.bll;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.context.EngineContext;
import org.ovirt.engine.core.bll.hostdev.HostDeviceManager;
import org.ovirt.engine.core.bll.interfaces.BackendInternal;
import org.ovirt.engine.core.bll.job.ExecutionHandler;
import org.ovirt.engine.core.bll.scheduling.SchedulingManager;
import org.ovirt.engine.core.bll.storage.pool.StoragePoolStatusHandler;
import org.ovirt.engine.core.bll.tasks.CommandCoordinatorUtil;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.action.AddUnmanagedVmsParameters;
import org.ovirt.engine.core.common.action.ConnectHostToStoragePoolServersParameters;
import org.ovirt.engine.core.common.action.FenceVdsActionParameters;
import org.ovirt.engine.core.common.action.HostStoragePoolParametersBase;
import org.ovirt.engine.core.common.action.MaintenanceNumberOfVdssParameters;
import org.ovirt.engine.core.common.action.MigrateVmToServerParameters;
import org.ovirt.engine.core.common.action.ProcessDownVmParameters;
import org.ovirt.engine.core.common.action.ReconstructMasterParameters;
import org.ovirt.engine.core.common.action.RunVmParams;
import org.ovirt.engine.core.common.action.SetNonOperationalVdsParameters;
import org.ovirt.engine.core.common.action.SetStoragePoolStatusParameters;
import org.ovirt.engine.core.common.action.StorageDomainParametersBase;
import org.ovirt.engine.core.common.action.StorageDomainPoolParametersBase;
import org.ovirt.engine.core.common.action.VdcActionParametersBase;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdsActionParameters;
import org.ovirt.engine.core.common.action.VmSlaPolicyParameters;
import org.ovirt.engine.core.common.businessentities.Cluster;
import org.ovirt.engine.core.common.businessentities.IVdsAsyncCommand;
import org.ovirt.engine.core.common.businessentities.IVdsEventListener;
import org.ovirt.engine.core.common.businessentities.NonOperationalReason;
import org.ovirt.engine.core.common.businessentities.StorageDomainStatic;
import org.ovirt.engine.core.common.businessentities.StoragePool;
import org.ovirt.engine.core.common.businessentities.StoragePoolStatus;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VDSStatus;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VmStatic;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterStatus;
import org.ovirt.engine.core.common.businessentities.qos.CpuQos;
import org.ovirt.engine.core.common.businessentities.qos.StorageQos;
import org.ovirt.engine.core.common.businessentities.storage.Disk;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.businessentities.storage.DiskStorageType;
import org.ovirt.engine.core.common.errors.EngineError;
import org.ovirt.engine.core.common.errors.EngineException;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.eventqueue.Event;
import org.ovirt.engine.core.common.eventqueue.EventQueue;
import org.ovirt.engine.core.common.eventqueue.EventResult;
import org.ovirt.engine.core.common.eventqueue.EventType;
import org.ovirt.engine.core.common.interfaces.VDSBrokerFrontend;
import org.ovirt.engine.core.common.locks.LockingGroup;
import org.ovirt.engine.core.common.qualifiers.MomPolicyUpdate;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.common.vdscommands.DisconnectStoragePoolVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.MomPolicyVDSParameters;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.TransactionScopeOption;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogable;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableImpl;
import org.ovirt.engine.core.dao.DiskDao;
import org.ovirt.engine.core.dao.StoragePoolDao;
import org.ovirt.engine.core.dao.VdsDao;
import org.ovirt.engine.core.dao.VmStaticDao;
import org.ovirt.engine.core.dao.gluster.GlusterBrickDao;
import org.ovirt.engine.core.dao.qos.CpuQosDao;
import org.ovirt.engine.core.dao.qos.StorageQosDao;
import org.ovirt.engine.core.di.Injector;
import org.ovirt.engine.core.utils.lock.EngineLock;
import org.ovirt.engine.core.utils.lock.LockManager;
import org.ovirt.engine.core.utils.threadpool.ThreadPoolUtil;
import org.ovirt.engine.core.vdsbroker.ResourceManager;
import org.ovirt.engine.core.vdsbroker.irsbroker.IrsProxy;
import org.ovirt.engine.core.vdsbroker.irsbroker.IrsProxyManager;
import org.ovirt.engine.core.vdsbroker.monitoring.VmJobsMonitoring;
import org.ovirt.engine.core.vdsbroker.vdsbroker.VDSNetworkException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class VdsEventListener implements IVdsEventListener {
@Inject
Instance<ResourceManager> resourceManagerProvider;
@Inject
EventQueue eventQueue;
@Inject
private LockManager lockManager;
@Inject
private HaAutoStartVmsRunner haAutoStartVmsRunner;
@Inject
private ColdRebootAutoStartVmsRunner coldRebootAutoStartVmsRunner;
@Inject
private VdsDao vdsDao;
@Inject
private VmStaticDao vmStaticDao;
@Inject
private StoragePoolDao storagePoolDao;
@Inject
private CpuQosDao cpuQosDao;
@Inject
private StorageQosDao storageQosDao;
@Inject
private DiskDao diskDao;
@Inject
private BackendInternal backend;
@Inject
private Instance<HostedEngineImporter> hostedEngineImporterProvider;
@Inject
private SchedulingManager schedulingManager;
@Inject
private AuditLogDirector auditLogDirector;
@Inject
private GlusterBrickDao glusterBrickDao;
@Inject
private VDSBrokerFrontend vdsBroker;
@Inject
private VmJobsMonitoring vmJobsMonitoring;
@Inject
private ExecutionHandler executionHandler;
@Inject
private IrsProxyManager irsProxyManager;
private static final Logger log = LoggerFactory.getLogger(VdsEventListener.class);
@Override
public void vdsMovedToMaintenance(VDS vds) {
try {
processStorageOnVdsInactive(vds);
} finally {
executionHandler.updateSpecificActionJobCompleted(vds.getId(), VdcActionType.MaintenanceVds, true);
}
}
private void processStorageOnVdsInactive(final VDS vds) {
// Clear the problematic timers since the VDS is in maintenance so it doesn't make sense to check it
// anymore.
if (!Guid.Empty.equals(vds.getStoragePoolId())) {
// when vds is being moved to maintenance, this is the part in which we disconnect it from the pool
// and the storage server. it should be synced with the host autorecovery mechanism to try to avoid
// leaving the host with storage/pool connection when it's on maintenance.
EngineLock lock = new EngineLock(Collections.singletonMap(vds.getId().toString(),
new Pair<>(LockingGroup.VDS_POOL_AND_STORAGE_CONNECTIONS.toString(),
EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED.toString())), null);
try {
lockManager.acquireLockWait(lock);
clearDomainCache(vds);
StoragePool storage_pool = storagePoolDao.get(vds.getStoragePoolId());
if (StoragePoolStatus.Uninitialized != storage_pool
.getStatus()) {
vdsBroker.runVdsCommand(
VDSCommandType.DisconnectStoragePool,
new DisconnectStoragePoolVDSCommandParameters(vds.getId(),
vds.getStoragePoolId(), vds.getVdsSpmId()));
HostStoragePoolParametersBase params =
new HostStoragePoolParametersBase(storage_pool, vds);
backend.runInternalAction(VdcActionType.DisconnectHostFromStoragePoolServers, params);
}
} finally {
lockManager.releaseLock(lock);
}
}
}
/**
* The following method will clear a cache for problematic domains, which were reported by vds
*/
private void clearDomainCache(final VDS vds) {
eventQueue.submitEventSync(new Event(vds.getStoragePoolId(),
null, vds.getId(), EventType.VDSCLEARCACHE, ""),
() -> {
clearVdsFromCache(vds.getStoragePoolId(), vds.getId(), vds.getName());
return new EventResult(true, EventType.VDSCLEARCACHE);
});
}
/**
* Remove a VDS entry from the pool's IRS Proxy cache, clearing the problematic domains for this VDS and their
* timers if they need to be cleaned. This is for a case when the VDS is switched to maintenance by the user, since
* we need to clear it's cache data and timers, or else the cache will contain stale data (since the VDS is not
* active anymore, it won't be connected to any of the domains).
*
* @param storagePoolId
* The ID of the storage pool to clean the IRS Proxy's cache for.
* @param vdsId
* The ID of the VDS to remove from the cache.
* @param vdsName
* The name of the VDS (for logging).
*/
private void clearVdsFromCache(Guid storagePoolId, Guid vdsId, String vdsName) {
IrsProxy irsProxyData = irsProxyManager.getProxy(storagePoolId);
if (irsProxyData != null) {
irsProxyData.clearVdsFromCache(vdsId, vdsName);
}
}
@Override
public EventResult storageDomainNotOperational(Guid storageDomainId, Guid storagePoolId) {
StorageDomainPoolParametersBase parameters =
new StorageDomainPoolParametersBase(storageDomainId, storagePoolId);
parameters.setIsInternal(true);
parameters.setInactive(true);
boolean isSucceeded = backend.runInternalAction(VdcActionType.DeactivateStorageDomain,
parameters,
ExecutionHandler.createInternalJobContext()).getSucceeded();
return new EventResult(isSucceeded, EventType.DOMAINNOTOPERATIONAL);
}
@Override
public EventResult masterDomainNotOperational(Guid storageDomainId,
Guid storagePoolId,
boolean isReconstructToInactiveDomains,
boolean canReconstructToCurrentMaster) {
VdcActionParametersBase parameters =
new ReconstructMasterParameters(storagePoolId,
storageDomainId,
true,
isReconstructToInactiveDomains,
canReconstructToCurrentMaster);
boolean isSucceeded = backend.runInternalAction(VdcActionType.ReconstructMasterDomain,
parameters,
ExecutionHandler.createInternalJobContext()).getSucceeded();
return new EventResult(isSucceeded, EventType.RECONSTRUCT);
}
@Override
public void processOnVmStop(final Collection<Guid> vmIds, final Guid hostId) {
if (vmIds.isEmpty()) {
return;
}
vmJobsMonitoring.removeJobsByVmIds(vmIds);
ThreadPoolUtil.execute(() -> processOnVmStopInternal(vmIds, hostId));
}
private void processOnVmStopInternal(final Collection<Guid> vmIds, final Guid hostId) {
for (Guid vmId : vmIds) {
backend.runInternalAction(VdcActionType.ProcessDownVm,
new ProcessDownVmParameters(vmId, true));
}
HostDeviceManager hostDeviceManager = Injector.get(HostDeviceManager.class);
hostDeviceManager.refreshHostIfAnyVmHasHostDevices(vmIds, hostId);
}
/**
* Synchronize LUN details comprising the storage domain with the DB
*/
@Override
public void syncLunsInfoForBlockStorageDomain(final Guid storageDomainId, final Guid vdsId) {
ThreadPoolUtil.execute(() -> {
StorageDomainParametersBase parameters = new StorageDomainParametersBase(storageDomainId);
parameters.setVdsId(vdsId);
backend.runInternalAction(VdcActionType.SyncLunsInfoForBlockStorageDomain, parameters);
});
}
@Override
public void vdsNonOperational(Guid vdsId, NonOperationalReason reason, boolean logCommand, Guid domainId) {
StorageDomainStatic storageDomain = DbFacade.getInstance().getStorageDomainStaticDao().get(domainId);
Map<String, String> customLogValues = null;
if (storageDomain != null) {
customLogValues = Collections.singletonMap("StorageDomainNames", storageDomain.getName());
}
vdsNonOperational(vdsId, reason, logCommand, domainId, customLogValues);
}
@Override
public void vdsNonOperational(Guid vdsId, NonOperationalReason reason, boolean logCommand, Guid domainId,
Map<String, String> customLogValues) {
executionHandler.updateSpecificActionJobCompleted(vdsId, VdcActionType.MaintenanceVds, false);
SetNonOperationalVdsParameters tempVar =
new SetNonOperationalVdsParameters(vdsId, reason, customLogValues);
tempVar.setStorageDomainId(domainId);
tempVar.setShouldBeLogged(logCommand);
backend.runInternalAction(VdcActionType.SetNonOperationalVds,
tempVar,
ExecutionHandler.createInternalJobContext());
}
@Override
public void vdsNotResponding(final VDS vds) {
executionHandler.updateSpecificActionJobCompleted(vds.getId(), VdcActionType.MaintenanceVds, false);
ThreadPoolUtil.execute(() -> {
log.info("ResourceManager::vdsNotResponding entered for Host '{}', '{}'",
vds.getId(),
vds.getHostName());
FenceVdsActionParameters params = new FenceVdsActionParameters(vds.getId());
backend.runInternalAction(VdcActionType.VdsNotRespondingTreatment,
params,
ExecutionHandler.createInternalJobContext());
moveBricksToUnknown(vds);
});
}
private void moveBricksToUnknown(final VDS vds) {
List<GlusterBrickEntity> brickEntities =
DbFacade.getInstance().getGlusterBrickDao().getGlusterVolumeBricksByServerId(vds.getId());
for (GlusterBrickEntity brick : brickEntities) {
if (brick.getStatus() == GlusterStatus.UP) {
brick.setStatus(GlusterStatus.UNKNOWN);
}
}
DbFacade.getInstance().getGlusterBrickDao().updateBrickStatuses(brickEntities);
}
@Override
public boolean vdsUpEvent(final VDS vds) {
HostStoragePoolParametersBase params = new HostStoragePoolParametersBase(vds);
boolean isSucceeded = backend.runInternalAction(VdcActionType.InitVdsOnUp, params).getSucceeded();
if (isSucceeded) {
ThreadPoolUtil.execute(() -> {
try {
// migrate vms that its their default vds and failback
// is on
List<VmStatic> vmsToMigrate =
DbFacade.getInstance().getVmStaticDao().getAllWithFailbackByVds(vds.getId());
if (!vmsToMigrate.isEmpty()) {
CommandContext ctx = new CommandContext(new EngineContext());
ctx.getExecutionContext().setMonitored(true);
backend.runInternalMultipleActions(VdcActionType.MigrateVmToServer,
new ArrayList<>(createMigrateVmToServerParametersList(
vmsToMigrate,
vds,
null)),
ctx);
}
} catch (RuntimeException e) {
log.error("Failed to initialize Vds on up: {}", e.getMessage());
log.error("Exception", e);
}
});
}
return isSucceeded;
}
@Override
public boolean connectHostToDomainsInActiveOrUnknownStatus(VDS vds) {
StoragePool sp = storagePoolDao.get(vds.getStoragePoolId());
ConnectHostToStoragePoolServersParameters params =
new ConnectHostToStoragePoolServersParameters(sp, vds, false);
return backend
.runInternalAction(VdcActionType.ConnectHostToStoragePoolServers, params)
.getSucceeded();
}
private List<VdcActionParametersBase> createMigrateVmToServerParametersList(List<VmStatic> vmsToMigrate,
final VDS vds,
String reason) {
return vmsToMigrate.stream().map(
vm -> {
MigrateVmToServerParameters parameters =
new MigrateVmToServerParameters(false, vm.getId(), vds.getId());
parameters.setReason(reason);
parameters.setShouldBeLogged(false);
return parameters;
}).collect(Collectors.toList());
}
@Override
public void processOnCpuFlagsChange(Guid vdsId) {
backend.runInternalAction(VdcActionType.HandleVdsCpuFlagsOrClusterChanged,
new VdsActionParameters(vdsId));
}
@Override
public void handleVdsVersion(Guid vdsId) {
backend.runInternalAction(VdcActionType.HandleVdsVersion, new VdsActionParameters(vdsId));
}
@Override
public void processOnVmPoweringUp(Guid vmId) {
IVdsAsyncCommand command = vdsBroker.getAsyncCommandForVm(vmId);
if (command != null) {
command.onPowerringUp();
}
}
@Override
public void storagePoolUpEvent(StoragePool storagePool) {
CommandCoordinatorUtil.addStoragePoolExistingTasks(storagePool);
}
@Override
public void storagePoolStatusChange(Guid storagePoolId, StoragePoolStatus status, AuditLogType auditLogType,
EngineError error) {
storagePoolStatusChange(storagePoolId, status, auditLogType, error, null);
}
@Override
public void storagePoolStatusChange(Guid storagePoolId, StoragePoolStatus status, AuditLogType auditLogType,
EngineError error, TransactionScopeOption transactionScopeOption) {
SetStoragePoolStatusParameters tempVar =
new SetStoragePoolStatusParameters(storagePoolId, status, auditLogType);
tempVar.setError(error);
if (transactionScopeOption != null) {
tempVar.setTransactionScopeOption(transactionScopeOption);
}
backend.runInternalAction(VdcActionType.SetStoragePoolStatus, tempVar);
}
@Override
public void storagePoolStatusChanged(Guid storagePoolId, StoragePoolStatus status) {
StoragePoolStatusHandler.poolStatusChanged(storagePoolId, status);
}
@Override
public void runFailedAutoStartVMs(List<Guid> vmIds) {
for (Guid vmId : vmIds) {
// Alert that the virtual machine failed:
AuditLogable event = createVmEvent(vmId, AuditLogType.HA_VM_FAILED);
log.info("Highly Available VM went down. Attempting to restart. VM Name '{}', VM Id '{}'",
event.getVmName(), vmId);
}
haAutoStartVmsRunner.addVmsToRun(vmIds);
}
@Override
public void runColdRebootVms(List<Guid> vmIds) {
for (Guid vmId : vmIds) {
AuditLogable event = createVmEvent(vmId, AuditLogType.COLD_REBOOT_VM_DOWN);
log.info("VM is down as a part of cold reboot process. Attempting to restart. VM Name '{}', VM Id '{}",
event.getVmName(), vmId);
}
coldRebootAutoStartVmsRunner.addVmsToRun(vmIds);
}
private AuditLogable createVmEvent(Guid vmId, AuditLogType logType) {
AuditLogable event = new AuditLogableImpl();
event.setVmName(vmStaticDao.get(vmId).getName());
event.setVmId(vmId);
auditLogDirector.log(event, logType);
return event;
}
@Override
public void addUnmanagedVms(Guid hostId, List<Guid> unmanagedVmIds) {
if (!unmanagedVmIds.isEmpty()) {
backend.runInternalAction(
VdcActionType.AddUnmanagedVms,
new AddUnmanagedVmsParameters(hostId, unmanagedVmIds),
ExecutionHandler.createInternalJobContext());
}
}
@Override
public void handleVdsMaintenanceTimeout(Guid vdsId) {
// try to put the host to Maintenance again.
backend.runInternalAction(VdcActionType.MaintenanceNumberOfVdss,
new MaintenanceNumberOfVdssParameters(Arrays.asList(vdsId), true));
}
@Override
public void rerun(Guid vmId) {
final IVdsAsyncCommand command = vdsBroker.getAsyncCommandForVm(vmId);
if (command != null) {
// The command will be invoked in a different VDS in its rerun method, so we're calling
// its rerun method from a new thread so that it won't be executed within our current VDSM lock
ThreadPoolUtil.execute(() -> command.rerun());
}
}
@Override
public void runningSucceded(Guid vmId) {
IVdsAsyncCommand command = vdsBroker.getAsyncCommandForVm(vmId);
if (command != null) {
command.runningSucceded();
}
}
@Override
public void actualDowntimeReported(Guid vmId, int actualDowntime) {
IVdsAsyncCommand command = vdsBroker.getAsyncCommandForVm(vmId);
if (command != null) {
command.actualDowntimeReported(actualDowntime);
}
}
@Override
public void removeAsyncRunningCommand(Guid vmId) {
IVdsAsyncCommand command = vdsBroker.removeAsyncRunningCommand(vmId);
if (command != null) {
command.reportCompleted();
}
}
@Override
public void updateSchedulingStats(VDS vds) {
schedulingManager.updateHostSchedulingStats(vds);
}
@Override
public void updateSlaPolicies(final List<Guid> vmIds, final Guid vdsId) {
if (vmIds.isEmpty()) {
return;
}
ThreadPoolUtil.execute(() -> {
// Get Disks and CpuQos of VMs from the DB
Map<Guid, List<Disk>> diskMap = diskDao.getAllForVms(vmIds);
Map<Guid, CpuQos> cpuQosMap = cpuQosDao.getCpuQosByVmIds(vmIds);
Map<Guid, List<DiskImage>> diskImageMap = new HashMap<>();
Set<Guid> diskProfileIds = new HashSet<>();
for (Guid vmId : vmIds) {
// Filter - only plugged disk images with disk profile remain
List<DiskImage> diskImages = diskMap.get(vmId).stream()
.filter(disk -> disk.getPlugged() && disk.getDiskStorageType() == DiskStorageType.IMAGE)
.map(DiskImage.class::cast)
.filter(disk -> disk.getDiskProfileId() != null)
.collect(Collectors.toList());
diskImageMap.put(vmId, diskImages);
for (DiskImage img : diskImages) {
diskProfileIds.add(img.getDiskProfileId());
}
}
// Get StorageQos of used disk profiles
Map<Guid, StorageQos> storageQosMap = storageQosDao.getQosByDiskProfileIds(diskProfileIds);
// Call VmSlaPolicyCommand for each VM
for (Guid vmId : vmIds) {
CpuQos cpuQos = cpuQosMap.get(vmId);
VmSlaPolicyParameters params = new VmSlaPolicyParameters(vmId, cpuQos);
for (DiskImage diskImage : diskImageMap.get(vmId)) {
Guid diskProfileId = diskImage.getDiskProfileId();
StorageQos storageQos = storageQosMap.get(diskProfileId);
if(storageQos != null) {
params.getStorageQos().put(diskImage, storageQos);
}
}
if (!params.isEmpty()) {
backend.runInternalAction(VdcActionType.VmSlaPolicy, params);
}
}
});
}
public void onError(@Observes final VDSNetworkException vdsException) {
ThreadPoolUtil.execute(() -> resourceManagerProvider.get().getVdsManager(
vdsException.getVdsError().getVdsId()).handleNetworkException(vdsException));
}
@Override
public void refreshHostIfAnyVmHasHostDevices(final List<Guid> vmIds, final Guid hostId) {
if (vmIds.isEmpty()) {
return;
}
ThreadPoolUtil.execute(() -> {
HostDeviceManager hostDeviceManager = Injector.get(HostDeviceManager.class);
hostDeviceManager.refreshHostIfAnyVmHasHostDevices(vmIds, hostId);
});
}
@Override
public void refreshHostCapabilities(Guid hostId) {
backend.runInternalAction(VdcActionType.RefreshHostCapabilities, new VdsActionParameters(hostId));
}
// TODO asynch event handler - design infra code to allow async events in segregated thread
public void onMomPolicyChange(@Observes @MomPolicyUpdate final Cluster cluster) {
if (cluster == null) {
return;
}
List<VDS> activeHostsInCluster =
vdsDao.getAllForClusterWithStatus(cluster.getId(), VDSStatus.Up);
// collect all Active hosts into a callable list
List<Callable<Object>> callables = new LinkedList<>();
for (final VDS vds : activeHostsInCluster) {
callables.add(() -> {
try {
resourceManagerProvider.get().runVdsCommand(VDSCommandType.SetMOMPolicyParameters,
new MomPolicyVDSParameters(vds,
cluster.isEnableBallooning(),
cluster.isEnableKsm(),
cluster.isKsmMergeAcrossNumaNodes())
);
} catch (EngineException e) {
log.error("Could not update MoM policy on host '{}'", vds.getName());
}
return null;
});
}
// run all VDSCommands concurrently with executor
if (callables.size() > 0) {
ThreadPoolUtil.invokeAll(callables);
}
}
@Override
public void importHostedEngineVm(final VM vm) {
ThreadPoolUtil.execute(() -> hostedEngineImporterProvider.get().doImport(vm));
}
@Override
public void restartVmsWithLease(List<Guid> vmIds) {
if (vmIds.isEmpty()) {
return;
}
EngineLock engineLock = new EngineLock(Collections.emptyMap(), Collections.emptyMap());
ThreadPoolUtil.execute(() -> {
for (Guid vmId : vmIds) {
resourceManagerProvider.get().removeAsyncRunningVm(vmId);
backend.runInternalAction(
VdcActionType.RunVm,
buildRunVmParameters(vmId),
ExecutionHandler.createInternalJobContext(engineLock));
}
});
}
private RunVmParams buildRunVmParameters(Guid vmId) {
RunVmParams parameters = new RunVmParams(vmId);
parameters.setRunInUnknownStatus(true);
return parameters;
}
}