CLI & TUI (raptorctl)
raptorctl is a separate binary (crate raptor-cli) that drives a running
raptor server over the same Management API the web console uses. It is a pure
HTTP client — install it anywhere that can reach raptor serve, no server-side
changes required.
Install
Each GitHub Release attaches
raptorctl-<tag>-<target>.tar.gz (plus a .sha256) for aarch64-apple-darwin,
x86_64-unknown-linux-gnu and aarch64-unknown-linux-gnu. With
mise, pin it like any other tool:
[tools]
"github:rosterloh/raptor" = { version = "1.3.2", bin = "raptorctl" }
The server’s .deb also ships /usr/bin/raptorctl. Elsewhere, build it from
source with cargo build --release -p raptor-cli.
Login
$ raptorctl login --url http://localhost:8088 --user admin
password for admin:
logged in as admin
This verifies the credentials with a request against the server, then saves
them to ~/.config/raptor/cli.toml (mode 0600). Every later command reuses
that file, so --url/--user are only needed again to switch servers.
raptorctl logout deletes the saved file.
Scripting / CI
Skip the config file entirely with environment variables — useful in CI where
there’s no interactive prompt for login to read a password from:
$ RAPTOR_URL=http://localhost:8088 RAPTOR_USER=admin RAPTOR_PASS=secret \
raptorctl target list
Precedence is flags > environment > the saved config file.
Commands
Every command accepts --json to print the server’s raw response instead of a
table — pipe it into jq:
$ raptorctl target list --json | jq '.content[].controllerId'
| Command | Does |
|---|---|
target list/get/create/set/delete | target CRUD |
target attributes <cid> | reported device attributes |
target tag add|rm <cid> <tag> | tag/untag a target |
target type list/set/clear | target types, and a target’s constraint |
tag list/create/delete [--ds] | tag CRUD (target tags, or --ds for set tags) |
target assign <cid> --ds <id> [--force ...] | assign a distribution set |
target actions <cid> | a target’s action history |
module list/create/delete | software module CRUD (delete is refused while a set references it) |
artifact upload/list/delete <moduleId> | artifact management |
ds list/get/create | distribution set CRUD |
ds invalidate <id> | withdraw a set so it can no longer be deployed |
ds tag add|rm <id> <tag> | tag/untag a distribution set |
publish <file> --version <v> | module + artifact + distribution set in one call |
action list/status/cancel/force | deployment action control |
rollout list/get | list rollouts, show one with its targets counted by outcome |
rollout create <name> --ds <id> --filter <fiql> --groups <n> --success <pct> | create a rollout (flags for every RolloutCreate field) |
rollout start/pause/resume/stop <id> | drive a rollout’s lifecycle; stop confirms unless -y |
rollout approve/deny <id> | decide rollouts awaiting approval |
status | fleet-wide statistics |
Run raptorctl <command> --help for full flag lists.
publish and the two type vocabularies
publish creates a software module, uploads the file to it, and wraps it in a
distribution set. Those are typed from two different hawkBit vocabularies:
| Flag | Vocabulary | Seeded values |
|---|---|---|
--module-type (alias --type) | software-module types | os, firmware, runtime, application |
--ds-type | distribution-set types | os, os_app, app |
--ds-type is optional: raptorctl reads /rest/v1/softwaremoduletypes and
/rest/v1/distributionsettypes and derives it — an exact key match wins (os
→ os), otherwise the one set type that requires exactly that module type
(application → app). When neither applies (e.g. --module-type firmware,
which no seeded set type requires) it errors and asks for --ds-type rather
than guessing, because a wrong guess builds an incomplete distribution set
that only fails later, at assign time.
Both types, and the file itself, are checked before anything is written. That
ordering matters: the sequence is create-module → upload → create-set, so a
failure at a later step would otherwise leave an orphaned module behind. If the
upload or the set creation still fails (the network, the server), publish
deletes the module it created; if even that fails, the error names the module
to remove with raptorctl module delete <id>.
Withdrawing a release
ds invalidate is the inverse of publish: the set can no longer be assigned
or rolled out, and any target filter auto-assigning it is detached. There is no
undo.
$ raptorctl ds invalidate 7
invalidate distribution set 7 (fw:1.4.1)? this cannot be undone. [y/N] y
invalidated distribution set 7 (fw:1.4.1)
The bare command is the safe one, because it is the one that gets run in a hurry: in-flight actions and rollouts are left alone, so a device that has already installed the set still reports its result. The destructive parts are opt-in:
| Flag | Effect |
|---|---|
--cancel-rollouts | also stop rollouts deploying this set |
--cancel-actions soft | ask devices to stop; the action ends when the device confirms |
--cancel-actions force | cancel server-side at once, without waiting for the device |
--yes (-y) | skip the confirmation prompt |
The prompt only appears when stdin is a TTY, so scripts and CI need no --yes.
ds get reports the result as valid false.
Tags
tag manages the tag itself; target tag/ds tag only assign an existing one
to something. --ds switches every tag subcommand from target tags to
distribution-set tags.
$ raptorctl tag create zephyr --description 'Zephyr firmware fleet' --colour '#4caf50'
created target tag 3 (zephyr)
$ raptorctl tag list
ID NAME DESCRIPTION ASSIGNED
3 zephyr Zephyr firmware fleet 0
$ raptorctl target tag add dev-042 zephyr
tagged dev-042 with zephyr
Assigning a tag that doesn’t exist names the ones that do, so a typo and a never-created tag are distinguishable:
$ raptorctl target tag add dev-042 zephry
error: no target tag named 'zephry' — existing: zephyr, prod. Create it with 'raptorctl tag create zephry'.
Target types
A target type constrains which distribution-set types the target will accept, so it is a correctness setting rather than an organisational one — an incompatible assignment is rejected at assign time.
$ raptorctl target type list
ID NAME DESCRIPTION ACCEPTS_DS_TYPES
1 gateway - os
$ raptorctl target type set dev-042 gateway
dev-042 is now target type gateway (1)
$ raptorctl target get dev-042 | grep targetType
targetType gateway
$ raptorctl target assign dev-042 --ds 7
error: distribution set type 'app' is not compatible with target type 'gateway', which accepts: os (HTTP 400)
raptorctl target type clear <cid> removes the constraint. Creating target
types themselves is not in the CLI yet — use the console or
POST /rest/v1/targettypes.
Rollouts
rollout create takes the POST /rest/v1/rollouts body as flags, with the
nested conditions flattened: --success/--error are percentages, and
--dynamic-suffix/--dynamic-count build the dynamicGroupTemplate. A
template flag without --dynamic is rejected before anything is sent.
A dynamic rollout never finishes on its own (see the Rollouts guide), so its full lifecycle is create, start, and eventually stop:
$ raptorctl rollout create fleet-1.1 --ds 16 --filter 'tag==rpi5' \
--groups 1 --success 50 --dynamic --dynamic-suffix -dynamic --dynamic-count 20
created rollout 2 (fleet-1.1) — 4 targets, now ready
$ raptorctl rollout start 2
rollout 2 is now running
$ raptorctl rollout get 2 # watch it absorb newly-matching targets
...
targets 4
notstarted 0 scheduled 2 running 2 finished 0 error 0 cancelled 0
$ raptorctl rollout stop 2
stop rollout 2 (fleet-1.1) and cancel its in-flight updates? this cannot be undone. [y/N] y
rollout 2 is now stopping
stop soft-cancels the rollout’s in-flight actions and is terminal, so it asks
first on a TTY; pass -y to skip the prompt. It reports stopping until those
devices acknowledge the cancel. pause and resume hold and release group
progression without cancelling anything.
Rollout approval
When the server runs with rollout_approval_enabled = true, a new rollout
waits in waiting_for_approval until an operator decides on it:
$ raptorctl rollout list
ID NAME STATUS FINISHED DECIDED BY
7 fw-1.4.2 waiting_for_approval 0/240
$ raptorctl rollout approve 7 --remark "checked with ops"
rollout 7 is now ready
deny is the other half, and is terminal — a denied rollout can only be
deleted, so create a fresh one to try again. Both take an optional --remark
recorded against the decision. See the
Rollouts guide.
End-to-end example
$ raptorctl module create --name fw --version 1.4.1 --type os
$ raptorctl artifact upload 1 ./firmware.bin
$ raptorctl ds create --name fw --version 1.4.1 --type os --module 1
$ raptorctl target create dev-042
$ raptorctl target assign dev-042 --ds 1 --force forced
$ raptorctl target get dev-042
TUI
raptorctl tui opens an interactive dashboard: the fleet on the left, the
selected target’s status, assigned/installed set, and action history on the
right, and running rollouts underneath the target list.
$ raptorctl tui [--refresh <seconds>] # default 5, 0 disables auto-refresh
| Key | Does |
|---|---|
↑↓ / j/k, g/G | move selection |
/ | filter targets (sent server-side as a FIQL q=) |
a | assign a distribution set to the selected target |
t | tag the selected target |
c / f | cancel / force the target’s active action (y to confirm, n/Esc to back out) |
r | refresh now |
? | help |
q | quit |
It respects NO_COLOR, works over SSH and inside tmux, and requires at least
an 80x24 terminal.
An active filter shows in the targets panel title; a failed or timed-out
refresh (15 s) leaves ⚠ stale in the header until that fetch succeeds again.