package org.ovirt.engine.core.vdsbroker.vdsbroker; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; import org.ovirt.engine.core.common.businessentities.AsyncTaskStatus; import org.ovirt.engine.core.common.businessentities.VDSStatus; import org.ovirt.engine.core.common.errors.EngineError; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.errors.VDSError; import org.ovirt.engine.core.common.locks.LockingGroup; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.common.vdscommands.SpmStopVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; import org.ovirt.engine.core.common.vdscommands.VdsIdVDSCommandParametersBase; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.utils.lock.EngineLock; import org.ovirt.engine.core.utils.lock.LockManager; public class SpmStopVDSCommand<P extends SpmStopVDSCommandParameters> extends VdsBrokerCommand<P> { @Inject private LockManager lockManager; private EngineLock lock; public SpmStopVDSCommand(P parameters) { super(parameters, DbFacade.getInstance().getVdsDao().get(parameters.getVdsId())); } private EngineLock retrieveVdsExecutionLock() { if (lock == null) { Map<String, Pair<String, String>> exsluciveLock = Collections.singletonMap(getParameters().getVdsId().toString(), new Pair<>(LockingGroup.VDS_EXECUTION.toString(), EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED.toString())); lock = new EngineLock(exsluciveLock, null); } return lock; } @Override protected void executeVdsBrokerCommand() { boolean lockAcquired = false; try { if (canVdsBeReached()) { lockAcquired = lockManager.acquireLock(retrieveVdsExecutionLock()).getFirst(); if (!lockAcquired) { getVDSReturnValue().setVdsError(new VDSError(EngineError.ENGINE, "Failed to acquire vds execution lock - related operation is under execution")); getVDSReturnValue().setSucceeded(false); return; } boolean performSpmStop = true; try { VDSReturnValue vdsReturnValue = resourceManager .runVdsCommand(VDSCommandType.HSMGetAllTasksStatuses, new VdsIdVDSCommandParametersBase(getVds().getId())); if (isNotSPM(vdsReturnValue)) { return; } getVDSReturnValue().setSucceeded(vdsReturnValue.getSucceeded()); getVDSReturnValue().setVdsError(vdsReturnValue.getVdsError()); if (vdsReturnValue.getReturnValue() != null) { performSpmStop = ((HashMap<Guid, AsyncTaskStatus>) vdsReturnValue.getReturnValue()).isEmpty(); } } catch (Exception e) { performSpmStop = false; log.info("SpmStopVDSCommand::Could not get tasks on vds '{}': {}", getVds().getName(), e.getMessage()); log.debug("Exception", e); } if (performSpmStop) { log.info("SpmStopVDSCommand::Stopping SPM on vds '{}', pool id '{}'", getVds().getName(), getParameters().getStoragePoolId()); status = getBroker().spmStop(getParameters().getStoragePoolId().toString()); proceedProxyReturnValue(); } else { getVDSReturnValue().setSucceeded(false); if (getVDSReturnValue().getVdsError() == null) { log.info("SpmStopVDSCommand::Not stopping SPM on vds '{}', pool id '{}' as there are uncleared tasks", getVds().getName(), getParameters().getStoragePoolId()); VDSError error = new VDSError(); error.setCode(EngineError.TaskInProgress); getVDSReturnValue().setVdsError(error); } else if (getVDSReturnValue().getVdsError().getCode() == EngineError.VDS_NETWORK_ERROR) { log.info( "SpmStopVDSCommand::Could not get tasks on vds '{}' - network exception, not stopping spm! pool id '{}'", getVds().getName(), getParameters().getStoragePoolId()); } } } else { log.info("SpmStopVDSCommand:: vds '{}' is in '{}' status - not performing spm stop, pool id '{}'", getVds().getName(), getVds().getStatus(), getParameters().getStoragePoolId()); getVDSReturnValue().setVdsError(new VDSError(EngineError.VDS_NETWORK_ERROR, "Vds is in incorrect status")); getVDSReturnValue().setSucceeded(false); } } catch (RuntimeException exp) { log.warn("Could not stop spm of pool '{}' on vds '{}': {}", getParameters() .getStoragePoolId(), getParameters().getVdsId(), exp.getMessage()); log.debug("Exception", exp); getVDSReturnValue().setExceptionObject(exp); getVDSReturnValue().setSucceeded(false); } finally { if (lockAcquired) { lockManager.releaseLock(retrieveVdsExecutionLock()); } } } /** * Checks if the VDS is in a state where it can be reached or not, since if it can't be reached we don't want to * try to stop the SPM because the command won't work. * @return Can the VDS be reached or not? */ private boolean canVdsBeReached() { VDSStatus vdsStatus = getVds().getStatus(); if (vdsStatus == VDSStatus.Down || vdsStatus == VDSStatus.Reboot || vdsStatus == VDSStatus.Kdumping) { vdsStatus = getVds().getPreviousStatus(); } return vdsStatus != VDSStatus.NonResponsive && getVds().getStatus() != VDSStatus.Connecting; } private boolean isNotSPM(VDSReturnValue returnValue) { return returnValue.getVdsError() != null && returnValue.getVdsError().getCode() == EngineError.SpmStatusError; } @Override protected void proceedProxyReturnValue() { EngineError returnStatus = getReturnValueFromStatus(getReturnStatus()); switch (returnStatus) { case StoragePoolUnknown: case SpmStatusError: // ignore this, the parser can handle the empty result. break; case TaskInProgress: getVDSReturnValue().setVdsError(new VDSError(returnStatus, getReturnStatus().message)); getVDSReturnValue().setSucceeded(false); break; default: super.proceedProxyReturnValue(); initializeVdsError(returnStatus); break; } } }