DRSM Documentation Live demo Downloads

Plugins

Every DRSM check is a plugin: a folder with a small manifest and one BASH script. bin/drsm_run.sh finds the plugins each host needs, runs them, and writes the reports the dashboard and alerts use. Adding a check means adding a folder, not editing a core script.

Plugins included

PluginRuns onChecks
core/cpuhostCPU usage, steal time, top processes, CPU temperatures
core/loadhost15 minute load average against the CPU count
core/memoryhostAvailable memory, swap use, top processes
core/usershostLogged in users, alerts for listed user names
storage/diskhostSpace and inodes on every local file system
storage/raidhostmdadm software RAID, LSI MegaRAID drives
storage/diskiohostDisk read and write operations and bytes, for IOPS and throughput trends
cloud/awshostAWS EC2 instance type, zone, public IPv4 and EBS volume sizes from instance metadata
network/nicshostInterface errors, drops and collisions
network/pingmonitorHost answers ping
network/httpmonitorHTTP service answers
network/httpsmonitorHTTPS service answers with a valid certificate
network/ftpmonitorFTP service answers
windows/checkinagent reportWindows host reported recently, complete report, agent version
windows/defenderagent reportDefender threats, protection turned off, old definitions
windows/patchesagent reportAge of the newest Windows patch
windows/appsagent reportRequired and forbidden installed programs
windows/resourcesagent reportCPU, memory, commit charge, disk space and network use, agent 3.3 and later

