Multi-vendor network automation framework with parallel execution support.
- Multi-vendor support: Juniper (hybrid SSH+NETCONF), Arista (eAPI), Generic SSH, Telnet (raw socket)
- Parallel execution: Run commands across multiple devices simultaneously
- Job mode: Per-device commands via JSON job file (
--job) - Batch mode: Multiple commands per device on a single connection (
--batch) - Command templates: Built-in JSON template library per vendor (bgp, ospf, interfaces, etc.)
- Cross-device diff: Compare output across devices (
--diff) - Safety gate: Per-device rate limiting and cooldown (
--safety-file) - Audit logging: JSONL audit trail for edit operations (
--audit-log) - Machine-friendly:
--jsonoutput,--targetinline devices, env var credentials - Human-friendly: Interactive prompts, verbose mode, pre-flight checks, dry-run
- Dual timeout control: Separate timeouts for connection and command execution
- Commit confirmed: Safe Junos configuration changes with automatic rollback
- Library & CLI: Use as a command-line tool or import as a Python library
- No deprecated dependencies: Raw socket telnet (no stdlib telnetlib, works on Python 3.13+)
python3 -m venv .venv
source .venv/bin/activate
# Base (SSH + telnet)
pip install paramiko
# Vendor libraries (install what you need)
pip install junos-eznc # Juniper (NETCONF)
pip install pyeapi # Arista (eAPI)# Show command with inline targets
./h-ssh.py --user admin -sC bgp --target R1:10.0.1.1:junos --target R2:10.0.1.2:junos
# Show command with CSV inventory
./h-ssh.py --user admin -sC "show version" --devices devices.csv
# JSON output
./h-ssh.py --user admin --json -sC bgp --target R1:10.0.1.1:junos
# Configuration (dry-run first)
./h-ssh.py --user admin -eC "set system ntp server 10.0.0.1" --dry-run
./h-ssh.py --user admin -eC "set system ntp server 10.0.0.1" -y
# Batch mode (multiple commands per device)
./h-ssh.py --user admin --batch commands.txt --target R1:10.0.1.1:junos
# Job mode (per-device commands from JSON)
./h-ssh.py --user admin --job jobs.json --json
# Cross-device diff
./h-ssh.py --user admin -sC bgp --diff --target R1:10.0.1.1:junos --target R2:10.0.1.2:junos
# Telnet (raw socket, works on Python 3.13+)
./h-ssh.py --user admin -sC "show version" --target SW1:10.0.0.1:5000:telnet-ios
# Commit confirmed with auto-rollback
./h-ssh.py --user admin -eB configs/all.set --commit-confirmed 10 -y[
{"target": "R1:10.0.1.1:junos", "show": "show bgp summary"},
{"target": "R2:10.0.1.2:junos", "show": "show version"},
{"target": "R3:10.0.1.3:junos", "edit": "set system host-name R3-new"}
]./h-ssh.py --user admin --job jobs.json --json
cat jobs.json | ./h-ssh.py --user admin --job - --json# SSH key auth (no password)
./h-ssh.py --user admin -sC bgp
# Password via flag or env var
./h-ssh.py --user admin --password secret -sC bgp
export HSSH_USER=admin HSSH_PASSWORD=secret && ./h-ssh.py -sC bgpTemplates in commands/{vendor}.json:
./h-ssh.py --list-commands # Junos
./h-ssh.py --transport arista --list-commands # AristaOverride with ~/.h-ssh/commands/{vendor}.json.
| Flag | Mode | Description |
|---|---|---|
-sC |
Show | Run show/display commands |
-eC |
Edit command | Apply a single config command |
-eD |
Edit directory | Per-device configs from <NAME>.set files |
-eB |
Edit broadcast | Same config file applied to all devices |
--batch |
Batch | Multiple show commands from file, single connection |
--job |
Job | Per-device commands from JSON file |
- Pre-flight checks: Edit operations verify reachability before proceeding
- Confirmation prompt: Edit operations require
y/N(skip with-y) - Dry-run:
--dry-runshows diffs without committing - Commit confirmed:
--commit-confirmed Nauto-rollbacks after N minutes (Junos) - Safety gate:
--safety-file PATHenables per-device rate limiting (10/device) and cooldown (120s on error) - Audit log:
--audit-log PATHrecords all edit operations as JSONL - Structured stderr:
[h-ssh] {"targets":3,"ok":2,"fail":1,...}on every invocation
| Vendor | Transport | Library | Show | Edit | Batch |
|---|---|---|---|---|---|
junos |
SSH (show) + NETCONF (config) | paramiko + junos-eznc | Paramiko SSH | PyEZ NETCONF | Single SSH connection |
arista |
eAPI (HTTPS) | pyeapi | eAPI enable | eAPI config | Single eAPI connection |
ssh |
SSH | paramiko | exec_command | exec_command | Single SSH connection |
telnet |
Raw socket | (built-in) | Raw TCP | Config mode | Single TCP connection |
telnet-ios |
Raw socket (IOS prompts) | (built-in) | Raw TCP | configure terminal | Single TCP connection |
telnet-junos |
Raw socket (Junos prompts) | (built-in) | Raw TCP | configure/commit | Single TCP connection |
from hssh import Target, vendors
from hssh.runner import run_for_target
# Direct vendor call
output = vendors.junos.show("10.0.1.1", "admin", None, "show version", 30, 20)
# Runner with safety gate
target = Target(name="R1", host="10.0.1.1", vendor="junos")
name, ok, output, ms = run_for_target(
t=target, transport="junos", mode="show",
show_cmd="show version", edit_cmd=None,
config_dir=None, broadcast_file=None,
user="admin", passwd=None,
session_timeout=30, command_timeout=20,
dry_run=False, commit_confirmed=None, save_dir=None,
)h-ssh/
├── hssh/ # Main package
│ ├── __init__.py # Package exports
│ ├── core.py # Target, CSV loader, command resolver, job parser
│ ├── cli.py # CLI argument parsing and orchestration
│ ├── runner.py # Task execution engine
│ ├── safety.py # SafetyGate: rate limiting + cooldown
│ ├── audit.py # JSONL audit trail for edits
│ └── vendors/ # Vendor implementations
│ ├── junos.py # Hybrid SSH+NETCONF
│ ├── arista.py # eAPI
│ ├── generic.py # Paramiko SSH
│ └── telnet.py # Raw socket telnet
├── commands/ # Command template library (JSON)
├── tests/ # Test suite
├── h-ssh.py # CLI entrypoint
└── devices.csv # Example inventory
Tested against live Junos vMX routers (24.2R1-S2.5) — 37 unit tests and 59 live integration tests covering all modes, error handling, concurrency, and safety features. Full results in TESTS.md.
MIT