package org.ovirt.engine.core.vdsbroker;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.businessentities.IVdsEventListener;
import org.ovirt.engine.core.common.businessentities.NetworkStatistics;
import org.ovirt.engine.core.common.businessentities.NonOperationalReason;
import org.ovirt.engine.core.common.businessentities.StoragePoolStatus;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VDSDomainsData;
import org.ovirt.engine.core.common.businessentities.VDSStatus;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.VdsDynamic;
import org.ovirt.engine.core.common.businessentities.VdsStatistics;
import org.ovirt.engine.core.common.businessentities.VmNetworkInterface;
import org.ovirt.engine.core.common.businessentities.VmNetworkStatistics;
import org.ovirt.engine.core.common.businessentities.VmPauseStatus;
import org.ovirt.engine.core.common.businessentities.storage_pool;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.errors.VdcBllErrors;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.common.vdscommands.VDSParametersBase;
import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.LogCompat;
import org.ovirt.engine.core.compat.LogFactoryCompat;
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.AuditLogableBase;
import org.ovirt.engine.core.utils.ReflectionUtils;
import org.ovirt.engine.core.utils.ThreadUtils;
import org.ovirt.engine.core.utils.ejb.BeanProxyType;
import org.ovirt.engine.core.utils.ejb.BeanType;
import org.ovirt.engine.core.utils.ejb.EjbUtils;
import org.ovirt.engine.core.vdsbroker.irsbroker.IrsBrokerCommand;
public class ResourceManager implements IVdsEventListener {
private static LogCompat log = LogFactoryCompat.getLog(ResourceManager.class);
private static ResourceManager _Instance = new ResourceManager();
public static ResourceManager getInstance() {
return _Instance;
}
private ResourceManager() {
log.info("ResourceManager::ResourceManager::Entered");
List<VDS> allVdsList = DbFacade.getInstance().getVdsDAO().getAll();
// get all vds_id of non responsive vds
// LINQ 29456 fixed
// HashSet<int> nonResponsiveVdss = new HashSet<int>(
// allVdsList.Where<VDS>(a => a.status ==
// VDSStatus.NonResponsive).Select<VDS, int>(a => a.vds_id));
java.util.HashSet<Guid> nonResponsiveVdss = new java.util.HashSet<Guid>(); // LINQ
// 29456
// fix
for (VDS helper_vds : allVdsList) // LINQ 29456 fix
{ // LINQ 29456 fix
if (helper_vds.getstatus() == VDSStatus.NonResponsive) // LINQ 29456
// fix
{
nonResponsiveVdss.add(helper_vds.getvds_id()); // LINQ 29456 fix
}
} // LINQ 29456 fix
// Cleanup all vms dynamic data. This is defencive code on power crash
List<VM> vms = DbFacade.getInstance().getVmDAO().getAll();
for (VM vm : vms) {
if (!VM.isStatusDown(vm.getstatus())) {
// check if vm should be suspended
if (vm.getstatus() == VMStatus.SavingState) {
InternalSetVmStatus(vm, VMStatus.Suspended);
DbFacade.getInstance().getVmDynamicDAO().update(vm.getDynamicData());
DbFacade.getInstance().getVmStatisticsDAO().update(vm.getStatisticsData());
} else {
if (vm.getrun_on_vds() != null) {
java.util.HashSet<Guid> vmsList = null;
// if vmsList == null
if (!((vmsList = _vdsAndVmsList.get(vm.getrun_on_vds())) != null)) {
vmsList = new java.util.HashSet<Guid>();
}
vmsList.add(vm.getvm_guid());
_vdsAndVmsList.put(new Guid(vm.getrun_on_vds().toString()), vmsList);
}
if (vm.getrun_on_vds() != null && nonResponsiveVdss.contains(vm.getrun_on_vds())) {
SetVmUnknown(vm);
}
}
}
}
if (allVdsList.size() > 0) {
int sleepTimout = Config.<Integer> GetValue(ConfigValues.VdsRefreshRate)
* Config.<Integer> GetValue(ConfigValues.NumberVmRefreshesBeforeSave) * 1000 / allVdsList.size();
// Populate the VDS dictionary
for (VDS curVds : allVdsList) {
log.debugFormat("Putting thread to sleep for {0} milliseconds before adding VDS {1}, with name {2}",
sleepTimout, curVds.getvds_id(), curVds.getvds_name());
ThreadUtils.sleep(sleepTimout);
AddVds(curVds, true);
}
}
IrsBrokerCommand.Init();
}
private final java.util.HashMap<Guid, java.util.HashSet<Guid>> _vdsAndVmsList =
new java.util.HashMap<Guid, java.util.HashSet<Guid>>();
private final java.util.Map<Guid, VdsManager> _vdsManagersDict = new ConcurrentHashMap<Guid, VdsManager>();
private final ConcurrentHashMap<Guid, IVdsEventListener> _asyncRunningVms =
new ConcurrentHashMap<Guid, IVdsEventListener>();
public boolean AddAsyncRunningVm(Guid vmId, IVdsEventListener listener) {
boolean returnValue = false;
if (_asyncRunningVms.putIfAbsent(vmId, listener) == null) {
returnValue = true;
}
return returnValue;
}
public void RemoveAsyncRunningVm(Guid vmId) {
_asyncRunningVms.remove(vmId);
getEventListener().RemoveAsyncRunningCommand(vmId);
}
public void SuccededToRunVm(Guid vmId, Guid vdsId) {
IVdsEventListener listener = _asyncRunningVms.get(vmId);
if (listener != null) {
listener.RunningSucceded(vmId);
}
RemoveAsyncRunningVm(vmId);
}
/**
* Initiate rerun event when vm failed to run
*
* @param vmId
*/
public void RerunFailedCommand(Guid vmId, Guid vdsId) {
IVdsEventListener listener = _asyncRunningVms.remove(vmId);
// remove async record from broker only
if (listener != null) {
listener.Rerun(vmId);
}
}
public boolean IsVmInAsyncRunningList(Guid vmId) {
return (_asyncRunningVms.containsKey(vmId));
}
public void RemoveVmFromDownVms(Guid vdsId, Guid vmId) {
java.util.HashSet<Guid> vms = null;
if ((vms = _vdsAndVmsList.get(vdsId)) != null) {
vms.remove(vmId);
}
}
public void HandleVdsFinishedInit(Guid vdsId) {
java.util.HashSet<Guid> vms = null;
if ((vms = _vdsAndVmsList.get(vdsId)) != null) {
for (Guid vmId : vms) {
getEventListener().ProcessOnVmStop(vmId);
log.info("Procceed on vm stop entered: " + vmId.toString());
}
_vdsAndVmsList.remove(vdsId);
}
}
// if no event listener, return this (no implementation)
public IVdsEventListener getEventListener() {
IVdsEventListener eventListener = EjbUtils.findBean(BeanType.VDS_EVENT_LISTENER, BeanProxyType.LOCAL);
if (eventListener != null) {
return eventListener;
} else {
return this;
}
}
/**
* This will return the EventListener from WCF Callback Channel if exists or the EventListener if not
*/
public IVdsEventListener getBackendCallback() {
return getEventListener();
}
public void AddVds(VDS vds, boolean isInternal) {
VdsManager vdsManager = VdsManager.buildVdsManager(vds);
if (isInternal) {
VDSStatus status = vds.getstatus();
switch (vds.getstatus()) {
case Error:
status = VDSStatus.Up;
break;
case Reboot:
case NonResponsive:
case Problematic:
case Installing:
status = VDSStatus.Unassigned;
break;
}
if (status != vds.getstatus()) {
vdsManager.setStatus(status, vds);
vdsManager.UpdateStatisticsData(vds.getStatisticsData());
}
// set pending to 0
vds.setpending_vcpus_count(0);
vdsManager.UpdateDynamicData(vds.getDynamicData());
}
_vdsManagersDict.put(vds.getvds_id(), vdsManager);
log.infoFormat("ResourceManager::AddVds - VDS {0} was added to the Resource Manager", vds.getvds_id());
}
public void RemoveVds(Guid vdsId) {
VdsManager vdsManager = GetVdsManager(vdsId);
if (vdsManager != null) {
vdsManager.dispose();
_vdsManagersDict.remove(vdsId);
}
}
public VdsManager GetVdsManager(Guid vdsId) {
if (_vdsManagersDict.containsKey(vdsId)) {
return _vdsManagersDict.get(vdsId);
} else {
log.errorFormat("Cannot get vdsManager for vdsid={0}", vdsId);
}
return null;
}
/**
* Set vm status to DOWN and save to DB.
*
* @param vm
*/
public void SetVmUnknown(VM vm) {
RemoveAsyncRunningVm(vm.getvm_guid());
InternalSetVmStatus(vm, VMStatus.Unknown);
// log VM transition to unknown status
AuditLogableBase logable = new AuditLogableBase();
logable.setVmId(vm.getvm_guid());
AuditLogDirector.log(logable, AuditLogType.VM_SET_TO_UNKNOWN_STATUS);
storeVm(vm);
}
private void storeVm(VM vm) {
DbFacade.getInstance().getVmDynamicDAO().update(vm.getDynamicData());
DbFacade.getInstance().getVmStatisticsDAO().update(vm.getStatisticsData());
List<VmNetworkInterface> interfaces = vm.getInterfaces();
if (interfaces != null) {
for (VmNetworkInterface ifc : interfaces) {
VmNetworkStatistics stats = ifc.getStatistics();
DbFacade.getInstance().getVmNetworkStatisticsDAO().update(stats);
}
}
}
public void SetVmDown(VM vm) {
RemoveAsyncRunningVm(vm.getvm_guid());
InternalSetVmStatus(vm, VMStatus.Down);
storeVm(vm);
}
public boolean IsVmDuringInitiating(Guid vm_guid) {
return _asyncRunningVms.containsKey(vm_guid);
}
/**
* Set vm status without saving to DB
*
* @param vm
* @param status
*/
public void InternalSetVmStatus(VM vm, VMStatus status) {
vm.setstatus(status);
VMStatus vmStatus = vm.getstatus();
boolean isVmStatusDown = VM.isStatusDown(vmStatus);
if (isVmStatusDown || vmStatus == VMStatus.Unknown) {
resetVmAttributes(vm);
if (isVmStatusDown) {
vm.setrun_on_vds(null);
vm.setVmPauseStatus(VmPauseStatus.NONE);
}
}
}
/**
* Resets VM attributes
* @param vm
* the VM to reset
*/
private void resetVmAttributes(VM vm) {
vm.setusage_network_percent(0);
vm.setelapsed_time(Double.valueOf(0));
vm.setcpu_sys(new Double(0));
vm.setcpu_user(new Double(0));
vm.setusage_cpu_percent(0);
vm.setusage_mem_percent(0);
vm.setmigrating_to_vds(null);
vm.setrun_on_vds_name("");
vm.setguest_cur_user_name(null);
vm.setguest_os(null);
vm.setvm_ip(null);
List<VmNetworkInterface> interfaces = vm.getInterfaces();
for (VmNetworkInterface ifc : interfaces) {
NetworkStatistics statistics = ifc.getStatistics();
statistics.setTransmitDropRate(new Double(0));
statistics.setTransmitRate(new Double(0));
statistics.setReceiveRate(new Double(0));
statistics.setReceiveDropRate(new Double(0));
}
}
public void UpdateVdsDynamicData(VdsDynamic vdsDynamic) {
VdsManager vdsManager = GetVdsManager(vdsDynamic.getId());
if (vdsManager != null) {
vdsManager.UpdateDynamicData(vdsDynamic);
}
}
public void UpdateVdsStatisticsData(VdsStatistics vdsStatistics) {
VdsManager vdsManager = GetVdsManager(vdsStatistics.getId());
if (vdsManager != null) {
vdsManager.UpdateStatisticsData(vdsStatistics);
}
}
private static final String VDSCommandPrefix = "VDSCommand";
private static String GetCommandTypeName(VDSCommandType command) {
String packageName = command.getPackageName();
String commandName = String.format("%s.%s%s", packageName, command, VDSCommandPrefix);
return commandName;
}
/**
* Create the command which needs to run.
*
* @param <P>
* @param commandType
* @param parameters
* @return The command, or null if it can't be created.
*/
private <P extends VDSParametersBase> VDSCommandBase<P> CreateCommand(
VDSCommandType commandType, P parameters) {
try {
@SuppressWarnings("unchecked")
Class<VDSCommandBase<P>> type =
(Class<VDSCommandBase<P>>) java.lang.Class.forName(GetCommandTypeName(commandType));
Constructor<VDSCommandBase<P>> constructor =
ReflectionUtils.findConstructor(type, parameters.getClass());
if (constructor != null) {
return constructor.newInstance(new Object[] { parameters });
}
} catch (InvocationTargetException e) {
if (e.getCause() != null) {
log.debug("CreateCommand failed", e.getCause());
throw new RuntimeException(e.getCause().getMessage(), e.getCause());
}
log.debug("CreateCommand failed", e);
} catch (java.lang.Exception e) {
log.debug("CreateCommand failed", e);
}
return null;
}
public <P extends VDSParametersBase> VDSReturnValue runVdsCommand(VDSCommandType commandType, P parameters) {
// try run vds command
VDSCommandBase<P> command = CreateCommand(commandType, parameters);
if (command != null) {
command.Execute();
return command.getVDSReturnValue();
}
return null;
}
/**
* implement this interface with blank methods just in case no event listener is sent from frontend
*
* @param vds
*/
@Override
public void VdsNotResponding(VDS vds) {
log.info("ResourceManager:vdsNotResponding - no event listener defined, nothing done.");
}
@Override
public void VdsNonOperational(Guid vdsId, NonOperationalReason reason, boolean logCommand, boolean saveToDb,
Guid domainId) {
log.info("ResourceManager:vdsMaintanance - no event listener defined, nothing done.");
}
@Override
public void VdsMovedToMaintanance(Guid vdsId) {
log.info("ResourceManager:VdsMovedToMaintanance - no event listener defined, nothing done.");
}
@Override
public void StorageDomainNotOperational(Guid storageDomainId, Guid storagePoolId) {
log.info("ResourceManager:StorageDomainOperational - no event listener defined, nothing done.");
}
@Override
public void MasterDomainNotOperational(Guid storageDomainId, Guid storagePoolId) {
log.info("ResourceManager:MasterDomainNotOperational - no event listener defined, nothing done.");
}
@Override
public void ProcessOnVmStop(Guid vmId) {
log.info("ResourceManager:ProcessOnVmStop - no event listener defined, nothing done.");
}
@Override
public void VdsUpEvent(Guid vdsId) {
log.info("ResourceManager:RunDedicatedVm - no event listener defined, nothing done.");
}
@Override
public void ProcessOnClientIpChange(VDS vds, Guid vmId) {
log.info("ResourceManager:ProcessOnClientIpChange - no event listener defined, nothing done.");
}
@Override
public void ProcessOnCpuFlagsChange(Guid vdsId) {
log.info("ResourceManager:ProcessOnCpuFlagsChange - no event listener defined, nothing done.");
}
@Override
public void Rerun(Guid VmId) {
log.info("ResourceManager:Rerun - no event listener defined, nothing done.");
}
@Override
public void RunningSucceded(Guid vmId) {
log.info("ResourceManager:RunningSucceded - no event listener defined, nothing done.");
}
@Override
public void ProcessOnVmPoweringUp(Guid vds_id, Guid vmid, String display_ip, int display_port) {
log.info("ResourceManager:ProcessOnVmPoweringUp - no event listener defined, nothing done.");
}
@Override
public void RemoveAsyncRunningCommand(Guid vmId) {
log.info("ResourceManager:RemoveAsyncRunningCommand - no event listener defined, nothing done.");
}
@Override
public void StoragePoolUpEvent(storage_pool storagePool, boolean isSpmStarted) {
log.info("ResourceManager:StoragePoolUpEvent - no event listener defined, nothing done.");
}
@Override
public void StoragePoolStatusChange(Guid storagePoolId, StoragePoolStatus status, AuditLogType auditLogType,
VdcBllErrors error, TransactionScopeOption transactionScopeOption) {
log.info("ResourceManager:StoragePoolStatusChange - no event listener defined, nothing done.");
}
@Override
public void StoragePoolStatusChange(Guid storagePoolId, StoragePoolStatus status, AuditLogType auditLogType,
VdcBllErrors error) {
log.info("ResourceManager:StoragePoolStatusChange - no event listener defined, nothing done.");
}
@Override
public void StoragePoolStatusChanged(Guid storagePoolId, StoragePoolStatus status) {
log.info("ResourceManager:StoragePoolStatusChange - no event listener defined, nothing done.");
}
@Override
public void RunFailedAutoStartVM(Guid vmId) {
log.info("ResourceManager:RunFailedAutoStartVM - no event listener defined, nothing done.");
}
@Override
public boolean RestartVds(Guid vdsId) {
log.info("ResourceManager:RestartVds - no event listener defined, nothing done.");
return false;
}
public void UpdateVdsDomainsData(Guid vdsId, String vdsName, Guid storagePoolId,
java.util.ArrayList<VDSDomainsData> vdsDomainData) {
IrsBrokerCommand.UpdateVdsDomainsData(vdsId, vdsName, storagePoolId, vdsDomainData);
}
public boolean isDomainReportedInProblem(Guid storagePoolId, Guid domainId) {
return IrsBrokerCommand.isDomainReportedInProblem(storagePoolId, domainId);
}
}