Files
steward/docs/cli.md
T
abrown38andClaude Opus 5.5 3c0808591f Steward 0.1.0 (in development): a DHCPv4 server with a web UI, API and CLI
Subnets served per interface, pools, reservations, options at three
levels, leases in SQLite saved before the ACK, ping and decline conflict
checks, validated changes with history and undo, users and tokens, an
audit log, a Kea importer, a sandboxed systemd unit and Debian packages.
Tested with real udhcpc and dhcpcd clients in Docker (scripts/e2e.sh).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:14:07 +01:00

161 lines
6.6 KiB
Markdown

# The steward CLI
`steward` talks to stewardd's REST API. `steward help COMMAND` describes
each command and its flags.
## Connecting
* **On the server**, with nothing configured, the CLI uses stewardd's
local socket, `/run/steward/steward.sock`. Root and the `steward` user
are administrators there without a token: `sudo steward status`.
* **From elsewhere**, give the server's URL and an API token:
```sh
steward config set server https://dhcp.example.com:8067
steward config set token # asks for it
```
The settings are in `~/.config/steward/config.yaml` (on macOS
`~/Library/Application Support/steward/config.yaml`, on Windows
`%AppData%\steward\config.yaml`).
| Flag | Environment | |
|---|---|---|
| `-s, --server URL` | `STEWARD_SERVER` | the server; `local` for the local socket |
| `--token TOKEN` or `@FILE` | `STEWARD_TOKEN` | the API token |
| `--config FILE` | `STEWARD_CLI_CONFIG` | the CLI's configuration file |
| | `STEWARD_SOCKET` | the local socket's path |
| `--insecure`, `--ca-cert FILE` | | TLS: skip the check, or trust another CA |
| `-n, --dry-run` | | check and show a change without making it |
| `-o, --output FORMAT` | | `table` (default), `json`, `yaml` or `id` |
| `-q, --quiet` | | print only errors (and the IDs of new objects) |
Exit codes: 0 ok, 1 error, 3 not authenticated or not allowed, 4 not
found, 5 conflict, 6 invalid or refused by validation, 7 server error.
## Changes
Every change is checked as a whole first. A refused change says why and
gives the problem's code ([validation.md](validation.md)). A saved one
says its history entry, and any new warnings:
```
$ steward subnet add 10.0.20.0/24 --interface eth0.20 --name iot --pool 10.0.20.100-10.0.20.200
created subnet iot (10.0.20.0/24)
saved (history 2; undo with 'steward history undo 2')
warning: subnet iot (10.0.20.0/24): this server has no interface eth0.20 (it has eth0, lo); the subnet is served once it appears [interface_unknown]
```
`-n` shows what would change without changing it.
## Commands
### status
`steward status`: the version, each interface and whether it is served
(and why not), each subnet's pool use, leases by state, DHCP messages
since the start, and problems.
### subnet
| Command | |
|---|---|
| `subnet list` | subnets, with interface, pools, use, reservations, lease time |
| `subnet show SUBNET` | one subnet; SUBNET is its ID, name or prefix |
| `subnet add PREFIX --interface IFACE [--name N] [--pool A-B]... [--lease-time 12h] [--option NAME=VALUE]... [--comment C]` | add one |
| `subnet update SUBNET [--name] [--interface] [--prefix] [--pool]... [--add-pool] [--remove-pool] [--lease-time 1h\|default] [--option NAME=VALUE]... [--unset-option NAME]... [--comment]` | change what is given |
| `subnet enable\|disable SUBNET` | answer its clients, or not |
| `subnet delete SUBNET [-y]` | delete it and its reservations |
`--pool` replaces the pools; `--add-pool` and `--remove-pool` change one.
`--option` sets an option and keeps the others; `--unset-option` removes
one. An option Steward doesn't know: `--option 224:string=hello`.
### reservation
| Command | |
|---|---|
| `reservation list [--subnet SUBNET]` | reservations, and whether each client is online |
| `reservation show RES` | RES is its ID, address or MAC address |
| `reservation add IP MAC [--hostname H] [--client-id HEX] [--option NAME=VALUE]... [--comment C]` | `-` for MAC with `--client-id` |
| `reservation update RES [--ip] [--mac] [--client-id] [--hostname] [--option]... [--unset-option]... [--comment]` | |
| `reservation delete RES` | |
### lease
| Command | |
|---|---|
| `lease list [--subnet S] [--state STATE] [--interface I] [--search TEXT] [-a]` | active and held-back leases; `-a` all |
| `lease show IP` | one lease |
| `lease reserve IP [--hostname H]` | make the address its client's reservation |
| `lease delete IP [-y]` | free the address at once |
### activity
`steward activity [--mac MAC] [--interface I] [--limit N] [-f]`: the latest
DHCP messages, received and sent, oldest first. `-f` keeps watching, which
is useful while a device tries to get an address:
```
11:02:13.120 eth0 DHCPDISCOVER 3c:22:fb:11:22:33 - adams-macbook
11:02:13.622 eth0 DHCPOFFER 3c:22:fb:11:22:33 10.0.10.150 adams-macbook
11:02:13.630 eth0 DHCPREQUEST 3c:22:fb:11:22:33 10.0.10.150 adams-macbook
11:02:13.631 eth0 DHCPACK 3c:22:fb:11:22:33 10.0.10.150 adams-macbook
```
`NO ADDRESS` means the pools on that interface are full, and `CONFLICT`
an address that answered the ping check. A `DHCPNAK` says why it was
sent.
### settings and options
| Command | |
|---|---|
| `settings show` | |
| `settings set [--lease-time 1d] [--ping-check on\|off] [--ping-timeout 500ms] [--decline-hold 24h] [--authoritative on\|off] [--option NAME=VALUE]... [--unset-option NAME]...` | |
| `option list` | the options Steward knows ([options.md](options.md)) |
| `interface list` | the server's interfaces, their addresses and subnets |
### history
| Command | |
|---|---|
| `history list [--limit N]` | changes, newest first |
| `history show ID` | each object's fields before and after |
| `history undo ID` | apply the change backwards (refused if something it touched has changed since) |
### import
`steward import kea CONFIG [--leases FILE]... [--interface PREFIX=IFACE]... [--replace]`:
see [kea.md](kea.md).
### users, tokens, audit
| Command | |
|---|---|
| `whoami` | who you are to the server, and what you may do |
| `user list\|add\|update\|delete` | users (administrators); `user add NAME --role operator` |
| `token list [--all]`, `token create NAME [--role R] [--grant G]... [--expires 90d] [--user U] [--save]`, `token revoke ID` | API tokens |
| `password` | change your password |
| `audit [--user U] [--action PREFIX] [--search TEXT]` | the audit log |
| `config show`, `config set server\|token\|insecure\|ca_cert [VALUE]` | this CLI's settings |
[permissions.md](permissions.md) explains roles and grants.
## stewardd
The daemon's own commands work on the database directly, as root or the
`steward` user (`sudo -u steward stewardd ...`):
| Command | |
|---|---|
| `stewardd serve` | run (the systemd unit does) |
| `stewardd init [-u NAME] [--token]` | create the database and the first administrator |
| `stewardd user add NAME [--admin]`, `user password NAME`, `user token NAME TOKEN-NAME` | when the API can't be used |
| `stewardd check` | check the configuration against this machine's interfaces |
| `stewardd backup [FILE]`, `stewardd restore FILE` | [operations.md](operations.md) |
| `stewardd config [--example]` | the settings in use, or a commented example |
| `stewardd version` | |
All take `-c FILE` for another configuration file.