Calling Programs
Calling programs or command line scripts is a very powerful feature that can be used to check configuration of the system or perform advanced automation steps.
Additionally, you can access information about the underlying system, e.g. the operating system type/name and environmental variables in order to tailor your script to work across multiple os types.
Because of the power of this automation, it can be disabled centrally by using the Security.EnableOSCodeExec parameter from the Administration > Settings page.
Options are to disable globally, enable only for non-root users and enable globally.
Code Walkthrough
The global variable os is the key object to allow access to the underlying operating system and information about the operating system in use.
Calling a simple program
In the following very simple check we will use the built in command whoami to report back the user that the agent is running under.
Using the method exec(..) we can simply call the command. This method returns an ExecResult object and the command line output is simply available on the out property. In this simple check, we set that to the check message property to create a simple JavaScript based custom check that can be run on all monitored system types:
const agentUser = os.exec("whoami");
check.message = agentUser.out;
Handling Errors
The above example works for simple commands that you know will execute, but perhaps this command could also throw an error which would need to be checked. The ExecResult object has a property exitCode that can be used to control the flow of your check.
let willFail;
try {
willFail = os.exec("this_doesnt_exist");
} catch (e) {
// Catch any exception (raised on Windows)
// and create an object with our results:
willFail = {
out: e.getMessage(),
exitCode: -1
};
}
// Format the message output as the command output
check.message = willFail.out;
if (willFail.exitCode != 0) {
// Handle the error case
// check.status is by default OK
check.status = CRITICAL;
}
This check will always fail (unless for some reason you have a command called this_doesnt_exist available) to demonstrate this feature. We always set the check message to contain the output the command produced, in this case something like command not found is printed but this depends on the operating system. And we set the status of the check to CRITICAL in this error case.
Handling OS differences
Sometimes the command to execute will differ between operating systems. You can use the osName property to differentiate between operating systems in your landscape and call different commands, or add different options depending on the type. This means you have a single custom check that can be rolled out to all servers rather than needing to define specific system selectors for different checks and future changes in check logic need only be made in one place.
Using the osName property is simple as seen in this example that will output the running processes in both Windows and Linux environments.
const isWindows = os.osName.toLowerCase().indexOf("windows") > -1;
let cmd = '';
if (isWindows) {
cmd = "tasklist";
} else {
cmd = "ps aux"
}
check.message = os.exec(cmd).out;
The check message is simply the text output, you could extend this check further to create a table of results. Note that the different operating systems commands return the information in different formats, and on Windows, the line endings are different and may need to be handled differently. See the examples section for the full code for this.
Developing such multi-os checks are accelerated with the test run feature for custom JavaScript checks. Here you can add multiple systems (choose one Linux and one Windows) and see the result of your changes in both systems immediately.
Using Cloud APIs
With the cloudMetaData property on the os global object, we also have access to information the virtualization provider has about this virtual machine. For example in Google Cloud Platform (GCP):
const cloudMD = os.cloudMetaData;
if (cloudMD) {
const project = cloudMD["project-id"];
const name = cloudMD.name;
console.log(`Running in GCP ${project} / ${name}`);
}
The structure of cloudMetaData is dependant on the cloud/virtualization provider in use and can be changed at any time by the provider.
You can console.log(JSON.stringify(os.cloudMetaData)) to work out what properties are available in your scripts while developing.
Examples
Example: Get the content of the /opt directory
The example is a bit silly, but it demonstrates how it works. Simply create a JavaScript based custom check (RUN_JS) for a Linux server, copy & paste the code example below, and you can see it work.
const result = os.exec("sh -c 'ls -al /opt'");
if (result.exitCode === 0) {
check.status = OK;
check.message = "The content of directory /opt is:\n";
}
else {
check.status = WARNING;
check.message = "Command failed!\n";
}
check.message = check.message + result.out;
Example: Cross-Platform Process List
This example is an extension of the cross-platform code walkthrough that will format the output of the process list command in a custom check.
const isWindows = os.osName.toLowerCase().indexOf("windows") > -1;
// on Windows, we call 'tasklist'
// whereas on Linux based systems it's 'ps aux'
const cmd = isWindows ? "tasklist" : "ps aux";
// Each command has a different number of header rows
const skipRows = isWindows ? 3 : 1;
// Call the command and split the output by each line
const rows = os.exec(cmd).out.split('\n');
// Create a table output with two columns:
// | PID | Name |
check.addTableColumn("PID");
check.addTableColumn("Name");
// Process each row
rows.forEach((row, index) => {
// Skip the header rows
if (index < skipRows) return;
// Split the row by whitespace
const parts = row.split(/\s+/);
if (parts.length > 1) {
// Create a new row in the table
check.newRow();
// The process id is always 2nd in the table
const pid = parts[1];
// The name of the process is in different columns
const name = isWindows ? parts[0] : parts[10];
// Add the data to the check output
check.addCell(pid);
check.addCell(name);
}
});
API Reference
Global Variable os
The global variable os is used to access the operating system of the managed object. Using the powerful exec methods allow access to collect information or perform actions by executing built in or custom programs at the operating system level.
canOsExec
canOsExec(): boolean
Test if os calls can be executed or not
Since: 25.1.0
Returns: boolean - true when os calls can be executed, false otherwise
exec
exec(commandLine: string): ExecResult
Execute a command on the operating system of the Agent.
Specify a shell/terminal command to execute as you would enter a command in a command line environment directly on the operating system. Please note that operating system commands may be disabled by system-wide settings.
If the command creates files or performs tasks, make sure to clean up after the command has been executed.
This command will wait for 30s before exiting.
Parameters
commandLine(string) - command line argument to execute
Returns: ExecResult - the result of the execution
exec
exec(commandLine: string, timeoutMs: number): ExecResult
Execute a command on the operating system of the Agent.
Specify a shell/terminal command to execute as you would enter a command in a command line environment directly on the operating system. Please note that operating system commands may be disabled by system-wide settings.
If the command creates files or performs tasks, make sure to clean up after the command has been executed.
This command will wait for the specified time given in ms to the parameter timeoutMS before exiting.
Parameters
commandLine(string) - command line argument to executetimeoutMs(number) - the timeout in ms to wait until failure
Returns: ExecResult - the result of the execution
execSSH
execSSH(credentials: any, commandLine: string): ExecResult
Executes the given command with the user set in credentials (with no timeout).
Example:
// Use with automation credentials:
const osCmd = os.execSSH(action.input.otherUser, 'id');
console.log(osCmd.exitCode); // Print exit code
console.log(osCmd.out); // Print command result
Since: 21.11.4
Parameters
credentials(any) - the credentials used to execute the commandcommandLine(string) - command line argument to execute
Returns: ExecResult - the result of the execution
execSSH
execSSH(credentials: any, commandLine: string, timeoutMs: number): ExecResult
Executes the given command with the user set in credentials.
Example:
// Use with automation credentials:
const osCmd = os.execSSH(action.input.otherUser, 'id', 10000);
console.log(osCmd.exitCode); // Print exit code
console.log(osCmd.out); // Print command result
Since: 21.11.4
Parameters
credentials(any) - the credentials used to execute the commandcommandLine(string) - command line argument to executetimeoutMs(number) - the timeout in ms to wait until failure (set to 0 for no timeout)
Returns: ExecResult - the result of the execution
getCloudMetaData
getCloudMetaData(): any
If the monitored object is running on a supported hyper-visor environment, e.g. Google Compute Platform, return a JSON object of information we've retrieved about this virtual machine and this environment.
Avantra uses this information to enrich our landscape information in the server UI, however a check developer could use this information to perform additional web API calls to perform actions on this environment or to report other useful information back to Avantra.
Since: 21.11
Returns: any - a JSON object or null if not running on a supported hyper-visor
See Also: cloudMetaData
getOsName
getOsName(): string
Return the type of operating system that this Agent is running on.
This can be used to tailor specific commands to the operating system in use so that the checks or automation can be made generic across OS type.
Returns: string - the name of the underlying operating system
See Also: osName
getenv
getenv(name: string): string
Returns the value of a specific environment variable set for this execution of the check on the Agent.
Parameters
name(string) - the name of the environment variable
Returns: string - the value of the environment variable
sleep
sleep(milliseconds: number): void
Causes the current script execution to sleep for the specified number of milliseconds. It is highly recommended to use this sleep function to pause a script execution.
Since: 23.0
Parameters
milliseconds(number) - the length of time to sleep in milliseconds
cloudMetaData
readonly cloudMetaData: any
If the monitored object is running on a supported hyper-visor environment, e.g. Google Compute Platform, return a JSON object of information we've retrieved about this virtual machine and this environment.
Avantra uses this information to enrich our landscape information in the server UI, however a check developer could use this information to perform additional web API calls to perform actions on this environment or to report other useful information back to Avantra.
Accessors
Type: any
Modifiers: readonly
Since: 21.11
osName
readonly osName: string
Return the type of operating system that this Agent is running on.
This can be used to tailor specific commands to the operating system in use so that the checks or automation can be made generic across OS type.
Accessors
Type: string
Modifiers: readonly
Class ExecResult
This class captures the response of executing a command on the operating system.
getExitCode
getExitCode(): number
Returns the exit code from executing the command
Returns: number - the exit code of the command executed
See Also: exitCode
getOut
getOut(): string
Returns the output of the command (i.e. the output of the command line console when the command is executed).
Returns: string - the console output/result of the command
See Also: out
exitCode
readonly exitCode: number
The exit code of the command executed
Accessors
Type: number
Modifiers: readonly
out
readonly out: string
The command line output of the command executed.
Accessors
Type: string
Modifiers: readonly