> Section: [3. Checks](https://jaque.sh/docs/checks/native-checks.md)
> Next: config/cue-in-practice
> Index: https://jaque.sh/llms.txt


The Nagios idiom `check_command name!arg1!arg2` names one command
template once and instantiates it with different positional arguments per
host or service. jaque keeps the idiom: a top-level `commands` map holds
the templates, a `command` check names one and supplies `args`, and
`$ARGn$`, `$USERn$` and `$_HOSTxxx$`/`$_SERVICExxx$` macros expand
exactly as an operator coming from Nagios expects. This is how fifty
services that differ in one flag share one line. The only thing dropped
is the `!` splitting, which belongs to the importer, not the schema.

## 1. Define a command once

```cue
resources: USER1: "/usr/lib/nagios/plugins"

commands: check_creds: line: "$USER1$/check_creds.sh --user $ARG1$ --password $_HOSTPASSWORD$"
```

`resources` plays the role of Nagios's `resource.cfg`: `$USERn$` lookups
only, so the schema requires every key to match `USER<digits>`; anything
else is a config error rather than a silently unreachable value. It keeps
paths and credential-adjacent strings out of the main object files, as it
always did. `commands` maps a name to a template `line`. `$ARGn$` are
positional arguments supplied at the call site; `$_HOSTxxx$` and
`$_SERVICExxx$` expand a host's or a service's `vars`, whose keys the
schema forces to uppercase so the CUE reads the way the macro reads.

## 2. Instantiate it per object

```cue
hosts: gw: {
	address: "192.168.1.1"
	vars: PASSWORD: "s3cr3t"
	check: {type: "icmp", host: "192.168.1.1"}
	services: creds: check: {
		type:    "command"
		command: "check_creds"
		args:    ["jaque"]
	}
}
```

`command` is a key into the top-level `commands` map; `args` fills
`$ARG1$`, `$ARG2$` and so on, the same argument list Nagios passed after
the `!`s. A `command` naming a key that is not in `commands` is a config
error.

## 3. Two expansion modes

A template is `shell: false` by default: after macro expansion the
resolved line is tokenized and executed directly, like a `legacy` check,
with no shell in between. `shell: true` hands the whole resolved line to
`/bin/sh -c` instead. That is the mode for a command that pipes or
redirects, at the usual cost: quoting is the caller's problem, and so is
everything a shell does with a `$` or a `;` it was not expecting.

```cue
commands: check_shell: {
	line:  "echo $_SERVICEMESSAGE$ $ARG1$"
	shell: true
}
```

Once resolved, a command check runs exactly like a [legacy exec
plugin](../checks/legacy-exec-plugins.md): the same exit-code protocol,
the same perfdata grammar, the same process-group kill on `timeout`.

## 4. Security considerations

With `shell: false`, an `args` value or a `vars` value is one argument
vector element and cannot become a second command. With `shell: true`,
every macro value is interpolated into a line `/bin/sh` will parse: a
`vars` entry or an `args` element containing shell metacharacters is a
command injection, and the template author is the one who accepted that
by choosing the mode. Use `shell: true` only for templates whose every
macro value the operator controls. `resources` and `vars` are plain text
in the config file and are expanded into process argument vectors, where
any user on the host can read them from the process table.
