ProcessRunner

From Dreamtsoft Wiki
Jump to: navigation, search
/**
* Allow script mappers to run external processes
* 
* Usage
*   Usage from a script mapper:
* 
* 		var runner = new ProcessRunner(executable_name);
* 		runner.addArgument(arg0);
* 		runner.addArgument(arg1);
* 		...
* 		int_ExitValue = runner.executeCommand()
*
*   This code will run an external process with 2 arguments and wait for the process to exit before returning.  The
*   exit value from the command will be returned by the executeCommand call. 
* 
* 
* Handling output
*   If the calling ScriptMapper has a 'onOutput' method defined, then each time the external process generates a 
*   line of output on either stdout or stderr, the onOutput method will be called using the following signature:
* 
* 		onOutput(type, line)
* 
* 		The type is one of:
* 			stdout - stdout output from the process
*			   stderr - stderr output from the process
*			   error - error from running the process (ie, not allowed, exception occurred that we caught)
* 
*   If 'onOutput' is not defined in the Script Mapper, stdout and stderr are collected while running the process
*   and are available when the process completes using:
* 
* 		lines[] = runner.getStdout();
* 		lines[] = runner.getStderr();
* 		errorString = runner.getErrorMessage();
*
*  There are cases in which there is an onOutput method defined in the script mapper, but a specific call to
*  executeCommand should not use onOutput, but rather gather the output for a call to runner.getStdout() after
*  the command has completed.  This occurs, when the script mapper handles different actions with some using onOutput
*  and some using getStdout.  To support this, call executeCommandWithOutput:
*
*       runner.executeCommandWithOutput()      // this will buffer all output for use with getStdout() instead of calling onOutput
*
* Whitelisting processes that may be executed
*   In order for a process to be executed, the executable_name must be in the whitelist of 
*   processes in the work/setup/whitelist.config file:
* 
* 		{ processes: [ "name1", "name2", etc. ] }
*
*   By default, there are no processes in the whitelist.
* 
* 
* Running as sudo
*   To run the command as 'sudo', before calling 'executeCommand' call:
* 
* 		runner.sudo();
* 
*   Note that to use this sudo support, 'sudo' should NOT be in the whitelist.  However, any
*   command that is to be executed must be in the whitelist.  As added security, it is 
*   recommended that you also configure the DataService user in the sudo config (at the unix 
*   system level) to allow NOPASSWD and specify the list of commands that are allowed to be 
*   executed as sudo.  The sudo config file should contain something like:
* 
* 		dataservice_user ALL = NOPASSWD: /bin/ls, /bin/cat
*
* Running with nohup
*   To run the command with nohup, before calling 'executeCommand' call:
*
* 		runner.nohup();
* 
* Providing standard input
*   Passing a string to standard input when running the process, use this API before calling 
*   executeCommand():
* 
* 		runner.setInput(string_to_use_as_stdin);
* 
* 
* Running command asynchronously
*   If you want to spawn the external process and not wait until the process exits, there are a few additional
*   requirements to support this.  First, use .executeCommandAsync() instead of .executeCommand() to run the
*   external process so that it does not block waiting for completion.  You must call 'this.startAsync()' before 
*   returning from the Script Mapper command you are executing.  This allows the executed process to continue 
*   running while sending the output lines to the Script Mapper's onOutput callback.  In the onOutput callback, 
*   the Script Mapper may generate websocket events using 'this.broadcast'.  When the executed process completes, 
*   the Script Mapper's onComplete method is called.
*   
*   So, the way to run a Script Mapper that executes a process asynchronously:
*   
*   	- in the script mapper method:
*   	- call processRunner.executeCommandAsync()
*   	- call this.startAsync()
*   	- provide an onOutput() method
*   	- call this.broadcast() when needed based on output from the process
*   	- provide an onComplete() method if handling the completion of the process is needed
*   		- in this onComplete() method call this.stopAsync()
*	
*	The onComplete method has the following signature:
*
* 		onComplete(exitValue, errorMessage)
* 
*/

The following APIs are available to Script Mappers using the ProcessRunner object:

/**
 * Add an argument to the command line
 */
addArgument(String arg)
/**
 * Provide a string as standard input to the process to run. This must be
 * called before calling executeComand()
 */
setInput(String input)
/**
 * Set the exit value that indicates success
 */
setExitValue(int value)
/**
 * Set the timeout for a process execution as seconds
 *
 * If this is set and the process runs longer than this time, the process will be killed and 
 * a 143 (SIGTERM) error will be returned by the ProcessRunner.
 */
setTimeout(int seconds);
/**
 * Use 'sudo' to run command
 */
sudo()
/**
 * Use 'nohup' to run command
 */
nohup()
/**
 * Execute the command, waiting for it to complete.
 * 
 * @return exit value from process that was executed or one of these values:
 * 
 * 			  2: process not found or not on whitelist 
 * 			 -1: IOException occurred
 */
int executeCommand()
/**
 * Execute the command, waiting for it to complete and buffer output (do not call onOutput if it exists).
 *
 * @return exit value from process that was executed or one of these values:
 *
 * 			  2: process not found or not on whitelist
 * 			 -1: IOException occurred
 */
int executeCommandWithOutput()
/**
 * Execute the command, do not wait for it to complete, but rather return immediately after starting
 * 
 * @return exit value from process that was executed or one of these values:
 * 
 * 			  2: process not found or not on whitelist 
 * 			 -1: IOException occurred
 */
int executeCommandAsync()
/**
 * Cancel a currently async running command
 *
 * When this is called, the process will be killed a 143 (SIGTERM) error will be 
 * returned by the ProcessRunner when it calls the onComplete callback.
 */
cancel();
/*
 * Return true if the call to execute the command resulted in an error
 */
boolean hasErrorMessage()
/*
 * Return the error message that resulted from the exeuction of the command
 */
String getErrorMessage()
/*
 * If 'onOutput' is not defined in the Script Mapper or executeCommandWithOutput was called, 
 * standard outout lines are collected while running the process and are available when the process 
 * completes using this method
 */
Array[String] getStdout()
/*
 * If 'onOutput' is not defined in the Script Mapper or executeCommandWithOutput was called, 
 * standard error lines are collected while running the process and are available when the process 
 * completes using this method
 */
Array[String] getStderr()