Closes #112. Source stays `docs/*.md`, rendered by MkDocs-Material and published to GitHub Pages by Actions. Same repository on purpose: documentation drifts, and co-location is the only thing that reliably prevents it — the pull request that changes behaviour changes the description, and review sees both. A separate repo would double the ceremony and guarantee divergence. The markdown remains readable when browsing the repository, so the site renders those files rather than replacing them. **Versioned from the start**, using mike. Images are published to GHCR and this project ships betas most days, so readers are routinely running something other than the newest build; a single "latest" would confidently describe a release they do not have. Versions follow the product rather than the docs, so the site and the running image carry the same number. **Content came first, and it had to.** The docs were eleven days and sixteen releases stale — SSH keys, bulk commands, the data-cap SMS, poller health and the timezone setting appeared in exactly zero files between them. Publishing that would have given documentation missing five of the most consequential features a polished, authoritative home, and a well-presented wrong answer is worse than an obviously rough one. Four pages now cover them: - cellular.md — signal grading, carrier aggregation, the uplink anchor, observed bands, and the data-cap SMS including why it fires early and how to calibrate the margin - ssh-keys.md — leading with what installing a key costs, because RouterOS disables password SSH for that user and the database becomes load-bearing - commands.md — why waves exist, and why reading output matters when RouterOS reports failure in text rather than an exit code - scaling.md — headroom, why it is insufficient on its own, and every tunable Pull requests build the site with `--strict`, which turns warnings into errors. That is the point of running it there at all, and it earned itself immediately: the first build failed on two links to the project README, which sits outside the docs tree. They are absolute now, so they resolve both in the rendered site and when reading the markdown on GitHub. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
69 lines
2.6 KiB
Markdown
69 lines
2.6 KiB
Markdown
# Bulk commands
|
|
|
|
[← Documentation index](README.md)
|
|
|
|
Run one RouterOS console command across many devices, in waves, stopping at the first
|
|
failure.
|
|
|
|
Commands run over **SSH**, because console syntax — `:put`, `:foreach`, `/interface print`
|
|
— is not reachable through the binary API, which has its own command tree.
|
|
|
|
## Why waves exist
|
|
|
|
A shell loop already runs a command on many hosts, costs nothing, and prints errors as
|
|
they happen. What it cannot do is **stop**.
|
|
|
|
Devices run together within a wave; waves run strictly in sequence. With halt-on-failure
|
|
enabled, a mistake reaches one wave rather than the whole fleet. That is the entire reason
|
|
to do this here rather than in a terminal — without it, this would be a worse shell loop.
|
|
|
|
Start with a wave of one. Widen it once the command has proved itself.
|
|
|
|
## Detecting failure
|
|
|
|
RouterOS reports most errors in the **output text** rather than through an exit code, so a
|
|
rejected command and a successful one are indistinguishable unless the output is read.
|
|
|
|
Output is scanned for unambiguous markers — `syntax error`, `bad command name`, `no such
|
|
item`, `failure:` and similar. The matching is deliberately conservative: mistaking
|
|
ordinary output for failure would halt a run that was working, which is worse than the
|
|
error it guards against.
|
|
|
|
## Change Guard
|
|
|
|
Each device is wrapped by [Change Guard](change-guard.md) by default, so one that stops
|
|
answering after the command restores itself.
|
|
|
|
It is **one click to turn off**. You may know exactly why you are running something that
|
|
will drop a device, and a tool that refuses to cut is not a sharp tool.
|
|
|
|
The one combination that asks for explicit acknowledgement is a command that can sever
|
|
management **with the guard disabled** — the only case where nothing catches a mistake.
|
|
|
|
## Preview
|
|
|
|
Before running, the preview shows:
|
|
|
|
- which devices are selected and which wave each falls into
|
|
- whether the command matches patterns that can cut management access, and why
|
|
- devices with **no SSH credential**, which would otherwise produce a wave of identical
|
|
authentication failures
|
|
|
|
It warns; it never blocks.
|
|
|
|
## Output
|
|
|
|
Captured per device and kept with the run. Some commands exist purely for their output —
|
|
`:put [:resolve google.com]` across a fleet is a legitimate use — and "it failed" without
|
|
the device's own words is not actionable.
|
|
|
|
## Stopping a run
|
|
|
|
Cancelling prevents the **next wave**. Devices already executing finish, because that is
|
|
the only point at which stopping is safe.
|
|
|
|
## Requirements
|
|
|
|
Every targeted device needs an SSH credential: either a password, or a verified
|
|
[SSH key](ssh-keys.md). On a fleet of any size, keys are the practical answer.
|