Script Functions

Overview

Script functions execute a named bash or Python script located in the /opt/atsd/atsd/conf/script directory and return the script stdout and stderr output.

Common Use Cases

  • Check the TCP availability of a remote host.
  • Check that the remote host is reachable via ICMP ping.
  • Check that an HTTP/S request to a URL returns HTTP 200 OK status code.
  • Execute a diagnostics command on a remote host.
  • Retrieve configuration information from the remote device or host.
  • Analyze data using Python and prepare a report in HTML or plain text format.

Syntax

scriptOut(string file [, array arguments])
  • [Required] file: Name of the executable script file located in the /opt/atsd/atsd/conf/script directory.
  • [optional] arguments: Array of arguments passed to the script. Can be an empty list.

Arguments

The arguments can include literal values or window placeholders.

scriptOut('disk_size.sh', [entity, tags.file_system])

Literal string arguments must be enclosed in single quotes.

scriptOut('check_site.py', ['example.org', 3])

If no arguments are required, invoke the script without arguments or by passing an empty array [].

scriptOut('check_service.sh')

The script must execute within a timeout.

Variables

As an alternative to passing arguments, the script can access window fields and user-defined variables as environment variables.

#!/usr/bin/env bash

# access window fields by name
ent=${entity}
...

Timeout

A script must execute within the timeout specified on the Scripts tab. If this timeout is set to Default, the timeout value is inherited from the system.commands.timeout.seconds server property. The default timeout is 15 seconds.

If the script times out, its process is stopped with SIGTERM and the following text is appended to the output:

Script terminated on timeout: {current timeout value}

Permissions

Scripts must be located in the /opt/atsd/atsd/conf/script directory and have the permission bit +x enabled.

