See bug 13034 for background.

start-instance/create-instance/delete-instance all need to do roughly the following:

  1. Validate parameters
  2. Construct the command to run
  3. Construct the human version of command we want the user to run if the DAS fails to run it
  4. Log what is being run
  5. Execute command on Node: handle remote and local
  6. Handle errors:
    1. SSH connection/execution failure
    2. ProcessManager execution failure
    3. Wrong node type (config node when ssh node needed)
    4. Command runs but returns status != 0
  7. Log appropriate information
  8. Return appropriate information to the user

Steps 5+6 have the most complexity. Each command does them slight differently. I propose we create a new method (possibly in a new class: NodeRunner):

public int executeCommandOnNode(Node node, StringBuilder ouput,
                                String command, String... args)
   throws SSHCommandExecutionException, ProcessManagerException,
          IllegalArgumentException

usage wold be like

command = new ArrayList();
humanVersionOfCommand = new ArrayList();
node = Nodes.getNodeByName(name);

// Build commands as needed
command.add("--node");
humanVersionOfCommand.add("--node");
command.add("n1");
humanVersionOfCommand.add("--node");
//. . .

RemoteCommandHelper rch = new NodeRunner(Habitat habitat, Logger logger);

output = new StringBuilder();
try {
    int status = rch.executeCommandOnNode(node, output, "asadmin", command.toArray());
    if (status != 0) {
      // handle logging and return status
    }
} catch (SSHCommandExecutionException e) {
    Throwable cause = ExceptionUtil.getRootCause(e);
    // handle it
} catch (ProcessManagerException e) {
    Throwable cause = ExceptionUtil.getRootCause(e);
    // handle it
} catch (IllegalArgumentException e) { 
   // handle it
}

There is also a smattering of utility methods that should be formalized and shared – I think as DuckTypes on the Node or Nodes config bean:

  • Node.isLocalHost()
  • Node.getLocalInstanceDir()
  • Nodes.getNodeByName()