package org.ovirt.engine.core.bll; import java.io.ByteArrayOutputStream; import java.io.IOException; import javax.inject.Inject; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.bll.job.ExecutionHandler; import org.ovirt.engine.core.bll.utils.EngineSSHClient; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.FenceVdsActionParameters; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdsPowerDownParameters; 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.dao.VdsDynamicDao; /** * Tries to shutdown a host using SSH connection. The host has to be in maintenance mode. */ @NonTransactiveCommandAttribute public class VdsPowerDownCommand<T extends VdsPowerDownParameters> extends VdsCommand<T> { @Inject private VdsDynamicDao vdsDynamicDao; public VdsPowerDownCommand(T parameters, CommandContext commandContext) { super(parameters, commandContext); } @Override protected boolean validate() { return getVds().getStatus() == VDSStatus.Maintenance && super.validate(); } /** * Try to shut down the host using a clean ssh poweroff method */ @Override protected void executeCommand() { setVds(null); if (getVds() == null) { handleError("SSH power down will not be executed on host {} ({}) since it doesn't exist anymore."); return; } /* Try this only when the Host is in maintenance state */ if (getVds().getStatus() != VDSStatus.Maintenance) { handleError("SSH power down will not be executed on host {} ({}) since it is not in Maintenance."); return; } boolean result = executeSshPowerDown(getVds().getClusterCompatibilityVersion().toString()); if (result) { // SSH powerdown executed without errors set the status to down setVdsStatus(VDSStatus.Down); // clear the automatic PM flag unless instructed otherwise if (!getParameters().getKeepPolicyPMEnabled()) { getVds().setPowerManagementControlledByPolicy(false); vdsDynamicDao.updateVdsDynamicPowerManagementPolicyFlag( getVdsId(), getVds().getDynamicData().isPowerManagementControlledByPolicy()); } } else if (getParameters().getFallbackToPowerManagement() && getVds().isPmEnabled()) { FenceVdsActionParameters parameters = new FenceVdsActionParameters(getVds().getId()); parameters.setKeepPolicyPMEnabled(getParameters().getKeepPolicyPMEnabled()); runInternalAction(VdcActionType.StopVds, parameters, ExecutionHandler.createInternalJobContext()); } setSucceeded(result); } @Override public AuditLogType getAuditLogTypeValue() { return getSucceeded() ? AuditLogType.USER_VDS_STOP : AuditLogType.USER_FAILED_VDS_STOP; } private void handleError(final String errorMessage) { setCommandShouldBeLogged(false); log.info(errorMessage, getVdsName(), getVdsId()); getReturnValue().setSucceeded(false); } /** * Executes SSH shutdown command * * @return {@code true} if command has been executed successfully, {@code false} otherwise */ private boolean executeSshPowerDown(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 power down session on host {}", getVds().getHostName()); sshClient.setVds(getVds()); sshClient.useDefaultKeyPair(); sshClient.connect(); sshClient.authenticate(); log.info("Executing SSH power down command on host {}", getVds().getHostName()); sshClient.executeCommand( Config.getValue(ConfigValues.SshVdsPowerdownCommand, version), null, cmdOut, cmdErr ); ret = true; } catch (Exception ex) { log.error("SSH power down command failed on host '{}': {}\nStdout: {}\nStderr: {}", getVds().getHostName(), ex.getMessage(), cmdOut, cmdErr); log.debug("Exception", ex); } } catch(IOException e) { log.error("Error opening SSH connection to '{}': {}", getVds().getHostName(), e.getMessage()); log.debug("Exception", e); } return ret; } }