/*
* RHQ Management Platform
* Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.server.control.command;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Future;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.Executor;
import org.rhq.server.control.ControlCommand;
import org.rhq.server.control.RHQControl;
import org.rhq.server.control.RHQControlException;
import org.rhq.server.control.util.ExecutorAssist;
/**
* @author John Sanda
*/
public class Console extends ControlCommand {
private Options options;
public Console() {
options = new Options().addOption(null, "storage", false, "Start the RHQ storage node in the foreground")
.addOption(null, "server", false, "Start the RHQ server in the foreground")
// leaving out the agent option for now...
;//.addOption(null, "agent", false, "Start the RHQ agent in the foreground (unsupported)");
}
@Override
public String getName() {
return "console";
}
@Override
public String getDescription() {
return "Starts an RHQ service in the foreground. Only --server or --storage is supported. To start the agent in "
+ "the foreground, use the <RHQ_AGENT_HOME>/bin/rhq-agent.(sh|bat) script.";
}
@Override
public Options getOptions() {
return options;
}
@Override
protected String getReadmeFilename() {
return "CONSOLE_README.txt";
}
@Override
protected int exec(CommandLine commandLine) {
int rValue = RHQControl.EXIT_CODE_OK;
if (commandLine.getOptions().length != 1) {
printUsage();
rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
} else {
String option = commandLine.getOptions()[0].getLongOpt();
try {
if (option.equals(STORAGE_OPTION)) {
if (isStorageInstalled()) {
rValue = Math.max(rValue, startStorageInForeground());
} else {
log.warn("It appears that the storage node is not installed. The --" + STORAGE_OPTION
+ " option will be ignored.");
rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
}
} else if (option.equals(SERVER_OPTION)) {
if (isServerInstalled()) {
rValue = Math.max(rValue, startServerInForeground());
} else {
log.warn("It appears that the server is not installed. The --" + SERVER_OPTION
+ " option will be ignored.");
rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
}
} else if (option.equals(AGENT_OPTION)) {
if (isAgentInstalled()) {
rValue = Math.max(rValue, startAgentInForeground());
} else {
log.warn("It appears that the agent is not installed. The --" + AGENT_OPTION
+ " option will be ignored.");
rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
}
} else {
throw new IllegalArgumentException(option + " is not a supported option");
}
} catch (Exception e) {
throw new RHQControlException("Failed to execute console command", e);
}
}
return rValue;
}
private int startStorageInForeground() throws Exception {
log.debug("Starting RHQ storage node in foreground");
File storageBinDir = new File(getStorageBasedir(), "bin");
if (isWindows()) {
return startInWindowsForeground(storageBinDir, "cassandra", "-f");
}
return startConsole(storageBinDir, getCommandLine(false, "cassandra", "-f"));
}
private int startServerInForeground() throws Exception {
log.debug("Starting RHQ server in foreground");
validateServerPropertiesFile();
File binDir = getBinDir();
if (isWindows()) {
return startInWindowsForeground(binDir, "rhq-server", "console");
}
return startConsole(binDir, getCommandLine("rhq-server", "console"));
}
private int startAgentInForeground() throws Exception {
log.info("Starting RHQ agent in foreground");
File agentHomeDir = getAgentBasedir();
File agentBinDir = new File(agentHomeDir, "bin");
File confDir = new File(agentHomeDir, "conf");
File agentConfigFile = new File(confDir, "agent-configuration.xml");
Process process = new ProcessBuilder(getScript("rhq-agent"), "-c", agentConfigFile.getPath()).directory(
agentBinDir)
// .redirectOutput(ProcessBuilder.Redirect.INHERIT)
// .redirectInput(ProcessBuilder.Redirect.INHERIT)
// .redirectError(ProcessBuilder.Redirect.INHERIT)
.start();
// .waitFor();
AgentInputStreamPipe pipe = new AgentInputStreamPipe(process.getInputStream());
pipe.start();
pipe.join();
// final InputStream inputStream = process.getInputStream();
// final CountDownLatch doneSignal = new CountDownLatch(1);
// Thread agentThread = new Thread(new Runnable() {
// @Override
// public void run() {
// InputStreamReader reader = new InputStreamReader(inputStream);
// Scanner scanner = new Scanner(reader);
// while (scanner.hasNextLine()) {
// System.out.println(scanner.nextLine());
// }
// doneSignal.countDown();
// }
// });
// agentThread.start();
// doneSignal.await();
// agentThread.join();
return RHQControl.EXIT_CODE_OK;
}
private int startInWindowsForeground(File binDir, String script, String... scriptArgs) throws Exception {
org.apache.commons.exec.CommandLine commandLine = getConsoleCommandLine(script, scriptArgs);
Future<Integer> f = ExecutorAssist.executeAsync(binDir, commandLine, null);
// The program won't launch if rhqctl exits first, wait a few seconds
for (int i = 0; (i < 3) && !f.isDone(); ++i) {
Thread.sleep(1000);
}
return f.isDone() ? f.get() : 0;
}
private class AgentInputStreamPipe extends Thread {
private InputStream inputStream;
public AgentInputStreamPipe(InputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
boolean running = true;
while (running) {
String line = reader.readLine();
System.out.println(line);
running = line == null || !line.equals("quit");
}
} catch (IOException e) {
log.error("An error occurred processing input from the agent prompt", e);
}
}
}
/**
* This assistant method provides correct SIGTERM handling.
*
* @param workingDir
* @param commandLine
* @return Exit code of the rhq-server.sh console, or 143 (128+15) in Linux if the service was killed.
* @throws IOException
*/
private int startConsole(final File workingDir, final org.apache.commons.exec.CommandLine commandLine) throws IOException {
Executor executor = new DefaultExecutor();
executor.setWorkingDirectory(workingDir);
final ExecuteWatchdog watchdog = new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT);
executor.setWatchdog(watchdog);
this.addUndoTask(new UndoTask() {
@Override
protected void performUndoWork() throws Exception {
watchdog.destroyProcess();
}
});
return executor.execute(commandLine);
}
}