chmod u=rwx,g=rx,o=r /opt/atsd/atsd/conf/script/*

Scripts are executed under the axibase user context.

To execute a Python script without the python interpreter, make the script executable and instruct the kernel which interpreter to use by adding a shebang line #!/usr/bin/env python at the beginning of the script.

$ cat check_site.py
#!/usr/bin/env python

from atsd_client import connect, connect_url
from prettytable import PrettyTable
...

Execute the Python script by specifying its file name, similar to bash scripts.

scriptOut('check_site.py', ['example.org', 3])

Review Daily Referer Requests script as an example.

Formatting

Format the output of the scriptOut function when using markdown (chat messages) or with <pre> tag when using HTML (email).

Markdown Format

HTML Format

Examples

ping

Script to ping a host n times.

Script

#!/usr/bin/env bash

host=${1}
count=${2}

ping -c ${count} ${host}

Function

Host ping report:

${scriptOut('ping.sh', ['example.org', '3'])}

Command

ping -c 3 example.org

Output

PING example.org (192.0.2.1) 56(84) bytes of data.
64 bytes from example.org (192.0.2.1): icmp_seq=1 ttl=52 time=45.5 ms
64 bytes from example.org (192.0.2.1): icmp_seq=2 ttl=52 time=40.0 ms
64 bytes from example.org (192.0.2.1): icmp_seq=3 ttl=52 time=43.9 ms

--- example.org ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 40.078/43.189/45.588/2.305 ms

Outgoing Webhooks

Telegram:

Discord:

Slack:

traceroute

Script returns traceroute output to host.

Script

#!/usr/bin/env bash

kill_after=${1}
host=${2}
dir=$(dirname $(readlink -f $0))

timeout ${kill_after}s traceroute ${host} 2>${dir}/error

if [ $? != 0 ] && [ $(wc -c < ${dir}/error) == 0 ]; then
  echo -e "\nExceeded ${kill_after} seconds"
else
  cat ${dir}/error
fi

rm  ${dir}/error

Function

Trace report:

${scriptOut('traceroute.sh', ['3', 'example.org'])}

Command

timeout 3 traceroute example.org

Output

traceroute to example.org (192.0.2.1), 30 hops max, 60 byte packets
 1  NURSWGVML102(192.0.2.1)  0.149 ms  0.059 ms  0.032 ms
...
 6  example.org (192.0.2.1)  0.348 ms  0.363 ms  0.308 ms

Outgoing Webhooks

Telegram:

Discord:

Slack:

top

Script returns output of top in batch mode from a remote server. SSH key is stored in a pre-defined location.

Script

#!/usr/bin/env bash

host=${1}
user=${2}
count=${3}
delay=${4}
rows_n=${5}

ssh -i /home/axibase/.ssh/def.key ${host} top -u ${user} -b -n ${count} -d ${delay} | head -n ${rows_n}

Function

${scriptOut('top.sh', ['nurswgvml006','www-data', '1', '1', '15'])}

Command

ssh -i /home/axibase/.ssh/def.key nurswgvml006 top -u www-data -b -n 1 -d 1 | head -n 15

Output

top - 13:01:25 up 96 days, 23:05,  1 user,  load average: 0.02, 0.04, 0.05
Tasks: 139 total,   1 running, 138 sleeping,   0 stopped,   0 zombie
%Cpu(s):  1.3 us,  0.6 sy,  0.0 ni, 97.8 id,  0.2 wa,  0.0 hi,  0.1 si,  0.0 st
KiB Mem:   2049052 total,  1951460 used,    97592 free,    25364 buffers
KiB Swap:        0 total,        0 used,        0 free.  1363820 cached Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 8831 www-data  20   0  346044  67436  50140 S   0.0  3.3   0:05.49 php5-fpm
10145 www-data  20   0  341676  58756  45816 S   0.0  2.9   1:16.71 php5-fpm
21890 www-data  20   0  338204  54772  43288 S   0.0  2.7   0:14.65 php5-fpm
25001 www-data  20   0   94860   8576   2724 S   0.0  0.4  55:42.36 nginx
25002 www-data  20   0   93864   7488   2552 S   0.0  0.4  56:01.59 nginx
25003 www-data  20   0   93816   6408   1536 S   0.0  0.3  53:06.12 nginx
25005 www-data  20   0   96512   8184    696 S   0.0  0.4  54:38.85 nginx
28047 www-data  20   0  339860  57372  44236 S   0.0  2.8   0:02.34 php5-fpm

Outgoing Webhooks

Telegram:

Discord:

Slack:

ps

Script returns ps output for the specified grep pattern from a remote server.

Script

#!/usr/bin/env bash

host=${1}
pattern=${2}

ssh -i /home/axibase/.ssh/def.key ${host} ps aux | grep ${pattern}

Function

Output is:
${scriptOut('ps.sh', ['example.org','bash'])}

Command

ssh -i /home/axibase/.ssh/def.key example.org ps aux | grep bash

Output

axibase      1  0.0  0.0  19712  3304 ?        Ss   11:07   0:00 /bin/bash /entrypoint.sh
axibase   2807  0.0  0.0  19828  3464 ?        S    11:09   0:00 bash /opt/atsd/hbase/bin/hbase-daemon.sh --config /opt/atsd/hbase/bin/../conf foreground_start master

Outgoing Webhooks

Telegram:

Discord:

Slack:

URL availability

Script tests URL availability.

Script

#!/usr/bin/env bash

url=${1}
dir=$(dirname $(readlink -f $0))
status=$(curl -sS -L --insecure -X GET -m 10 -D ${dir}/headers -w "\nResponse Time: %{time_total}\n" "${url}" > ${dir}/response 2>&1)
if [[ $? == 0 ]] ; then
  code=$(head -n 1 ${dir}/headers | grep -oiE "[0-9]{3}[a-z ]*")
  echo "Status code: ${code}"
  echo "$(tail -n 1 ${dir}/response)" # Response Time
  length=$(head -n -1 ${dir}/response | wc -c)
  echo "Content Length: ${length} bytes"
  grep "Location:" ${dir}/headers
else
  head -n 1 ${dir}/response
fi

rm  ${dir}/response  ${dir}/headers

Function

${scriptOut('url_avail.sh', ['https://example.org'])}

Command

curl -sS -L --insecure -X GET -m 10 -D /opt/atsd/atsd/conf/script/headers \
  -w "\nResponse Time: %{time_total}\n" "https://example.org" > /opt/atsd/atsd/conf/script/response 2>&1

Output

Status code: 200 OK
Response Time: 0.618
Content Length: 35214 bytes

Outgoing Webhooks

Telegram:

Discord:

Slack:

TCP availability

Script tests TCP availability.

Script

#!/usr/bin/env bash

kill_after=${1}
host=${2}
port=${3}

timeout ${kill_after} bash -c "</dev/tcp/${host}/${port}"

if [[ $? -eq 0 ]]; then
   echo "TCP port ${port} is available"
else
   echo "TCP port ${port} is unavailable"
fi

Function

Output is: ${scriptOut('tcp.sh', ['2','example.org', '443'])}

Command

timeout 2 bash -c "</dev/tcp/example.org/443"

Output

TCP port 443 is available

Outgoing Webhooks

Telegram:

Discord:

Slack:

osquery

Script executes an osquery request against a remote server.

Script

#!/usr/bin/env bash

host=${1}
query=${2}

ssh -i /home/axibase/.ssh/def.key ${host} "osqueryi \"${query}\""

Function

${scriptOut('osquery.sh',
            ['example.org',
            "SELECT DISTINCT processes.name, listening_ports.port, processes.pid FROM listening_ports " +
            "JOIN processes USING (pid) WHERE listening_ports.address = '0.0.0.0';"])}

Command

ssh -i /home/axibase/.ssh/def.key example.org \
      'osqueryi "SELECT DISTINCT processes.name, listening_ports.port, processes.pid FROM listening_ports \
      JOIN processes USING (pid) WHERE listening_ports.address = '\''0.0.0.0'\'';"'

Output

+------+-------+------+
| name | port  | pid  |
+------+-------+------+
| java | 50010 | 9112 |
| java | 50075 | 9112 |
| java | 50020 | 9112 |
| java | 50090 | 9365 |
| java | 50070 | 8921 |
+------+-------+------+

Outgoing Webhooks

Telegram:

Discord:

Slack:

Daily Referer Requests

Python script generates a daily http_referer report in HTML format based on messages collected by the nginx_access_log_tail script.

Function

${scriptOut('daily_referer_requests.py')}

Command

./daily_referer_requests.py

Output

<table>
    <tr>
        <th>Date</th>
        <th>URI</th>
        <th>Referer</th>
        <th>IP</th>
        <th>Org</th>
    </tr>
    <tr>
        <td>2018-06-14 03:58</td>
        <td>/</td>
        <td>https://example.org/</td>
        <td>192.0.2.1</td>
        <td>Example Org</td>
    </tr>
    <tr>
        <td>2018-06-14 20:43</td>
        <td>/chartlab/2ef08f32</td>
        <td>https://example.org/</td>
        <td>192.0.2.1</td>
        <td>Example Org</td>
    </tr>
</table>