package org.ovirt.engine.core.bll;
import java.util.Date;
import java.util.LinkedList;
import java.util.Queue;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.action.FenceVdsActionParameters;
import org.ovirt.engine.core.common.action.MaintananceNumberOfVdssParameters;
import org.ovirt.engine.core.common.action.SetStoragePoolStatusParameters;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.businessentities.StoragePoolStatus;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.VdsSpmStatus;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.vdscommands.SetVmStatusVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.compat.DateTime;
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.dal.dbbroker.auditloghandling.AuditLogDirector;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase;
public class VdsNotRespondingTreatmentCommand<T extends FenceVdsActionParameters> extends RestartVdsCommand<T> {
private static Queue<Date> mFencingAttempts = new LinkedList<Date>();
/**
* use this member to determine if fencing failed but vms moved to unknown mode (for the audit log type)
*/
private boolean _vmsMovedToUnknown;
public VdsNotRespondingTreatmentCommand(T parameters) {
super(parameters);
}
/**
* Create an executor which retries to find a proxy, since this command is automatic and we don't want it to fail
* fast if no proxy is available, but to try a few times.
*
* @return The executor, which is used to check if a proxy is available for fencing the host.
*/
@Override
protected FencingExecutor createExecutorForProxyCheck() {
return new FencingExecutor(getVds(), getParameters().getAction());
}
/**
* Only fence the host if the VDS is down, otherwise it might have gone back up until this command was executed. If
* the VDS is not fenced then don't send an audit log event.
*/
@Override
protected void executeCommand() {
setVds(null);
if (getVds() != null && shouldVdsBeFenced()) {
super.executeCommand();
} else {
setCommandShouldBeLogged(false);
log.infoFormat("Not fencing host {0}({1}) since it's status is ok, or it doesn't exist anymore.",
getVdsName(), getVdsId());
}
}
@Override
protected void setStatus() {
}
@Override
protected void HandleError() {
final String RESTART = "Restart";
MoveVMsToUnknown();
// if fencing failed on spm, move storage pool to non operational
if (getVds().getspm_status() != VdsSpmStatus.None) {
log.infoFormat("Fence failed on vds {0} which is spm of pool {1} - moving pool to non operational",
getVds().getvds_name(), getVds().getstorage_pool_id());
Backend.getInstance().runInternalAction(
VdcActionType.SetStoragePoolStatus,
new SetStoragePoolStatusParameters(getVds().getstorage_pool_id(), StoragePoolStatus.NotOperational,
AuditLogType.SYSTEM_CHANGE_STORAGE_POOL_STATUS_NO_HOST_FOR_SPM));
}
_vmsMovedToUnknown = true;
log.errorFormat("Failed to run Fence script on vds:{0}, VMs moved to UnKnown instead.", getVdsName());
if (!getVds().getpm_enabled()) {
AlertIfPowerManagementOperationSkipped(RESTART);
}
}
@Override
public AuditLogType getAuditLogTypeValue() {
return getSucceeded() ? _vmsMovedToUnknown ? AuditLogType.VDS_RECOVER_FAILED_VMS_UNKNOWN
: AuditLogType.VDS_RECOVER : AuditLogType.VDS_RECOVER_FAILED;
}
/**
* Determine if the status is legal for actually fencing the VDS.
*
* @return <c>true</c> if the VDS should be fenced, otherwise <c>false</c>.
*/
private boolean shouldVdsBeFenced() {
boolean result;
switch (getVds().getstatus()) {
case Down:
case InstallFailed:
case Maintenance:
case NonOperational:
case NonResponsive:
result = true;
break;
default:
result = false;
break;
}
return result;
}
private boolean fenceVds() {
mFencingAttempts.offer(new java.util.Date());
java.util.Date timeOutAgo = DateTime.getNow().AddSeconds(
-1 * Config.<Integer> GetValue(ConfigValues.VdsFailTimeout));
while (mFencingAttempts.size() > 0 && mFencingAttempts.peek().before(timeOutAgo)) {
mFencingAttempts.poll();
}
if (mFencingAttempts.size() > 3) {
// mark vds as maintenens
java.util.ArrayList<Guid> list = new java.util.ArrayList<Guid>();
list.add(getVdsId());
// Backend.getInstance().vdsMaintenance(list);
Backend.getInstance().runInternalAction(VdcActionType.MaintananceNumberOfVdss,
new MaintananceNumberOfVdssParameters(list, false));
return false;
}
return true;
}
private void MoveVMsToUnknown() {
for (VM vm : getVmList()) {
DestroyVmOnDestination(vm);
Backend.getInstance()
.getResourceManager()
.RunVdsCommand(VDSCommandType.SetVmStatus,
new SetVmStatusVDSCommandParameters(vm.getvm_guid(), 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);
}
}
private static LogCompat log = LogFactoryCompat.getLog(VdsNotRespondingTreatmentCommand.class);
}