# 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 os global variable 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 commandes 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 virtualisation 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/virtualisation 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 1. 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 2. 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.

#### 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 execute

  - `timeoutMs`: 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 command

  - `commandLine`: 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 command

  - `commandLine`: string

    command line argument to execute

  - `timeoutMs`: 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.

See Also

  - getCloudMetaData()

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.

See Also

  - getOsName()

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

See Also

  - getExitCode()

Type

  number

Modifiers

  Readonly

#### out

    readonly out: string

The command line output of the command executed.

See Also

  - getOut()

Type

  string

Modifiers

  Readonly