These are the checks from bin/*_checks.sh and system_check.sh with the same messages and default levels. Their settings are listed in Thresholds and alerts.

Running checks with drsm_run.sh

$ ~/drsm/bin/drsm_run.sh -l             # list hosts and the plugins that would run
$ ~/drsm/bin/drsm_run.sh -n             # all hosts, no alerts
$ ~/drsm/bin/drsm_run.sh -n -H cloud1   # one host
$ ~/drsm/bin/drsm_run.sh -n -g dev      # the dev group
$ ~/drsm/bin/drsm_run.sh -m probes      # connectivity probes only
OptionMeaning
-s org/siteOne site, default every site this monitor host runs, one after the other
-g groupHost group (tier), default production, which ops also names. Before migration -g dev reads dev_systems.dat
-H hostOne host only, for testing. org/site/host when two sites have a host with that name
-m probesConnectivity probes only, the old system_check.sh job. Default all
-eEmail a status report even when everything passes
-nDo not send alerts
-lList hosts and plugins, then exit
-vVerbose

Exit code: 0 all good, 1 warnings, 2 errors.

Host files

One file per host in etc/hosts, named <host>.conf. The files are plain KEY=value lines, read but never run, so a typo cannot execute anything. Values with spaces go in double quotes.

HOST=cloud1
DESCRIPTION="AWS web server"
IMPACT="Public website is down"
GROUP=production
PLATFORM=linux
COLLECTOR=ssh
PROBES="network/ping network/https"
PLUGINS="storage/disk storage/raid core/cpu core/load core/memory network/nics core/users"

# Plugin settings: <category>_<name>_<SETTING>=value
storage_disk_WARN=85
storage_disk_SKIP="/mnt/scratch"
network_https_URL=https://www.example.com/
core_cpu_TIMEOUT=60
KeyMeaning
HOSTName or address for SSH and probes, default is the file name
DESCRIPTION, IMPACTShown in reports and alerts
SITEOrganization and site, <org>/<site>, see Ansible inventoryOrganizations and sites
GROUPHost group and tier: ops (or production, the default), dev or qa, picked with drsm_run.sh -g
PLATFORMlinux or windows
COLLECTORssh, local for the monitor host itself, wra for Windows Reporting Agent hosts, none for probes only
ENABLEDno skips the host
PROBESPlugins run from the monitor host against this host
PLUGINSPlugins run on the host

_defaults.conf is read before every host file, so put the common PLUGINS list and site wide settings there. Files starting with _ are not hosts. If network/ping fails the host is reported down and its remote plugins are skipped.

To convert systems.dat, dev_systems.dat and the custom levels in <host>_profile.sh scripts, run utils/migrate_systems_dat.sh.

Ansible inventory

If your Linux hosts are already in an Ansible inventory, DRSM can use it as its host list, so there is one list to keep. Add to ~/.drsm.sh:

export ANSIBLE_INVENTORY=/etc/ansible/hosts
export ANSIBLE_TIERS="production=prod qa=qa dev=dev"   # tier=group[,group]
export ANSIBLE_DEFAULT_TIER=""                          # tier for other hosts, empty leaves them out
export ANSIBLE_SHORT_NAMES=yes                          # web1.example.com becomes web1
export ANSIBLE_EXCLUSIVE=no                             # yes: Linux hosts only from Ansible

With ANSIBLE_EXCLUSIVE=yes, Linux host files of hosts the inventory does not list are skipped, so removing a host from Ansible stops its checks from the next run; Windows and other host files still run, and so do probe only hosts (PLUGINS="" or COLLECTOR=none, such as cluster addresses). Its last report stays on the dashboard, shown as not reporting, until utils/drsm_remove_host.sh <host> --apply removes it.

Hosts in a group named in ANSIBLE_TIERS, or in any group under it through [group:children] at any depth, are checked as Linux hosts over SSH in that tier, with the _defaults.conf plugins. A host in two tiers goes to the first one listed. A host file with the same short or full name, or the same HOST=, adds settings such as DESCRIPTION, PLUGINS or plugin levels, but the tier always comes from Ansible. Host files for hosts Ansible does not list, such as Windows hosts and network devices, work as before. Check the result with drsm_run.sh -l.

Ansible Automation Platform or AWX

To read the inventory from Ansible Automation Platform (AAP, formerly Ansible Tower) or AWX instead of a file:

export ANSIBLE_AAP_URL=https://aap.example.com
export ANSIBLE_AAP_INVENTORY=12                     # ID or name
export ANSIBLE_AAP_TOKEN_FILE=~/.drsm_aap_token     # OAuth2 token, mode 600
export ANSIBLE_AAP_CA_FILE=""                       # CA bundle for a private CA
export ANSIBLE_AAP_CACHE_MINUTES=15
export ANSIBLE_AAP_API=""                           # empty tries /api/controller/v2, then /api/v2

DRSM fetches the inventory script (<api>/inventories/<id>/script/) with curl and jq, keeps an INI copy in $VARdir for the cache time and reads it like a local inventory with ANSIBLE_TIERS. AAP 2.5 and later serve the controller API at /api/controller/v2, older AAP, Tower and AWX at /api/v2; both are tried. The older ANSIBLE_TOWER_* names of these settings still work. If the platform cannot be reached, the last good copy is used and a warning is printed. A read-only token is enough; it is sent from a header file, not on the command line. utils/drsm_ansible_hosts.sh (-f to fetch now) lists the hosts and tiers DRSM takes from either source.

INI inventories are read: [group], [group:children], numeric ranges such as web[01:03].example.com; [group:vars] and host variables are skipped. YAML inventories are not read; ansible-inventory -i inv.yml --list can show their groups for an INI copy.

Organizations and sites

To monitor several customers or offices from one dashboard, put hosts in organizations and sites: organization > site > group > host. Each site has its own reports, alerts and card on the Organizations page, and two sites may have a host with the same name. Hosts in no site are in the default/default site, which keeps the reports where they have always been, so nothing changes until you add a site.

etc/sites/acme.org            # NAME="Acme Corp", CONTACT="..."
etc/sites/acme/hq.site        # the hq site of acme
Site keyMeaning
NAME, LOCATIONShown on the Organizations page
TZTime zone for the site's report times
ALERT_EMAILAlert addresses for the site, in place of alert.email.list
LINKA Site links menu entry, LINK="Menu/Submenu/Name|https://url|tier". Also in org files
ALERT_EMAIL_<TIER>Alert addresses for one tier at the site, for example ALERT_EMAIL_DEV, else ALERT_EMAIL
STALE_MINUTESWhen a host, or the site's monitor host, counts as not reporting, default 60
COLLECTOR_IDThe monitor host that runs the site. Others skip it. Unset, any monitor host runs it

Any host key or plugin setting in a site file is a default for the site's hosts, read after _defaults.conf and before the host file. GROUP is one too, so a whole site can be a QA or DEV site. A host joins a site with SITE=<org>/<site>, or every host of a monitor host with DRSM_SITE in ~/.drsm.sh. IDs use a-z, 0-9, _ and -.

Site reports go to reports/orgs/<org>/<site> with the usual layout inside, plus site.json. Each site has its own lock, log and alert throttle, and the alert subject names the site. Plugins get DRSM_ORG and DRSM_SITE.

ToolDoes
utils/drsm_migrate_sites.sh org/site [host ...]Moves hosts and their reports from the default site into a site, dry run unless --apply
utils/drsm_remove_site.sh org/siteRemoves a site's hosts, site file and reports, dry run unless --apply
utils/drsm_add_collector.sh org/sitePrints the setup for a monitor host that runs one site, with an SSH key line limited by rrsync to the site's folder on the dashboard
utils/drsm_web_sync.shCopies each site to its own folder on the dashboard, so several monitor hosts can feed one dashboard

Tiers

GROUP sorts hosts into tiers: dev, qa and ops. The dashboard shows them as DEV, QA and OPS, with a tier filter on the Organizations, Heat map and Hosts pages. ops is another name for production, the default group: ops hosts run with the production hosts, write the production report names with no _<group> suffix and get texts, so existing production files keep their names. Run each tier from cron:

15,45 * * * * ~/drsm/bin/drsm_run.sh &> /dev/null                # OPS
55 09-16 * * mon-fri ~/drsm/bin/drsm_run.sh -g dev &> /dev/null
55 09-16 * * mon-fri ~/drsm/bin/drsm_run.sh -g qa &> /dev/null

DEV and QA alerts never send texts. A site file can send each tier's alerts to its own addresses with ALERT_EMAIL_DEV, ALERT_EMAIL_QA and ALERT_EMAIL_OPS. A tier without one uses ALERT_EMAIL, then alert.email.list. Other group names still work and show as their own tier, in upper case.

Site and org files can list links for the dashboard's Site links menu, one LINK line each:

LINK="Wiki|https://wiki.example.com/"
LINK="Grafana/Database|https://grafana.example.com/d/db"
LINK="Apps/OSA/Admin|https://osa.example.com/admin|ops"

The first field is the name, and each / in it makes a submenu, up to six levels. The second is the URL: only http and https links are kept, others are reported by drsm_run.sh and skipped, and the dashboard checks them again. The optional third field is a tier: the link shows only when the tier filter is All or that tier. Links in <org>.org show for every site of the organization, in an Org links section of the same menu.

drsm_run.sh puts the links in site.json, so drsm_web_sync.sh takes them to a hosted dashboard, and users only see the links of sites they may see.

Windows hosts

Windows hosts run the Windows Reporting Agent, a small Windows service from the agent distribution. Every 45 minutes it sends a text report (installed programs, Windows Defender events, Windows Update history, hotfixes, users, IP addresses) to the monitor side by signed HTTPS upload, a CIFS share, or SCP. DRSM never connects to the Windows host: the wra collector runs the windows/* plugins on the monitor host against each host's last report, $WRA_REPORTS_DIR/<host>_windows_report_agent.txt.

A Windows host file, also in etc/hosts/windows.conf_example:

HOST=laptop1
PLATFORM=windows
COLLECTOR=wra
PROBES=""
PLUGINS="windows/checkin windows/defender windows/patches windows/apps windows/resources"

PROBES="" turns off the ping probe, laptops move between networks. Set WRA_REPORTS_DIR once in _defaults.conf: it is reports_dir from the agent's server.ini, or the folder the CIFS or SCP delivery writes to. The default is /var/www/html/windows/reports. Set WRA_NAME when the agent reports under a name other than HOST. Linux plugins in _defaults.conf are skipped on Windows hosts.

For many hosts, utils/wra_hosts.sh makes one host file per report. It only lists what it would write until run with --apply, and never changes a host file that exists:

$ ~/drsm/utils/wra_hosts.sh -d /var/www/html/windows/reports
$ ~/drsm/utils/wra_hosts.sh -d /var/www/html/windows/reports --apply
PluginSettingDefaultMeaning
windows/checkinWARN_HOURS48Hours without a report before a warning
CRIT_DAYS15Days without a report before an error
MIN_VERSIONLowest agent version that does not warn
windows/defenderLOOKBACK_DAYS7Days of Defender events that alert
PROTECTION_LOOKBACK_DAYS30Days that protection turned off keeps alerting
CRIT_EVENTSthreats, failed remediation, protection offEvent IDs that are errors
WARN_EVENTSthreat removed, update failuresEvent IDs that are warnings
DEFINITIONS_WARN_DAYS7Age of the newest Security Intelligence update, 0 to skip
windows/patchesWARN_DAYS, CRIT_DAYS45, 90Age of the newest Windows patch
IGNOREdefinition updatesPatch titles that do not count
windows/appsREQUIREDNONEPrograms that must be installed
FORBIDDENNONEPrograms that are errors
WARNNONEPrograms that are warnings
windows/resourcesCPU_WARN, CPU_CRIT85, 95CPU used percent, a 5 second sample
MIN_AVAIL_MB256Available memory at or below this is an error
COMMIT_WARN90Commit charge (memory plus page file) percent of the limit
DISK_WARN, DISK_CRIT90, 99Space used percent on each fixed drive
DISK_SKIPDrives to skip, for example "D: E:"
UPTIME_WARN_DAYS0Days without a restart before a warning, 0 to skip
MAX_AGE_HOURS2Older reports are not checked, windows/checkin reports them

windows/resources uses the metric names of the Linux plugins (cpu_used_pct, mem_available_mb, disk_used_pct{mount="C:"}, nic_rx_bytes{nic="Wi-Fi"} and so on), so Windows hosts get the same gauges and trends. Its sample_etime metric is the time the agent read the counters: the trends page times network rates by the reports, and counts a report that two runs saw only once.

The windows/apps lists are case insensitive regular expressions separated by semicolons, because program names have spaces: windows_apps_REQUIRED="Microsoft Defender;Mozilla Firefox".

A host that has never sent a report, or whose report file is empty, is an ERROR from windows/checkin; the other Windows plugins are UNKNOWN until a report arrives. To run a Windows plugin by hand:

$ DRSM_TARGET=laptop1 DRSM_WRA_REPORT=/var/www/html/windows/reports/laptop1_windows_report_agent.txt \
    bash ~/drsm/plugins/windows/checkin/check.sh

Writing a plugin

$ ~/drsm/utils/new_plugin.sh local/myapp            # runs on the host
$ ~/drsm/utils/new_plugin.sh local/myapp_url probe  # runs from the monitor against the host

This creates the folder, a commented plugin.conf, and a script you can run by hand right away:

$ DRSM_WARN=50 bash ~/drsm/plugins/local/myapp/check.sh
$ DRSM_TARGET=cloud1 bash ~/drsm/plugins/local/myapp_url/probe.sh

Then add local/myapp to PLUGINS (or PROBES) in a host file. Site plugins live in plugins/local, which updates never overwrite.

Manifest

NAME=myapp
CATEGORY=local
DESCRIPTION="Order queue is draining"
PLATFORMS="linux"      # linux, windows, or any
MODE=remote            # remote runs check.sh on the host, probe runs probe.sh on the monitor
TIMEOUT=30             # seconds, enforced by the runner
REQUIRES="curl jq"     # commands that must exist, otherwise the plugin is UNKNOWN
NEEDS_SUDO=no          # informational: no, yes, or optional

# Every other key is a setting with its default
WARN=100
CRIT=500
QUEUE_DIR=/var/spool/myapp

Each setting reaches the script as DRSM_<KEY>. A host overrides it with <category>_<name>_<KEY>, for example local_myapp_WARN=200, and can set <category>_<name>_TIMEOUT.

Script

#!/bin/bash
source "${DRSM_LIB:-$(dirname "$0")/../../../lib}/drsm_plugin.sh"

WARN=$(drsm_setting WARN 100)
CRIT=$(drsm_setting CRIT 500)
QUEUE_DIR=$(drsm_setting QUEUE_DIR /var/spool/myapp)

count=$(find "${QUEUE_DIR}" -type f | wc -l)
if [ "${count}" -ge "${CRIT}" ]; then
    drsm_crit "${HOST} myapp queue has ${count} files"
elif [ "${count}" -ge "${WARN}" ]; then
    drsm_warn "${HOST} myapp queue has ${count} files"
else
    drsm_ok "${HOST} myapp queue checks good at ${count} files"
fi
drsm_metric myapp_queue_files "${count}"

drsm_exit
HelperPrintsEffect
drsm_ok, drsm_infoINFO - ...none
drsm_warnWARNING - ...state at least WARNING
drsm_critERROR - ...state ERROR, alerts are sent
drsm_unknownUNKNOWN - ...state UNKNOWN when nothing is worse
drsm_metric name value [labels]METRIC name{labels}=valuefeeds the gauges and heat map
drsm_detail name valueDETAIL name=valuea host fact shown in the Details panel of the host page, such as an IP address or agent version
drsm_setting NAME defaultvalue of DRSM_NAME or the default
drsm_targetthe host a probe checks, DRSM_TARGET
drsm_gt a bfloating point a > b without bc
drsm_exitexits with the state

States and exit codes

Exit codes follow the Nagios plugin convention:

0 OK 1 WARNING 2 ERROR 3 UNKNOWN

How a run works

For each host the runner builds one job script with a line per plugin, its settings and its timeout. Probe jobs run on the monitor host. Remote jobs go through the host's collector:

Each plugin's output is a section of the host report:

=== storage/disk [WARNING] 0s ===
Disk usage checks for cloud1
WARNING - cloud1:/var is at 92% capacity.
METRIC disk_used_pct{mount="/var"}=92
FileWritten by
$REPORTdir/systems/<host>/<host>_report.txt and archivesame as system_report.sh
$REPORTdir/systems/<host>/status.jsonnew, plugin states for the dashboard
$REPORTdir/system_health_report.txt, _errors.txtsame as system_report.sh
$REPORTdir/system_check_report.txt, _report_errors.txtsame as system_check.sh

Groups other than production (and ops, its other name) add _<group> to the group report names. Alerts use bin/text_email_alert.sh with the same subjects and 4 hour throttle as before.

Files

bin/drsm_run.sh               plugin runner
lib/drsm_plugin.sh            helpers every plugin sources
lib/drsm_conf.sh              KEY=value reader for manifests and host files
lib/drsm_job.sh               runs plugins on the target, with timeouts
collectors/local.sh           runs plugins on the monitor host itself
collectors/ssh-linux.sh       copies and runs plugins on Linux hosts over SSH
collectors/wra.sh             reads Windows Reporting Agent reports for Windows hosts
plugins/<category>/<name>/    plugin.conf plus check.sh or probe.sh
plugins/local/                your own plugins, never overwritten by updates
etc/hosts/_defaults.conf      settings shared by all hosts
etc/hosts/<host>.conf         one file per host
utils/new_plugin.sh           creates a plugin from a template
utils/migrate_systems_dat.sh  converts systems.dat and profiles to host files
utils/wra_hosts.sh            creates host files for Windows agent hosts

Roadmap

Later phases of the plugin design add more checks (SMART, mounts, backup age, TCP ports, TLS expiry, DNS, time sync, failed services), generic database, container, service and process plugins with a custom/command catch all, live Windows checks over OpenSSH and PowerShell alongside the Windows Reporting Agent, and configurable notifiers (email, SMS, Slack, ntfy, webhook) with alert on change.