Author: Joven Talasan
Python 3.10+ network automation tool for pushing configuration to thousands of network devices in parallel via SSH. Supports Cisco IOS/IOS-XE, Alcatel AOS OmniSwitches, and Alcatel AOS-W WLCs.
| Task | Description |
|---|---|
| Push config | Push SNMPv3, syslog, ACL, or any config to 1,000+ devices in minutes |
| Backup | Save full running-config from every device |
| Inventory | Auto-discover hostname, serial, model, firmware version on every run |
| Retry | Track failed devices and retry separately |
| Pre/Post check | Capture device state before and after every change |
| Compliance | Run CIS baseline checks against saved configs |
# 1. Install dependencies
pip install -r requirements.txt
# 2. Set up credentials (run once, as the Windows user that runs Netpilot)
cd src
.\setup_credentials.ps1
# 3. Add devices to config/devices.csv
# 4. Test on one device (replace TASKNAME / taskname with your task, e.g. SNMPV3/snmpv3 or SYSLOG/syslog)
python -m src --task TASKNAME --commands taskname --ip 10.0.0.1 --vendor cisco
# 5. Roll out to all devices
python -m src --task TASKNAME --commands taskname --devices config/devices.csv --workers 20
# 6. Retry any failures
python -m src --task TASKNAME --commands taskname --retry --workers 10Credentials are DPAPI-encrypted on Windows — only decryptable by the same Windows user account that created them. Run the setup script once before first use, and again whenever passwords change.
cd src
.\setup_credentials.ps1The script prompts for 4 credential sets in this order:
| Prompt | What to enter | Files created |
|---|---|---|
CRED_NETWORK_1 |
Username + password (e.g. your_username_1) |
network_1.txt, network_1_pwd.txt |
CRED_NETWORK_2 |
Username + password (e.g. your_username_2) |
network_2.txt, network_2_pwd.txt |
CRED_NETWORK_3 |
Username + password (first password) | network_3.txt, network_3_pwd.txt |
CRED_NETWORK_4 |
Password only — inherits username from network_3 (second password) | network_4_pwd.txt |
Netpilot tries each credential set in order until one succeeds. If a credential set file is missing, it is silently skipped.
Important: Always run
setup_credentials.ps1as the same Windows user that runs Netpilot. DPAPI files are user-specific — files created by another user account will silently fail to decrypt.
Linux / environment variable override:
export CRED_NETWORK_1="username"
export CRED_NETWORK_1_PWD="password"Credential files are stored in the path set by secrets_dir_windows in config.yaml (default: D:\Prod_Automation\env\prod\secrets_v3).
Minimum required columns:
host,vendor,role,site
10.0.0.1,cisco,cisco_core,Site-A
10.0.0.2,cisco,cisco_dataswitch,Site-A
10.0.0.3,alcatel,alcatel_dataswitch,Site-B
10.0.0.4,alcatel,alcatel_poeswitch,Site-B
10.0.0.5,alcatel_wlc,wlc,Site-Avendor |
Netmiko device_type | Use for |
|---|---|---|
cisco |
cisco_ios |
Cisco IOS/IOS-XE switches and routers |
alcatel |
alcatel_aos |
Alcatel-Lucent OmniSwitches (OS6860, OS6900, etc.) |
alcatel_wlc |
aruba_os |
Alcatel-Lucent WLCs (OAW-4550, OAW-4350, OAW-4250) |
role |
Config folder used |
|---|---|
cisco_core |
config/cisco/ |
cisco_dataswitch |
config/cisco/ |
cisco_poeswitch |
config/cisco/ |
alcatel_core |
config/alcatel/ |
alcatel_dataswitch |
config/alcatel/ |
alcatel_poeswitch |
config/alcatel/poe_switch/ (role override) |
wlc |
config/alcatel_wlc/ or config/cisco/ |
Hostname, serial, model, and firmware version are discovered automatically from the device on every run — no need to pre-fill them.
Testing tip: Copy a few rows into config/testdata_devices.csv and test against that before running against all devices.
Netpilot is a generic config push engine. A task is any set of commands you want to push to devices — SNMPv3, syslog server migration, NTP, ACL, banner, or anything else. The --task flag is just a label for the inventory; --commands tells it which command files to load.
Each task uses up to 3 files per vendor:
| File | Purpose | When |
|---|---|---|
config/{vendor}/{task}_pre.txt |
Show commands — snapshot before change | Before push |
config/{vendor}/{task}.txt |
Config commands to push to device | Config push |
config/{vendor}/{task}_post.txt |
Show commands — verify change applied | After push |
File resolution order (most specific wins):
config/{vendor}/{role_suffix}/{task}.txt— role override (e.g.alcatel/poe_switch/snmpv3.txt)config/{vendor}/{task}.txt— vendor default
| Task | --commands |
Cisco | Alcatel dataswitch | Alcatel poe_switch | Alcatel WLC |
|---|---|---|---|---|---|
| SNMPv3 push | snmpv3 |
cisco/snmpv3.txt |
alcatel/snmpv3.txt |
alcatel/poe_switch/snmpv3.txt |
alcatel_wlc/snmpv3.txt |
| Syslog config | syslog |
cisco/syslog.txt |
alcatel/syslog.txt |
— | — |
| Config backup | backup |
cisco/backup.txt |
alcatel/backup.txt |
— | — |
Create command files for each vendor you need, then run with any task label:
config/cisco/ntp.txt ← Cisco commands
config/cisco/ntp_pre.txt ← show commands before (optional)
config/cisco/ntp_post.txt ← show commands after (optional)
config/alcatel/ntp.txt ← Alcatel commands
python -m src --task NTP --commands ntp --devices config/devices.csv --workers 20The --task label (e.g. NTP) is recorded in the inventory so you can track which devices have been configured for each task independently.
SNMPv3 (--commands snmpv3):
| Vendor | Command syntax notes |
|---|---|
| Cisco | configure terminal + snmp-server commands + write memory |
| Alcatel dataswitch | Direct commands (no config mode), sha256+aes256, write memory flash-synchro |
| Alcatel poe_switch | Same as dataswitch but sha256+aes (older firmware) and snmp authentication-trap enable (hyphen) |
| Alcatel WLC (AOS-W) | configure terminal + auth-prot sha / priv-prot aes syntax + write memory |
Syslog (--commands syslog):
Pushes new syslog server config and verifies with pre/post checks. Use syslog_remove.txt to roll back:
python -m src --task SYSLOG_REMOVE --commands syslog_remove --devices config/devices.csv --workers 20Backup (--commands backup + --backup flag):
Saves full running-config per device to BACKUP\YYYY-MM\{hostname}_{timestamp}.cfg:
python -m src --task BACKUP --commands backup --backup --devices config/devices.csv --workers 20# Test on a single device
python -m src --task SNMPV3 --commands snmpv3 --ip 10.0.0.1 --vendor cisco
python -m src --task SYSLOG --commands syslog --ip 10.0.0.1 --vendor alcatel
# Test on a small subset CSV before full rollout
python -m src --task SNMPV3 --commands snmpv3 --devices config/testdata_devices.csv
# Roll out to all devices
python -m src --task SNMPV3 --commands snmpv3 --devices config/devices.csv --workers 20
python -m src --task SYSLOG --commands syslog --devices config/devices.csv --workers 20
# Retry failed devices only
python -m src --task SNMPV3 --commands snmpv3 --retry --workers 10
# Backup all running-configs
python -m src --task BACKUP --commands backup --backup --devices config/devices.csv --workers 20
# Remove syslog config (rollback)
python -m src --task SYSLOG_REMOVE --commands syslog_remove --devices config/devices.csv --workers 20
# Preview commands without connecting
python -m src --task SNMPV3 --commands snmpv3 --devices config/devices.csv --dry-run
# Update a monitoring CSV status column after successful runs
python -m src --task SNMPV3 --commands snmpv3 --devices config/devices.csv --workers 20 --status-file data/dataswitches.csv| Flag | Description |
|---|---|
--task NAME |
Task label used in inventory (e.g. SNMPV3, SYSLOG) |
--commands NAME |
Command file prefix (e.g. snmpv3 → {vendor}/snmpv3.txt) |
--ip IP |
Single device IP |
--vendor VENDOR |
Vendor for --ip mode |
--devices FILE |
Device CSV file |
--retry |
Retry failed devices from config/failed_devices.csv |
--workers N |
Parallel workers (default: 1) |
--backup |
Save full running-config backup per device to BACKUP/ |
--dry-run |
Show what would run without connecting |
--validate |
Validate device list and command files |
--log |
Enable SSH session logging to LOGS/ |
--status-file FILE |
Update Status column to Configured in a monitoring CSV — CSV must have a host or ip column |
--consolidate |
Merge all SUMMARY CSVs into one file |
--report [FILE] |
Report from a SUMMARY csv (omit FILE for latest) |
--format csv|json |
Summary output format (default: csv) |
--retention DAYS |
Backup retention in days (0 = keep all) |
--diff FILE1 FILE2 |
Compare two config files |
--health-check |
SSH health check on all devices |
--baseline VENDOR |
Run CIS compliance check on backup configs |
Each worker is one simultaneous SSH connection (one device at a time per worker).
| Workers | 10,000 devices @ 30s each |
|---|---|
| 10 | ~8.3 hours |
| 20 | ~4.2 hours |
| 30 | ~2.8 hours |
| 50 | ~1.7 hours |
Start with
--workers 20and increase if the network handles it. Each device gets exactly one connection — workers do not share connections.
Set a permanent default in config.yaml:
execution:
max_workers: 20host,vendor,site,hostname,serial,model,status,error,post_check
10.0.0.1,cisco,Site-A,CORE-SW-01,FCW1234A01B,C9300-48P,success,,show snmp user output...
10.0.0.2,alcatel,Site-B,N1744PS1R1ESW01,,OS6860-P48,error,Auth failed,| Column | Description |
|---|---|
host |
IP address |
hostname |
Discovered live from device |
serial |
Discovered from device |
model |
Discovered from device |
status |
success or error |
error |
Failure reason (if any) |
post_check |
Output of post-check command (e.g. show snmp user) |
| Folder | Contents |
|---|---|
PRE_CHECK\{hostname}.cfg |
Running-config snapshot before changes |
POST_CHECK\{hostname}.cfg |
Verification output after changes |
Persistent, auto-updated on every run. One row per device. Per-task status columns are added automatically.
host,hostname,vendor,site,model,serial,ios_version,last_seen,SNMPV3_status,SNMPV3_date
10.0.0.1,CORE-SW-01,cisco,Site-A,C9300-48P,FCW1234A01B,17.3.5,2026-05-02 15:00,CONFIGURED,2026-05-02 15:00python -m src --consolidate
# Output: SUMMARY\CONSOLIDATED_SUMMARY.csv — one row per device, latest run wins| Error | Cause | Fix |
|---|---|---|
Authentication failed |
Wrong credentials for that device | Check which credential set the device needs |
Error reading SSH protocol banner |
Device dropped connection before SSH handshake | Transient — just retry |
Command read timeout |
Device slow to respond | Already handled with send_command_timing for Alcatel |
Failed to read credential files |
Credential file missing or encrypted by wrong Windows user | Re-run setup_credentials.ps1 as the correct user |
No IP column found |
Status CSV uses host column — now supported |
Upgrade to latest release |
1344 invalid devices |
Device names contain special characters | Fixed in update_inventory.py — parentheses stripped |
- No
configure terminalmode — AOS OmniSwitches use direct commands, not config mode - CERTIFY mode — Some switches show
Setting CERTIFY Timeout for 800 secondson login — handled automatically (global_cmd_verify=False) - poe_switch vs dataswitch — Older firmware uses
sha256+aes(AES-128) andsnmp authentication-trap enable(hyphen); newer usessha256+aes256andsnmp authentication trap enable(no hyphen) - AOS-W WLC — Uses
auth-prot sha/priv-prot aessyntax (not Cisco-styleauth sha)
netpilot/
├── src/
│ ├── __main__.py # CLI entry point
│ ├── config.py # Configuration loading
│ ├── connection.py # SSH connections, command execution, identity parsing
│ ├── utils.py # Credentials, validation, helpers
│ ├── backup.py # Backup rotation and diff
│ ├── compliance.py # CIS baseline checks
│ ├── database.py # SQLite inventory
│ ├── notifications.py # Email/Telegram alerts
│ ├── discovery.py # Subnet scanning
│ ├── syslog_manager.py # Syslog push/removal
│ └── setup_credentials.ps1 # DPAPI credential setup (run once)
├── config/
│ ├── devices.csv # Device list
│ ├── failed_devices.csv # Auto-created after runs with failures
│ ├── alcatel/
│ │ ├── snmpv3.txt, snmpv3_pre.txt, snmpv3_post.txt
│ │ ├── syslog.txt, backup.txt
│ │ └── poe_switch/ # Role override for alcatel_poeswitch
│ │ └── snmpv3.txt, snmpv3_post.txt
│ ├── alcatel_wlc/
│ │ └── snmpv3.txt, snmpv3_pre.txt, snmpv3_post.txt
│ └── cisco/
│ ├── snmpv3.txt, snmpv3_pre.txt, snmpv3_post.txt
│ ├── syslog.txt, backup.txt
├── data/ # Your monitoring CSVs (bring your own)
├── config.yaml # Settings (workers, timeouts, paths)
├── INVENTORY/
│ └── inventory.csv # Persistent — auto-updated every run
├── SUMMARY/YYYY-MM/ # Per-run results
├── PRE_CHECK/ # Config snapshot before each run
├── POST_CHECK/ # Verification output after each run
├── BACKUP/ # Full config backups (--backup flag)
└── LOGS/ # SSH session logs (--log flag)
execution:
max_workers: 20 # Default parallel workers
connection:
banner_timeout: 60 # SSH banner timeout (seconds)
auth_timeout: 60 # Authentication timeout (seconds)
backup:
retention_days: 30 # 0 = keep forever
paths:
secrets_dir_windows: "D:\\Prod_Automation\\env\\prod\\secrets_v3"
secrets_dir_linux: "/opt/automation/secrets"
logs_dir: "LOGS"
backup_dir: "BACKUP"
summary_dir: "SUMMARY"Credential sets are configured under
credentials.sets— see Credential Setup for the full structure.