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.
Install the released package from PyPI:
pip install NetConfigPulse
netconfigpulse --helpUse 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.yamlThis validates the example configuration without connecting to any device. Use
backup only after replacing the example devices and credentials with real
values.
From PyPI:
pip install NetConfigPulse
netconfigpulse --helpThe 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.yamlThree subcommands: validate, backup, import-csv.
After installation, both python -m netconfigpulse ... and the console command
netconfigpulse ... are supported.
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.yamlRuns 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.yamlAll 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.
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.yaml0— all devices succeeded1— the entire run failed (no devices succeeded)2— partial failure (some succeeded, some failed)
config/devices.example.yaml
devices:
- name: edge-r1
host: 192.0.2.10
vendor: cisco_ios
tags:
- production
- edge
group: coreconfig/commands.default.yaml
vendors:
cisco_ios:
backup:
- terminal length 0
- show runningconfig/credentials.example.yaml
defaults:
username: backup-user
password: change-meconfig/runtime.example.yaml
backup_root: backups
concurrency: 10
min_backup_size_bytes: 2000
backup_retry_attempts: 3
backup_retry_delay_seconds: 10python -m netconfigpulse backup \
--inventory config/devices.example.yaml \
--commands config/commands.default.yaml \
--credentials config/credentials.example.yaml \
--config config/runtime.example.yamlBacked up 1 device: 1 succeeded, 0 failed, 0 warned, 1 changed.
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
}
]
}NetConfigPulse can also be used directly as a Python library.
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))| 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 |
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
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,
)
],
)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.
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/
- 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
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.