package org.ovirt.engine.core.bll.hostdeploy; import java.util.List; import org.ovirt.engine.core.bll.CommandBase; import org.ovirt.engine.core.bll.tasks.CommandCoordinatorUtil; import org.ovirt.engine.core.bll.tasks.interfaces.CommandCallback; import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.hostdeploy.UpgradeHostParameters; import org.ovirt.engine.core.common.businessentities.CommandEntity; import org.ovirt.engine.core.common.businessentities.VdsDynamic; import org.ovirt.engine.core.common.businessentities.VdsStatic; import org.ovirt.engine.core.compat.CommandStatus; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * {@code HostUpgradeCallback} monitors the transition of the host to maintenance status. Once the host is on * maintenance mode, the callback invokes the {@code UpgradeHostInternalCommand} for upgrading the host in async way. * The {@code UpgradeHostInternalCommand} is being monitored by this callback to its completion. */ public class HostUpgradeCallback implements CommandCallback { private static final Logger log = LoggerFactory.getLogger(HostUpgradeCallback.class); private String hostName; private Guid maintenanceCmdId; private Guid hostUpgradeInternalCmdId; /** * The callback is being polling till the host move to maintenance or failed to do so. */ @Override public void doPolling(Guid cmdId, List<Guid> childCmdIds) { CommandBase<?> rootCommand = CommandCoordinatorUtil.retrieveCommand(cmdId); // If there are child commands and the host upgrade process was started, check the status of the host // upgrade command. if (childCommandsExist(childCmdIds) && evaluateHostUpgradeInternalCommandProgress(childCmdIds, rootCommand)) { return; } // if the host upgrade command was not started check the status of maintenance command if (Guid.isNullOrEmpty(getHostUpgradeInternalCmdId(childCmdIds))) { evaluateMaintenanceHostCommandProgress(childCmdIds, rootCommand); } } @Override public void onFailed(Guid cmdId, List<Guid> childCmdIds) { CommandCoordinatorUtil.removeAllCommandsInHierarchy(cmdId); } @Override public void onSucceeded(Guid cmdId, List<Guid> childCmdIds) { CommandCoordinatorUtil.removeAllCommandsInHierarchy(cmdId); } /** * Evaluates the host status in regards to maintenance status: The host must move to {@code VDSStatus.Maintenance} * in order to proceed with the upgrade process. * * @param childCmdIds * child command IDs list to search if {@code MaintenanceNumberOfVdss} exists in it * @param rootCommand * The root command */ private void evaluateMaintenanceHostCommandProgress(List<Guid> childCmdIds, CommandBase<?> rootCommand) { UpgradeHostParameters parameters = (UpgradeHostParameters) rootCommand.getParameters(); VdsDynamic host = DbFacade.getInstance().getVdsDynamicDao().get(parameters.getVdsId()); switch (host.getStatus()) { // Wait till moving to maintenance ends case PreparingForMaintenance: break; // Invoke the upgrade action case Maintenance: log.info("Host '{}' is on maintenance mode. Proceeding with Upgrade process.", getHostName(parameters.getVdsId())); invokeHostUpgrade(rootCommand, parameters); break; // Any other status implies maintenance action failed, and the callback cannot proceed with the upgrade default: if (isMaintenanceCommandExecuted(childCmdIds)) { log.error("Host '{}' failed to move to maintenance mode. Upgrade process is terminated.", getHostName(parameters.getVdsId())); rootCommand.setCommandStatus(CommandStatus.FAILED); } break; } } /** * Evaluates the progress of the {@code UpgradeHostInternalCommand} and updates root command status accordingly * * @param childCmdIds * The child command IDs list to search if {@code UpgradeHostInternalCommand} exists in it * @param rootCommand * The root command * @return returns {@code true} if command execution has ended, else {@code false} */ private boolean evaluateHostUpgradeInternalCommandProgress(List<Guid> childCmdIds, CommandBase<?> rootCommand) { CommandEntity upgradeCommand = getHostUpgradeInternalCommand(childCmdIds); if (upgradeCommand == null) { return false; } // upgrade command execution has started and its status should be examined switch (upgradeCommand.getCommandStatus()) { case ACTIVE: case NOT_STARTED: return false; case FAILED: case EXECUTION_FAILED: case ENDED_WITH_FAILURE: case UNKNOWN: rootCommand.setCommandStatus(CommandStatus.FAILED); return true; case SUCCEEDED: case ENDED_SUCCESSFULLY: rootCommand.setCommandStatus(CommandStatus.SUCCEEDED); return true; } return true; } private CommandEntity getHostUpgradeInternalCommand(List<Guid> childCmdIds) { Guid upgradeCmdId = getHostUpgradeInternalCmdId(childCmdIds); return CommandCoordinatorUtil.getCommandEntity(upgradeCmdId); } private void invokeHostUpgrade(CommandBase<?> command, UpgradeHostParameters parameters) { CommandCoordinatorUtil.executeAsyncCommand(VdcActionType.UpgradeHostInternal, createUpgradeParameters(parameters), command.cloneContextAndDetachFromParent()); } private VdcActionParametersBase createUpgradeParameters(UpgradeHostParameters parameters) { UpgradeHostParameters upgradeParams = new UpgradeHostParameters(parameters.getVdsId()); upgradeParams.setSessionId(parameters.getSessionId()); upgradeParams.setCorrelationId(parameters.getCorrelationId()); upgradeParams.setInitialStatus(parameters.getInitialStatus()); upgradeParams.setoVirtIsoFile(parameters.getoVirtIsoFile()); upgradeParams.setParentCommand(VdcActionType.UpgradeHost); upgradeParams.setParentParameters(parameters); return upgradeParams; } private boolean isMaintenanceCommandExecuted(List<Guid> childCmdIds) { Guid maintenanceCommandId = getMaintenanceCmdId(childCmdIds); CommandEntity maintenanceCmd = CommandCoordinatorUtil.getCommandEntity(maintenanceCommandId); return maintenanceCmd != null && maintenanceCmd.isExecuted(); } private String getHostName(Guid hostId) { if (hostName == null) { VdsStatic host = DbFacade.getInstance().getVdsStaticDao().get(hostId); hostName = host == null ? null : host.getName(); } return hostName; } private Guid getHostUpgradeInternalCmdId(List<Guid> childCmdIds) { if (hostUpgradeInternalCmdId == null) { hostUpgradeInternalCmdId = findChildCommandByActionType(VdcActionType.UpgradeHostInternal, childCmdIds); } return hostUpgradeInternalCmdId; } private Guid getMaintenanceCmdId(List<Guid> childCmdIds) { if (maintenanceCmdId == null) { maintenanceCmdId = findChildCommandByActionType(VdcActionType.MaintenanceNumberOfVdss, childCmdIds); } return maintenanceCmdId; } private Guid findChildCommandByActionType(VdcActionType commandType, List<Guid> childCmdIds) { for (Guid cmdId : childCmdIds) { CommandEntity commandEntity = CommandCoordinatorUtil.getCommandEntity(cmdId); if (commandEntity.getCommandType() == commandType) { return cmdId; } } return null; } private boolean childCommandsExist(List<Guid> childCmdIds) { return !childCmdIds.isEmpty(); } }