/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.instancemanagement;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.jcraft.jsch.JSchException;
import de.rcenvironment.core.command.common.CommandException;
import de.rcenvironment.core.command.spi.CommandContext;
import de.rcenvironment.core.command.spi.CommandDescription;
import de.rcenvironment.core.command.spi.CommandPlugin;
import de.rcenvironment.core.instancemanagement.InstanceManagementService.ConfigurationFlag;
import de.rcenvironment.core.instancemanagement.InstanceManagementService.InstallationPolicy;
import de.rcenvironment.core.instancemanagement.internal.ConfigurationChangeEntry;
import de.rcenvironment.core.instancemanagement.internal.ConfigurationChangeSequence;
import de.rcenvironment.core.instancemanagement.internal.ConfigurationSshConnection;
import de.rcenvironment.core.utils.common.StringUtils;
import de.rcenvironment.core.utils.ssh.jsch.SshParameterException;
/**
* A {@link CommandPlugin} that provides instance management ("im") commands.
*
* @author Robert Mischke
* @author David Scholz
*/
public class InstanceManagementCommandPlugin implements CommandPlugin {
private static final String SUBCOMMAND_ADD_CONNECTION = "--add-connection";
private static final String SUBCOMMAND_ADD_SERVER_PORT = "--add-server-port";
private static final String ROOT_COMMAND = "im";
private static final String SUBCOMMAND_RESET = "--reset";
private static final String SUBCOMMAND_APPLY_TEMPLATE = "--apply-template";
private static final String SUBCOMMAND_SET_NAME = "--set-name";
private static final String SUBCOMMAND_SET_COMMENT = "--set-comment";
private static final String SUBCOMMAND_SET_RELAY_OPTION = "--set-relay-option";
private static final String SUBCOMMAND_SET_WORKFLOW_HOST_OPTION = "--set-workflow-host-option";
private static final String SUBCOMMAND_SET_TEMPDIR_PATH = "--set-tempdir-path";
private static final String SUBCOMMAND_ENABLE_IM_SSH_ACCESS = "--enable-im-ssh-access";
private static final String SUBCOMMAND_CONFIGURE_SSH_SERVER = "--configure-ssh-server";
private static final String SUBCOMMAND_DISABLE_SSH_SERVER = "--disable-ssh-server";
private static final String SUBCOMMAND_SET_IP_FILTER_ENABLED = "--set-ip-filter-enabled";
private static final String ZERO_STRING = "0";
private static final String COMMA_STRING = ",";
private static final String ALL_MARKER_TOKEN = "all";
private static final String IF_MISSING = "--if-missing";
private static final String FORCE_DOWNLOAD = "--force-download";
private static final String FORCE_REINSTALL = "--force-reinstall";
private static final String TIMEOUT = "--timeout";
private static final String TIMEOUT_DESCRIPTION =
"--timeout - specifies the maximum length of time this command is allowed to run (in seconds) - default = 60s";
private InstanceManagementService instanceManagementService;
private ThreadLocal<CommandContext> currentContext = new ThreadLocal<>(); // to avoid lots of context passing, but still be thread-safe
protected void bindInstanceManagementService(InstanceManagementService newInstance) {
this.instanceManagementService = newInstance;
}
@Override
public Collection<CommandDescription> getCommandDescriptions() {
final Collection<CommandDescription> contributions = new ArrayList<CommandDescription>();
contributions
.add(new CommandDescription(ROOT_COMMAND + " install",
"[--if-missing] [--force-download] [--force-reinstall] [--timeout] <url version id/part> <installation id>",
true,
"downloads and installs a new RCE installation",
"--if-missing - download and install if and only if an installation with the same version is not present",
"--force-download - forces the download of the installation files even if they are present in the current cache",
"--force-reinstall - forces reinstallation even if the same version is already installed",
TIMEOUT_DESCRIPTION));
contributions
.add(new CommandDescription(ROOT_COMMAND + " reinstall",
"[--force-download] [--force-reinstall] [--timeout] <url version id/part> <installation id>",
true,
"stops all instances running the given installation id, downloads and installs the new RCE installation, and starts the "
+ "instances again with the new installation",
"--force-download - forces the download of the installation files even if they are present in the current cache",
"--force-reinstall - forces reinstallation even if the same version is already installed",
TIMEOUT_DESCRIPTION));
contributions
.add(new CommandDescription(ROOT_COMMAND + " configure",
"<instance id(s)> <command> [<parameters>] [<command> [<parameters>]] [...]",
true,
"configures the configuration.json file of the specified RCE instance(s)",
"Available commands:",
SUBCOMMAND_RESET + " - resets the instance to an empty configuration",
SUBCOMMAND_APPLY_TEMPLATE + " <template id> - applies (i.e. copies) the given template as the new configuration",
SUBCOMMAND_SET_NAME + " <name> - sets the name of the instance",
SUBCOMMAND_SET_COMMENT + " <comment> - sets a general comment",
SUBCOMMAND_SET_WORKFLOW_HOST_OPTION + " [<true/false>] - sets or clears the workflow host flag",
SUBCOMMAND_SET_RELAY_OPTION + " [<true/false>] - sets or clears the relay flag",
SUBCOMMAND_SET_TEMPDIR_PATH + " <path> - sets the root path for RCE's temporary files directory",
SUBCOMMAND_ADD_SERVER_PORT + " <id> <ip> <port> - adds a new server port and sets the ip and port number to bind to",
// TODO restore reconnect parameters
SUBCOMMAND_ADD_CONNECTION + " <id> <host> <port> <true/false> - adds new connection "
+ "to the given ip/hostname and port, and whether it should auto-connect",
SUBCOMMAND_SET_IP_FILTER_ENABLED + " [<true/false>] - enables or disables the ip filter; default: true",
SUBCOMMAND_ENABLE_IM_SSH_ACCESS + " <port> - enables and configures SSH forwarding of "
+ "RCE console commands by the IM \"master\" instance",
SUBCOMMAND_CONFIGURE_SSH_SERVER + " <ip> <port> - enables the ssh server and sets the ip and port to bind to",
SUBCOMMAND_DISABLE_SSH_SERVER + " - disables the ssh server"
// from here: new or reworked commands, but handling not adapted/implemented yet
));
// from here: not checked or migrated yet
// "--set-request-timeout <timeout> - sets the request timeout in msec",
// "--set-forwarding-timeout <timeout> - sets the forwarding timeout in msec",
// + "<autoRetryInitialDelay> <autoRetryMaximumDelay> <atuoRetryDelayMultiplier> - adds new connection",
// "--remove-connection <name> - removes a connection",
// "--remove-server-port <name> - removes the desired server port",
// "--add-allowed-inbound-ip <ip> - adds/allows an inbound IP address to the filter",
// "--remove-allowed-inbound-ip <ip> - removes/disallows an inbound IP address from the filter",
// "--add-ssh-connection <name> <displayName> <host> <port> <loginName> - adds a new ssh connection",
// "--remove-ssh-connection <name> - removes a ssh connection",
// "--publish-component <name> - publishes a new component",
// "--unpublish-component <name> - unpublishes a component",
// "--set-ssh-server-ip <ip> - sets the ssh server ip adress",
// "--set-ssh-server-port <port> - sets the ssh server port"));
contributions.add(new CommandDescription(ROOT_COMMAND + " start",
"[--timeout] <instance id1, instance id2, ...> <installation id>",
true,
"starts a list of new RCE instances with the desired instance IDs and the desired installation",
TIMEOUT_DESCRIPTION));
contributions.add(new CommandDescription(ROOT_COMMAND + " stop",
"[--timeout] <instance id1, instance id2, ...>",
true,
"stops a list of running RCE instances",
TIMEOUT_DESCRIPTION));
contributions.add(new CommandDescription(ROOT_COMMAND + " start all",
"[--timeout] <installation id>",
true,
"starts all available instances with the desired installation",
TIMEOUT_DESCRIPTION));
contributions.add(new CommandDescription(ROOT_COMMAND + " stop all",
"[--timeout] <installation id>",
true,
"stops all running instances",
"<installation id> - optional parameter if one want to stop all running instances of a specific installation",
TIMEOUT_DESCRIPTION));
contributions.add(new CommandDescription(ROOT_COMMAND + " restart",
" <instance id1, instance id2, ...> <installation id>",
true,
"restarts a list of RCE instances with the given instance IDs and the given installation"));
contributions.add(new CommandDescription(ROOT_COMMAND + " dispose",
"<instance id>",
true,
"disposes the specified instance meaning deletion of the profile directory"));
contributions.add(new CommandDescription(ROOT_COMMAND + " list",
"[--instances] [--installations] [--templates]",
true,
"lists information about instances, installations or templates"));
contributions.add(new CommandDescription(ROOT_COMMAND + " info",
"",
true,
"shows additional information"));
return contributions;
}
@Override
public void execute(CommandContext context) throws CommandException {
context.consumeExpectedToken(ROOT_COMMAND);
String subCommand = context.consumeNextToken();
if (subCommand == null) {
throw CommandException.unknownCommand(context);
}
switch (subCommand) {
case "install":
performInstall(context);
break;
case "reinstall":
performReinstall(context);
break;
case "configure":
performConfigure(context);
break;
case "start":
if (context.consumeNextTokenIfEquals(ALL_MARKER_TOKEN)) {
performStartAll(context);
} else {
performStart(context);
}
break;
case "stop":
if (context.consumeNextTokenIfEquals(ALL_MARKER_TOKEN)) {
performStopAll(context);
} else {
performStop(context);
}
break;
case "restart":
performRestart(context);
break;
case "list":
performList(context);
break;
case "dispose":
performDispose(context);
break;
case "info":
performInformation(context);
break;
case "execute-on":
performExecuteOn(context);
break;
default:
throw CommandException.syntaxError("Unknown sub-command", context);
}
}
private void performExecuteOn(CommandContext context) throws CommandException {
String instanceId = context.consumeNextToken();
String command = context.consumeNextToken();
if (instanceId == null || command == null || context.hasRemainingTokens()) {
throw CommandException.wrongNumberOfParameters(context);
}
try {
instanceManagementService.executeCommandOnInstance(instanceId, command, context.getOutputReceiver());
} catch (JSchException | SshParameterException | IOException | InterruptedException e) {
throw CommandException.executionError(
"Could not execute command " + command + " on instance " + instanceId + ": " + e.getMessage(), context);
}
}
private void performInstall(CommandContext context) throws CommandException {
InstallationPolicy policy = InstallationPolicy.IF_PRESENT_CHECK_VERSION_AND_REINSTALL_IF_DIFFERENT;
if (context.consumeNextTokenIfEquals(FORCE_DOWNLOAD)) {
policy = InstallationPolicy.FORCE_NEW_DOWNLOAD_AND_REINSTALL;
} else if (context.consumeNextTokenIfEquals(FORCE_REINSTALL)) {
policy = InstallationPolicy.FORCE_REINSTALL;
} else if (context.consumeNextTokenIfEquals(IF_MISSING)) {
policy = InstallationPolicy.ONLY_INSTALL_IF_NOT_PRESENT;
}
String urlQualifier = context.consumeNextToken();
String installationId = context.consumeNextToken();
if (urlQualifier == null || installationId == null || context.hasRemainingTokens()) {
throw CommandException.wrongNumberOfParameters(context);
}
try {
switch (policy) {
case FORCE_NEW_DOWNLOAD_AND_REINSTALL:
instanceManagementService.setupInstallationFromUrlQualifier(installationId, urlQualifier,
InstallationPolicy.FORCE_NEW_DOWNLOAD_AND_REINSTALL, context.getOutputReceiver(), 0);
break;
case FORCE_REINSTALL:
instanceManagementService.setupInstallationFromUrlQualifier(installationId, urlQualifier,
InstallationPolicy.FORCE_REINSTALL, context.getOutputReceiver(), 0);
break;
case IF_PRESENT_CHECK_VERSION_AND_REINSTALL_IF_DIFFERENT:
instanceManagementService.setupInstallationFromUrlQualifier(installationId, urlQualifier,
InstallationPolicy.IF_PRESENT_CHECK_VERSION_AND_REINSTALL_IF_DIFFERENT, context.getOutputReceiver(), 0);
break;
case ONLY_INSTALL_IF_NOT_PRESENT:
instanceManagementService.setupInstallationFromUrlQualifier(installationId, urlQualifier,
InstallationPolicy.ONLY_INSTALL_IF_NOT_PRESENT, context.getOutputReceiver(), 0);
break;
default:
instanceManagementService.setupInstallationFromUrlQualifier(installationId, urlQualifier,
InstallationPolicy.IF_PRESENT_CHECK_VERSION_AND_REINSTALL_IF_DIFFERENT, context.getOutputReceiver(), 0);
break;
}
} catch (IOException e) {
throw CommandException.executionError("Error during installation setup process: " + e.getMessage(), context);
}
}
private void performReinstall(CommandContext context) throws CommandException {
InstallationPolicy policy = InstallationPolicy.IF_PRESENT_CHECK_VERSION_AND_REINSTALL_IF_DIFFERENT;
if (context.consumeNextTokenIfEquals(FORCE_DOWNLOAD)) {
policy = InstallationPolicy.FORCE_NEW_DOWNLOAD_AND_REINSTALL;
} else if (context.consumeNextTokenIfEquals(FORCE_REINSTALL)) {
policy = InstallationPolicy.FORCE_REINSTALL;
}
String urlQualifier = context.consumeNextToken();
String installationId = context.consumeNextToken();
if (urlQualifier == null || installationId == null || context.hasRemainingTokens()) {
throw CommandException.wrongNumberOfParameters(context);
}
try {
switch (policy) {
case FORCE_NEW_DOWNLOAD_AND_REINSTALL:
instanceManagementService.reinstallFromUrlQualifier(installationId, urlQualifier,
InstallationPolicy.FORCE_NEW_DOWNLOAD_AND_REINSTALL, context.getOutputReceiver(), 0);
break;
case FORCE_REINSTALL:
instanceManagementService.reinstallFromUrlQualifier(installationId, urlQualifier,
InstallationPolicy.FORCE_REINSTALL, context.getOutputReceiver(), 0);
break;
case IF_PRESENT_CHECK_VERSION_AND_REINSTALL_IF_DIFFERENT:
instanceManagementService.reinstallFromUrlQualifier(installationId, urlQualifier,
InstallationPolicy.IF_PRESENT_CHECK_VERSION_AND_REINSTALL_IF_DIFFERENT, context.getOutputReceiver(), 0);
break;
default:
instanceManagementService.reinstallFromUrlQualifier(installationId, urlQualifier,
InstallationPolicy.IF_PRESENT_CHECK_VERSION_AND_REINSTALL_IF_DIFFERENT, context.getOutputReceiver(), 0);
break;
}
} catch (IOException e) {
throw CommandException.executionError("Error during installation setup process: " + e.getMessage(), context);
}
}
private void performConfigure(CommandContext context) throws CommandException {
currentContext.set(context); // TODO use for other commands as well?
String instanceIds = context.consumeNextToken();
if (instanceIds.contains(COMMA_STRING)) {
throw CommandException.executionError("Configuring multiple instance ids at once is not implemented yet", context);
}
// validate start of first sub-command
String firstToken = context.peekNextToken();
if (firstToken == null) {
throw CommandException.syntaxError("At least one command must be provided after the instance id(s)", context);
}
if (!isASubCommandToken(firstToken)) {
throw CommandException.syntaxError("Expected a command after the instance id(s), but found another value: " + firstToken,
context);
}
ConfigurationChangeSequence changeSequence = new ConfigurationChangeSequence();
while (context.hasRemainingTokens()) {
String commandToken = context.consumeNextToken();
if (!isASubCommandToken(commandToken)) {
throw CommandException.syntaxError("Internal consistency error: received an unexpected non-command token ", context);
}
List<String> parameters = new ArrayList<>();
while (isAParameterToken(context.peekNextToken())) {
parameters.add(context.consumeNextToken());
}
handleSubCommand(changeSequence, commandToken, parameters);
}
try {
instanceManagementService.configureInstance(instanceIds, changeSequence, context.getOutputReceiver());
} catch (IOException e) {
throw CommandException.executionError(e.toString(), context);
}
}
private void handleSubCommand(ConfigurationChangeSequence changeSequence, String token, List<String> parameters)
throws CommandException {
switch (token) {
case SUBCOMMAND_RESET:
assertParameterCount(parameters, 0, token);
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.RESET_CONFIGURATION, Object.class,
null));
break;
case SUBCOMMAND_APPLY_TEMPLATE:
assertParameterCount(parameters, 1, token);
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.APPLY_TEMPLATE, String.class,
parameters.get(0)));
break;
case SUBCOMMAND_SET_NAME:
assertParameterCount(parameters, 1, token);
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.SET_NAME, String.class, parameters.get(0)));
break;
case SUBCOMMAND_SET_COMMENT:
assertParameterCount(parameters, 1, token);
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.SET_COMMENT, String.class, parameters.get(0)));
break;
case SUBCOMMAND_SET_RELAY_OPTION:
assertParameterCount(parameters, 0, 1, token);
if (parseSingleBooleanParameter(parameters, true)) { // TODO merge derived configuration keys?
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_RELAY, Boolean.class, true));
} else {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.DISABLE_RELAY, Boolean.class, false));
}
break;
case SUBCOMMAND_SET_WORKFLOW_HOST_OPTION:
assertParameterCount(parameters, 0, 1, token);
if (parseSingleBooleanParameter(parameters, true)) { // TODO merge derived configuration keys?
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_WORKFLOWHOST, Boolean.class, true));
} else {
changeSequence
.append(new ConfigurationChangeEntry(ConfigurationFlag.DISABLE_WORKFLOWHOST, Boolean.class, false));
}
break;
case SUBCOMMAND_SET_TEMPDIR_PATH:
assertParameterCount(parameters, 1, token);
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.TEMP_DIR, String.class, parameters.get(0)));
break;
case SUBCOMMAND_ADD_SERVER_PORT:
assertParameterCount(parameters, 3, token); // id, host, port
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ADD_SERVER_PORT, Object.class, parameters));
break;
case SUBCOMMAND_ADD_CONNECTION:
assertParameterCount(parameters, 4, token); // id, host, port, autoconnect
parameters.add(ZERO_STRING); // TODO dummy values for now
parameters.add(ZERO_STRING);
parameters.add(ZERO_STRING);
addConnectionToConfig(parameters, changeSequence);
break;
case SUBCOMMAND_CONFIGURE_SSH_SERVER:
assertParameterCount(parameters, 2, token);
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_SSH_SERVER, Boolean.class,
true));
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.SET_SSH_SERVER_IP, String.class,
parameters.get(0)));
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.SET_SSH_SERVER_PORT, Integer.class,
Integer.parseInt(parameters.get(1))));
break;
case SUBCOMMAND_DISABLE_SSH_SERVER:
assertParameterCount(parameters, 0, token);
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.DISABLE_SSH_SERVER, Boolean.class,
false));
break;
case SUBCOMMAND_SET_IP_FILTER_ENABLED:
assertParameterCount(parameters, 0, 1, token);
if (parseSingleBooleanParameter(parameters, true)) { // TODO merge derived configuration keys?
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_IP_FILTER, Boolean.class, true));
} else {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.DISABLE_IP_FILTER, Boolean.class, false));
}
break;
case SUBCOMMAND_ENABLE_IM_SSH_ACCESS:
assertParameterCount(parameters, 1, token);
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_IM_SSH_ACCESS, Integer.class,
Integer.parseInt(parameters.get(0))));
break;
// case SUBCOMMAND_:
// assertParameterCount(parameters, 1, token);
// break;
default:
throw CommandException.syntaxError("Unexpected configuration command " + token, currentContext.get());
}
// TODO unmigrated code below - for reference only
if (true) {
return;
}
int index = 0; // only to ensure compilation during migration
List<String> tokens = new ArrayList<>(); // only to ensure compilation during migration
if (token.equals("")) {
index = 1; // dummy entry
} else if (token.equals(ConfigurationFlag.ENABLE_DEP_INPUT_TAB.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_DEP_INPUT_TAB, Boolean.class, true));
} else if (token.equals(ConfigurationFlag.DISABLE_DEP_INPUT_TAB.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.DISABLE_DEP_INPUT_TAB, Boolean.class,
false));
} else if (token.equals(ConfigurationFlag.REQUEST_TIMEOUT.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.REQUEST_TIMEOUT, Long.class,
Long.parseLong(tokens.get(index + 1))));
} else if (token.equals(ConfigurationFlag.FORWARDING_TIMEOUT.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.FORWARDING_TIMEOUT, Long.class,
Long.parseLong(tokens.get(index + 1))));
} else if (token.equals(ConfigurationFlag.REMOVE_CONNECTION.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.REMOVE_CONNECTION, String.class,
tokens.get(index + 1)));
} else if (token.equals(ConfigurationFlag.REMOVE_SERVER_PORT.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.REMOVE_SERVER_PORT, String.class,
tokens.get(index + 1)));
} else if (token.equals(ConfigurationFlag.ADD_ALLOWED_IP.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ADD_ALLOWED_IP, String.class,
parameters.get(0)));
} else if (token.equals(ConfigurationFlag.REMOVE_ALLOWED_IP.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.REMOVE_ALLOWED_IP, String.class,
parameters.get(0)));
} else if (token.equals(ConfigurationFlag.ADD_SSH_CONNECTION.getFlag())) {
addSshConnectionToConfig(tokens, changeSequence, index);
for (int i = 5; i < 1; i--) {
tokens.remove(index + i);
}
index = 0;
} else if (token.equals(ConfigurationFlag.REMOVE_SSH_CONNECTION.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.REMOVE_SSH_CONNECTION, String.class,
parameters.get(0)));
} else if (token.equals(ConfigurationFlag.PUBLISH_COMPONENT.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.PUBLISH_COMPONENT, String.class,
parameters.get(0)));
} else if (token.equals(ConfigurationFlag.UNPUBLISH_COMPONENT.getFlag())) {
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.UNPUBLISH_COMPONENT, String.class,
parameters.get(0)));
} else if (token.equals(ConfigurationFlag.SET_BACKGROUND_MONITORING.getFlag())) {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put(parameters.get(0), Integer.parseInt(parameters.get(1)));
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.SET_BACKGROUND_MONITORING, Object.class,
map));
tokens.remove(index + 1);
tokens.remove(index + 2);
index = 0;
} else {
throw CommandException.syntaxError("Unexpected token: " + token, currentContext.get());
}
}
private boolean parseSingleBooleanParameter(List<String> parameters, boolean defaultValue) throws CommandException {
if (parameters.isEmpty()) {
return defaultValue;
} else if (parameters.get(0).equals("true")) {
return true;
} else if (parameters.get(0).equals("false")) {
return false;
} else {
throw CommandException
.syntaxError("Invalid parameter (expected 'true' or 'false'): " + parameters.get(0), currentContext.get());
}
}
private void assertParameterCount(List<String> parameters, int min, String commandToken)
throws CommandException {
assertParameterCount(parameters, min, min, commandToken);
}
private void assertParameterCount(List<String> parameters, int min, int max, String commandToken) throws CommandException {
int actual = parameters.size();
if (actual < min || max < actual) {
throw CommandException.syntaxError(StringUtils.format(
"Wrong number of parameters for the %s command: expected between %d and %d parameters, but found %d: %s", commandToken,
min, max, actual, Arrays.toString(parameters.toArray())), currentContext.get());
}
}
private boolean isASubCommandToken(String token) {
return token != null && token.startsWith("--");
}
private boolean isAParameterToken(String token) {
return token != null && !token.startsWith("--");
}
private void addSshConnectionToConfig(List<String> tokens, ConfigurationChangeSequence changeSequence, int index) {
ConfigurationSshConnection connection =
new ConfigurationSshConnection(tokens.get(index + 1), tokens.get(index + 2), tokens.get(index + 3),
Integer.parseInt(tokens
.get(index + 4)),
tokens.get(index + 5));
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ADD_SSH_CONNECTION,
ConfigurationSshConnection.class, connection));
}
private void addConnectionToConfig(List<String> parameters, ConfigurationChangeSequence changeSequence) {
de.rcenvironment.core.instancemanagement.internal.ConfigurationConnection configConnection =
new de.rcenvironment.core.instancemanagement.internal.ConfigurationConnection(parameters.get(0),
parameters.get(1), Integer.parseInt(parameters.get(2)), Boolean.parseBoolean(parameters.get(3)),
Long.parseLong(parameters.get(4)), Long.parseLong(parameters.get(5)), Integer.parseInt(parameters.get(6)));
changeSequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ADD_CONNECTION,
de.rcenvironment.core.instancemanagement.internal.ConfigurationConnection.class, configConnection));
}
private List<String> getInstanceIdList(List<String> tokens) {
List<String> instanceIdList = new LinkedList<>();
final String c = COMMA_STRING;
for (String token : tokens) {
if (token.contains(c)) {
if (token.length() == 1) {
continue;
}
if (token.startsWith(c)) {
instanceIdList.add(token.replaceFirst(COMMA_STRING, ""));
} else {
instanceIdList.addAll(Arrays.asList(token.split(c)));
}
} else {
instanceIdList.add(token);
}
}
return instanceIdList;
}
private void performStart(CommandContext context) throws CommandException {
List<String> instanceIdList = new LinkedList<>();
List<String> tokens = new LinkedList<>(context.consumeRemainingTokens());
long timeout = getTimeoutIfSpecified(tokens, context);
boolean startWithGui = getStartWithGUIIfSpecified(tokens, context);
String installationId = ((LinkedList<String>) tokens).removeLast();
instanceIdList = getInstanceIdList(tokens);
if (instanceIdList.isEmpty() || installationId == null || context.hasRemainingTokens()) {
throw CommandException.wrongNumberOfParameters(context);
}
try {
instanceManagementService.startInstance(installationId, instanceIdList, context.getOutputReceiver(), timeout, startWithGui);
} catch (IOException e) {
throw CommandException.executionError(e.toString(), context);
}
}
private void performRestart(CommandContext context) throws CommandException {
List<String> instanceIdList = new LinkedList<>();
List<String> tokens = new LinkedList<>(context.consumeRemainingTokens());
long timeout = getTimeoutIfSpecified(tokens, context);
boolean startWithGui = getStartWithGUIIfSpecified(tokens, context);
String installationId = ((LinkedList<String>) tokens).removeLast();
instanceIdList = getInstanceIdList(tokens);
if (instanceIdList.isEmpty() || installationId == null || context.hasRemainingTokens()) {
throw CommandException.wrongNumberOfParameters(context);
}
try {
instanceManagementService.stopInstance(new LinkedList<String>(instanceIdList), context.getOutputReceiver(), timeout);
instanceManagementService.startInstance(installationId, new LinkedList<String>(instanceIdList), context.getOutputReceiver(),
timeout, startWithGui);
} catch (IOException e) {
throw CommandException.executionError(e.toString(), context);
}
}
private void performStop(CommandContext context) throws CommandException {
List<String> tokens = new LinkedList<>(context.consumeRemainingTokens());
List<String> instanceIdList = new LinkedList<>();
long timeout = getTimeoutIfSpecified(tokens, context);
instanceIdList = getInstanceIdList(tokens);
if (instanceIdList.isEmpty() || context.hasRemainingTokens()) {
throw CommandException.wrongNumberOfParameters(context);
}
try {
instanceManagementService.stopInstance(instanceIdList, context.getOutputReceiver(), timeout);
} catch (IOException e) {
throw CommandException.executionError(e.toString(), context);
}
}
private void performStopAll(CommandContext context) throws CommandException {
List<String> tokens = new LinkedList<>(context.consumeRemainingTokens());
long timeout = getTimeoutIfSpecified(tokens, context);
if (tokens.size() > 1) {
throw CommandException.wrongNumberOfParameters(context);
}
String installationId = "";
if (!tokens.isEmpty()) {
installationId = ((LinkedList<String>) tokens).removeLast();
}
try {
instanceManagementService.stopAllInstances(installationId, context.getOutputReceiver(), timeout);
} catch (IOException e) {
throw CommandException.executionError(e.toString(), context);
}
}
private long getTimeoutIfSpecified(final List<String> tokens, CommandContext context) throws CommandException {
long timeout = 0;
if (tokens.contains(TIMEOUT)) {
int index = tokens.indexOf(TIMEOUT);
tokens.remove(index);
try {
String t = tokens.remove(index);
if (org.apache.commons.lang3.StringUtils.isNumeric(t)) {
timeout = Long.parseLong(t);
} else {
throw CommandException.executionError("No timeout specified", context);
}
} catch (IndexOutOfBoundsException e) {
throw CommandException.executionError("No timeout specified", context);
}
}
return timeout;
}
private boolean getStartWithGUIIfSpecified(final List<String> tokens, CommandContext context) throws CommandException {
long timeout = 0;
if (tokens.contains("--gui")) {
int index = tokens.indexOf("--gui");
tokens.remove(index);
return true;
}
return false;
}
private void performStartAll(CommandContext context) throws CommandException {
List<String> tokens = new LinkedList<>(context.consumeRemainingTokens());
long timeout = getTimeoutIfSpecified(tokens, context);
if (tokens.isEmpty()) {
throw CommandException.wrongNumberOfParameters(context);
}
String installationId = ((LinkedList<String>) tokens).removeLast();
try {
instanceManagementService.startAllInstances(installationId, context.getOutputReceiver(), timeout);
} catch (IOException e) {
throw CommandException.executionError(e.toString(), context);
}
}
private void performList(CommandContext context) throws CommandException {
String scope = context.consumeNextToken();
if (scope == null) {
// list ALL
scope = ALL_MARKER_TOKEN;
}
if (("instances".equals(scope) || "installations".equals(scope) || "templates".equals(scope) || ALL_MARKER_TOKEN.equals(scope))
&& !context.hasRemainingTokens()) {
try {
instanceManagementService.listInstanceManagementInformation(scope, context.getOutputReceiver());
} catch (IOException e) {
throw CommandException.executionError(e.toString(), context);
}
} else {
throw CommandException.syntaxError("Unknown parameter", context);
}
}
private void performDispose(CommandContext context) throws CommandException {
List<String> tokens = new LinkedList<>(context.consumeRemainingTokens());
List<String> instanceIds = getInstanceIdList(tokens);
if (instanceIds.isEmpty()) {
throw CommandException.wrongNumberOfParameters(context);
}
for (String instanceId : instanceIds) {
try {
instanceManagementService.disposeInstance(instanceId, context.getOutputReceiver());
} catch (IOException e) {
throw CommandException.executionError(e.toString(), context);
}
context.getOutputReceiver().addOutput("Instance with id: " + instanceId + " disposed");
context.getOutputReceiver().addOutput("Done.");
}
}
private void performInformation(CommandContext context) throws CommandException {
if (context.hasRemainingTokens()) {
throw CommandException.wrongNumberOfParameters(context);
}
instanceManagementService.showInstanceManagementInformation(context.getOutputReceiver());
}
}