Nornir-rs & KoRE CLI
A network automation stack written in Rust
Overview
KoRE re-imagines the classic network automation toolchain (Nornir, Netmiko, Ansible, Jinja2, TextFSM) with modern Rust ergonomics. It delivers:
- Declarative inventories with layered defaults, host/group vars, and secrets providers.
- Async transports (SSH, NETCONF, HTTP, local runners) with connection pooling and profile-aware prompt handling.
- Jinja2/MiniJinja templates for config generation plus first-class REST helpers and TextFSM parsing.
- Ansible-vault compatible secrets and a CLI (
kore) that mirrors the library API so you can embed workflows or drive them interactively.
Documentation Map
docs/CLI_USAGE.md– all CLI commands, flags, and examples.docs/INVENTORY_SCHEMA.md– inventory fields, connection options, and schema reference.docs/INTERPOLATION.md–${…}syntax for config, inventory, and pipeline files.docs/SECRETS_VAULT.md– vault commands, provider configuration, and thekore test secretshelper.docs/DATA_REFERENCE.md– collection/task parameter reference.docs/DEVELOPER_GUIDE.md– transports, device profiles, and collection module internals.
Quick Start
- Clone & build
- Bootstrap a workspace
# creates inventory/{hosts,groups,defaults}.yaml, kore.yaml, logs/ - List hosts
- Render & push configs
Once comfortable with the CLI, embed the same workflows via the nornir-rs
crate and builder APIs.
Installation
KoRE is a Cargo project—any modern Rust toolchain works.
- Install the CLI:
# or locally - Manual build:
- Ad-hoc runs (no install):
Configuration (kore.yaml)
The CLI searches for kore.yaml in this order:
./kore.yaml$HOME/.kore.yaml$KORE_CONFIG/etc/kore/kore.yaml
It controls transports, vault defaults, parsers, rendering paths, etc. See
docs/CLI_USAGE.md for every field plus examples.
Inventory & Variables
The init command generates the canonical Nornir-style layout:
inventory/hosts.yaml– device entries (hostname, port, platform, metadata).inventory/groups.yaml– shared parameters for groups.inventory/defaults.yaml– global defaults merged last.
KoRE also supports remote inventory plugins wired through kore.yaml:
simple– load YAML/JSON/TOML files from disk (the defaultinitlayout).http– fetch a serialized inventory document from any REST endpoint.nautobot– call Nautobot’s REST API, paginate automatically, and build hosts for both devices and virtual machines (including custom fields, tags, and role/site/cluster groups).netbox– query NetBox’s REST API (devices and virtual machines), flatten custom fields/tags, and optionally merge SimpleInventory-style groups/defaults.
Example Nautobot configuration:
inventory:
plugin: nautobot
options:
url: https://nautobot.local/api/
token: ${NAUTOBOT_TOKEN}
include_virtual_machines: true
flatten_custom_fields: true
device_query:
- name: status
value: active
virtual_machine_query:
- name: tenant
value: lab
Layer Ansible-style vars by pointing kore.yaml (or CLI flags) at
inventory/group_vars and inventory/host_vars. Merge strategies (override
or deep) mirror Nornir. Details live in
docs/INVENTORY_SCHEMA.md.
Example NetBox configuration:
inventory:
plugin: netbox
options:
nb_url: https://netbox.local
nb_token: ${NETBOX_TOKEN}
include_virtual_machines: true
flatten_custom_fields: true
device_query:
- name: role
value: edge
group_file: inventory/groups.yaml
defaults_file: inventory/defaults.yaml
NetBox API tokens can be provided in either legacy (Token abc…) or application
(Bearer nbt_…) form; KoRE detects the prefix automatically, so you can paste
the exact token string from NetBox.
Every static file—inventory YAML/TOML/JSON, kore.yaml, pipelines—supports
${…} interpolation. Reference environment variables, vault secrets, or other
inventory data. Syntax and namespaces are documented in
docs/INTERPOLATION.md.
Logging & Diagnostics
All commands expose consistent logging flags:
-v / -vv / -vvvraise verbosity to info/debug/trace.-q/--quietrestricts output to warnings (ideal for scripting).--log-level <level>explicitly sets the tracer level.--log-file <path>mirrors stderr logs to a file.
For TextFSM troubleshooting, use the bundled debugger (see below) to step through template states without rerunning live commands.
Running Tasks
SSH
kore run ssh … reuses the inventory’s transport settings (or CLI overrides)
with session pooling, fast CLI profiles, and optional TextFSM parsing.
Enable TextFSM globally via parsers.use_textfsm in kore.yaml or per command
with --use-textfsm. Override template detection using --textfsm-command
when the executed CLI differs from the canonical template name. Full flag
reference: docs/CLI_USAGE.md#ssh.
NETCONF
Run NETCONF RPCs, <get-config>, <edit-config>, and raw payloads over SSH or
any registered transport:
Additional subcommands (--get-config, --edit-config, --rpc) support
locking, commit confirm, pretty-printing, and per-host output paths. See
docs/CLI_USAGE.md#netconf.
HTTP / RESTCONF
Use inventory-defined HTTP transports (RESTCONF, Arista eAPI, custom REST
servers) and override headers, auth type, request bodies, and output paths on
the CLI. ${host.*} and ${data.*} placeholders expand inside URLs, headers,
and JSON payloads, so multi-host REST tasks stay declarative.
Template Rendering
MiniJinja renders Jinja2-compatible templates with the layered inventory data.
Without explicit output flags each host renders to
configs/<host>/<template>.config (configurable via kore.yaml, --output,
--output-root, --output-pattern).
--debug-vars prints the fully merged context to stdout so you can inspect the
data the template sees. Full render options are documented in
docs/CLI_USAGE.md.
Pipelines
Pipelines package multiple tasks (render, push, verify, archive) into a single YAML/TOML/JSON file with the same semantics as the CLI flags. Each spec describes host selectors, vars, and ordered tasks:
- name: ospf-template
hosts:
names:
filters:
vars:
template_dir: templates
tasks:
- name: Render
j2:
templates:
- ${template_dir}/interfaces.j2
- ${template_dir}/ospf.j2
output-dir: configs
- name: Push configuration
ssh:
config_files:
- configs/${host.name}/interfaces.config
- configs/${host.name}/ospf.config
save_config: true
- name: Archive
local:
commands:
- tar -czf backups/${host.name}.tar.gz configs/${host.name}
Invoke with cargo run -- run pipeline pipelines/ospf.yaml. Pipelines share
the same interpolation engine, vault flags, and logging behavior as the CLI.
More examples live in docs/CLI_USAGE.md.
Secrets & Vault
kore vault mirrors Ansible-vault, supporting create/view/edit, encrypt/decrypt,
--vault-id, and --ask-vault-password. Files encrypted by KoRE can be read
by ansible-vault and vice versa. Configure default IDs/password sources inside
kore.yaml:
vault:
ids:
- default@env:KORE_VAULT_PASS
- prod@file:~/.config/kore/prod.vault
Inventories, vars, secrets providers, and pipeline files all understand vault
payloads. Use kore test secrets --provider <name> --ref key[#field] to verify
provider lookups before wiring them into inventories. Details:
docs/SECRETS_VAULT.md.
TextFSM Debugger
Need to troubleshoot a template? The bundled debugger replays raw command output through TextFSM, logging every state/regex so you can see why a rule matched (or failed):
For normal runs, --json (or --json-only) emits newline-delimited JSON for
each command with template metadata and parsed records.
Shell Completions
Generate completion scripts for your preferred shell:
Feedback & Contributions
Issues and merge requests are welcome—especially around new transports, collections, or docs. Spin up a test lab, kick the tires, and let me know what would make KoRE even better for your workflow. Happy automating!