package org.ovirt.engine.core.bll.pm; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute; import org.ovirt.engine.core.bll.VdsCommand; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.bll.utils.EngineSSHClient; import org.ovirt.engine.core.common.action.VdsActionParameters; import org.ovirt.engine.core.common.businessentities.VDSStatus; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.utils.ThreadUtils; import org.ovirt.engine.core.vdsbroker.ResourceManager; import org.ovirt.engine.core.vdsbroker.VdsManager; /** * Tries to restart VDSM using SSH connection */ @NonTransactiveCommandAttribute public class SshSoftFencingCommand<T extends VdsActionParameters> extends VdsCommand<T> { @Inject private ResourceManager resourceManager; public SshSoftFencingCommand(T parameters, CommandContext commandContext) { super(parameters, commandContext); } /** * If the VDS is not responding, it executes SSH Soft Fencing. */ @Override protected void executeCommand() { setVds(null); if (getVds() == null) { setCommandShouldBeLogged(false); log.info("SSH Soft Fencing will not be executed on host '{}' ({}) since it doesn't exist anymore.", getVdsName(), getVdsId()); getReturnValue().setSucceeded(false); return; } if (new HostFenceActionExecutor(getVds()).isHostPoweredOff()) { // do not try to soft-fence if Host is reported as Down via PM getReturnValue().setSucceeded(false); } else { if (getVds().shouldVdsBeFenced()) { boolean result = executeSshSoftFencingCommand(getVds().getClusterCompatibilityVersion().toString()); if (result) { // SSH Soft Fencing executed successfully, check if host become Up result = checkIfHostBecomeUp(); } getReturnValue().setSucceeded(result); } else { setCommandShouldBeLogged(false); log.info("SSH Soft Fencing will not be executed on host '{}' ({}) since it's status is ok.", getVdsName(), getVdsId()); getReturnValue().setSucceeded(false); } } } /** * Executes SSH Soft Fencing command * * @param version * cluster compatibility version to acquire correct command to restart VDSM * @return {@code true} if command has been executed successfully, {@code false} otherwise */ private boolean executeSshSoftFencingCommand(String version) { boolean ret = false; try ( final EngineSSHClient sshClient = new EngineSSHClient(); final ByteArrayOutputStream cmdOut = new ByteArrayOutputStream(); final ByteArrayOutputStream cmdErr = new ByteArrayOutputStream() ) { try { log.info("Opening SSH Soft Fencing session on host '{}'", getVds().getHostName()); sshClient.setVds(getVds()); sshClient.useDefaultKeyPair(); sshClient.connect(); sshClient.authenticate(); log.info("Executing SSH Soft Fencing command on host '{}'", getVds().getHostName()); sshClient.executeCommand( Config.getValue(ConfigValues.SshSoftFencingCommand, version), null, cmdOut, cmdErr ); ret = true; } catch (Exception ex) { log.error("SSH Soft Fencing command failed on host '{}': {}\nStdout: {}\nStderr: {}", getVds().getHostName(), ex.getMessage(), cmdOut, cmdErr); log.debug("Exception", ex); } } catch(IOException e) { log.error("IOException", e); } return ret; } /** * Check if host become Up after successful SSH Soft Fencing execution until grace period is over * * @return {@code true} if host became Up during grace period, otherwise {@code false} */ private boolean checkIfHostBecomeUp() { VdsManager vdsManager = getResourceManager().getVdsManager(getVdsId()); long sleepInterval = TimeUnit.SECONDS.toMillis( Config.<Integer> getValue(ConfigValues.VdsRefreshRate)); while (vdsManager.isHostInGracePeriod(true)) { if (vdsManager.getCopyVds().getStatus() == VDSStatus.Up) { // host became Up during grace period return true; } // wait until next host monitoring attempt ThreadUtils.sleep(sleepInterval); } return false; } public ResourceManager getResourceManager() { return resourceManager; } }