CLI-first Python package for network device configuration backup, versioned snapshots, and diffs.
Project description
NetConfigPulse
NetConfigPulse is an open source Python package and CLI for network device configuration backup. It connects to routers and switches over SSH, runs vendor-specific collection commands, saves versioned backup files, and generates diffs against previous runs. Maintained by 21Vianet.
Quick Start
Install the released package from PyPI:
pip install NetConfigPulse
netconfigpulse --help
Use the CLI with your own YAML files, or clone the repository and start from the sample configuration:
netconfigpulse validate \
--inventory config/devices.example.yaml \
--commands config/commands.default.yaml \
--credentials config/credentials.example.yaml \
--config config/runtime.example.yaml
This validates the example configuration without connecting to any device. Use
backup only after replacing the example devices and credentials with real
values.
Installation
From PyPI:
pip install NetConfigPulse
netconfigpulse --help
The PyPI package includes both the netconfigpulse console command and the
Python library API. To run the example configuration files from this repository,
clone the repository or copy the config/ directory, then run:
netconfigpulse validate \
--inventory config/devices.example.yaml \
--commands config/commands.default.yaml \
--credentials config/credentials.example.yaml \
--config config/runtime.example.yaml
CLI Usage
Three subcommands: validate, backup, import-csv.
After installation, both python -m netconfigpulse ... and the console command
netconfigpulse ... are supported.
validate
Loads and validates all config files. Reports errors without connecting to any devices.
python -m netconfigpulse validate \
--inventory config/devices.example.yaml \
--commands config/commands.default.yaml \
--credentials config/credentials.example.yaml \
--config config/runtime.example.yaml
backup
Runs the backup workflow: connect to devices, execute commands, save output, generate diffs.
python -m netconfigpulse backup \
--inventory config/devices.example.yaml \
--commands config/commands.default.yaml \
--credentials config/credentials.example.yaml \
--config config/runtime.example.yaml
All flags:
| Flag | Required | Default | Description |
|---|---|---|---|
--inventory |
yes | — | Path to device inventory YAML |
--commands |
yes | — | Path to vendor command catalog YAML |
--credentials |
no | — | Path to credentials YAML (can also use env vars, see below) |
--config |
no | — | Path to runtime config YAML |
--device |
no | — | Filter: backup a single device by name |
--tag |
no | — | Filter: backup only devices with this tag |
--group |
no | — | Filter: backup only devices in this group |
--output |
no | text |
Output format: text or json |
--concurrency |
no | 10 |
Max parallel SSH sessions |
--backup-root |
no | backups |
Root directory for backup files |
When --config is provided, values in the runtime config file take precedence
over the --backup-root and --concurrency command-line defaults.
import-csv
Imports a vendor command catalog from CSV and writes it as YAML.
python -m netconfigpulse import-csv \
--input device_cli_command.csv \
--output config/commands.default.yaml
Exit codes
0— all devices succeeded1— the entire run failed (no devices succeeded)2— partial failure (some succeeded, some failed)
End-to-End Example
Input files
config/devices.example.yaml
devices:
- name: edge-r1
host: 192.0.2.10
vendor: cisco_ios
tags:
- production
- edge
group: core
config/commands.default.yaml
vendors:
cisco_ios:
backup:
- terminal length 0
- show running
config/credentials.example.yaml
defaults:
username: backup-user
password: change-me
config/runtime.example.yaml
backup_root: backups
concurrency: 10
min_backup_size_bytes: 2000
backup_retry_attempts: 3
backup_retry_delay_seconds: 10
Run
python -m netconfigpulse backup \
--inventory config/devices.example.yaml \
--commands config/commands.default.yaml \
--credentials config/credentials.example.yaml \
--config config/runtime.example.yaml
Text output
Backed up 1 device: 1 succeeded, 0 failed, 0 warned, 1 changed.
JSON output
Pass --output json to get machine-readable output:
{
"total_devices": 1,
"success_count": 1,
"failed_count": 0,
"warning_count": 0,
"changed_devices": 1,
"unchanged_devices": 0,
"results": [
{
"device_name": "edge-r1",
"status": "success",
"file_path": "backups/2026-04-21/edge-r1/edge-r1_020202.cfg",
"diff_file_path": "backups/2026-04-21/diff/edge-r1/edge-r1_020202_diff.cfg",
"has_changes": true,
"backup_size": 12345,
"warnings": [],
"error": null
}
]
}
Python Library API
NetConfigPulse can also be used directly as a Python library.
Minimal example
from pathlib import Path
from netconfigpulse import load_commands, load_credentials, load_inventory, run_backup
from netconfigpulse.models.config import BackupOptions
devices = load_inventory("config/devices.example.yaml")
commands = load_commands("config/commands.default.yaml")
credentials = load_credentials("config/credentials.example.yaml")
result = run_backup(
devices=devices,
command_catalog=commands,
credentials=credentials,
options=BackupOptions(
backup_root=Path("backups"),
concurrency=10,
),
)
# result is a dataclass, not JSON — access fields directly
print(result.total_devices)
print(result.success_count)
print(result.failed_count)
# to convert to dict / JSON:
from dataclasses import asdict
import json
print(json.dumps(asdict(result), indent=2))
Available functions
| Function | Purpose |
|---|---|
load_inventory(path) |
Read device list from YAML |
load_commands(path) |
Read vendor command catalog from YAML |
load_credentials(path) |
Read credentials from YAML (also picks up env vars) |
run_backup(...) |
Run the full backup workflow (connect, collect, save, diff) |
generate_diff(current, previous) |
Produce a unified diff between two backup texts |
filter_dynamic_content(text) |
Replace timestamps and uptime with placeholders to avoid false diffs |
Result shape
run_backup(...) returns a BackupRunResult with aggregated counters and per-device entries.
Top-level fields:
total_devices: intsuccess_count: intfailed_count: intwarning_count: intchanged_devices: intunchanged_devices: intresults: list[DeviceBackupResult]
Each DeviceBackupResult includes:
device_name: strstatus: strfile_path: str | Nonediff_file_path: str | Nonehas_changes: boolbackup_size: int | Nonewarnings: list[str]error: str | None
Return example
BackupRunResult(
total_devices=1,
success_count=1,
failed_count=0,
warning_count=0,
changed_devices=1,
unchanged_devices=0,
results=[
DeviceBackupResult(
device_name="edge-r1",
status="success",
file_path="backups/2026-04-21/edge-r1/edge-r1_020202.cfg",
diff_file_path="backups/2026-04-21/diff/edge-r1/edge-r1_020202_diff.cfg",
has_changes=True,
backup_size=12345,
warnings=[],
error=None,
)
],
)
Configuration Files
config/devices.example.yaml— device inventoryconfig/commands.default.yaml— full vendor command catalogconfig/commands.minimal.yaml— smaller starter sampleconfig/credentials.example.yaml— credentials (can also be provided via env vars)config/runtime.example.yaml— runtime options (backup root, concurrency, backup-size warning threshold, retry policy)
Credentials can be provided via YAML file or environment variables. Env vars override YAML defaults:
NETCONFIGPULSE_DEFAULT_USERNAMENETCONFIGPULSE_DEFAULT_PASSWORDNETCONFIGPULSE_DEFAULT_SECRET
The --credentials flag is optional. If omitted, credentials come from env vars only.
min_backup_size_bytes warns when a text backup is smaller than the configured
threshold, which helps catch truncated or prompt-only backup files. Set it to
0 to disable this warning. Binary backup output is written as bytes and does
not use the text-size warning.
backup_retry_attempts and backup_retry_delay_seconds retry transient SSH
failures, empty backup output, and text backups that are below the minimum-size
threshold before the run records the final result.
Project Layout
netconfigpulse/
cli/ # argparse entry point
core/ # backup engine orchestrator
loaders/ # YAML/CSV parsers
models/ # dataclasses (Device, BackupOptions, results, etc.)
transports/ssh/ # netmiko-based SSH runner
diffing/ # unified diff generator
filters/ # dynamic content filters (timestamps, uptime)
output/ # text and JSON renderers
config/ # default and example configuration files
scripts/
tests/
docs/
Integration Scenarios
- Call the CLI from CI/CD pipelines or cron schedulers
- Consume machine-readable output via
--output json - Embed the Python package into a larger internal service
Governance
NetConfigPulse is maintained by 21Vianet as the lead steward. External contributions are welcome, while roadmap direction, release management, and future commercial packaging remain under maintainer control.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file netconfigpulse-0.1.1.tar.gz.
File metadata
- Download URL: netconfigpulse-0.1.1.tar.gz
- Upload date:
- Size: 21.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64f145efedba65ec5c6c3be8ff5926edbce52d659cfa6f286a5c4f1a307f52bc
|
|
| MD5 |
7a5c24d671c441eab02778d2050b19b6
|
|
| BLAKE2b-256 |
4aec53e8a5766c33008d3628748dccda904a858d6e814500fb141b667061f0a7
|
File details
Details for the file netconfigpulse-0.1.1-py3-none-any.whl.
File metadata
- Download URL: netconfigpulse-0.1.1-py3-none-any.whl
- Upload date:
- Size: 22.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ab47e6f3e7dcd3f7d9e8f4b7548ec4be4c98ee556eddd2205e1ba90aa408d8a0
|
|
| MD5 |
f756bf54f393934a94026ec51e28aee1
|
|
| BLAKE2b-256 |
f5a85270a6f2b68188af09d43c2fd949b05711abb0bf0ac0a686332273f6f432
|