Skip to main content

A modular, profile-driven Python orchestrator for network device firmware upgrades. Currently supports Cisco IOS-XE.

Project description

simple-upgrade

A modular, profile-driven Python orchestrator for network device firmware upgrades. Built for Cisco IOS-XE with a dynamic JSON device-profile architecture that eliminates hardcoded CLI strings.

Architecture Overview

┌─────────────────────────────────────────────────┐
│                 UpgradePackage                   │
│  (Orchestrator — runs stages sequentially)       │
├──────────┬──────────┬───────────┬───────────────┤
│   sync   │readiness │ pre_check │  distribute   │
│          │          │           │               │
│ activate │post_acti-│post_check │ verification  │
│          │vation_wait│          │     diff      │
├──────────┴──────────┴───────────┴───────────────┤
│              ExecutionContext (ctx)               │
│  Carries: device_info, golden_image, file_server │
│           device_profile, stage_results          │
├─────────────────────────────────────────────────┤
│  Device Profiles (JSON)    │   TaskRegistry      │
│  groups/ → inheritance     │   @register_stage   │
│  models → regex matching   │   manufacturer map  │
└─────────────────────────────────────────────────┘

Key Features

  • Profile-Driven Execution — All CLI commands (show, copy, verify, install, boot) are defined in JSON device profiles, not hardcoded in Python
  • Group Inheritance — Device profiles inherit commands from shared group templates (e.g. install_mode.json)
  • Automatic Profile Matching — Hardware model detected via show version is regex-matched to the correct JSON profile
  • Configuration Integrity Validation — JSON profiles are statically linted at startup for schema errors and overlapping model patterns
  • Smart Download — Skips re-download if file already exists with matching size and MD5
  • Flash Cleanup — Automatically runs install remove inactive before file transfer
  • TCP Socket Polling — Post-reload wait uses intelligent SSH port probing instead of blind sleep timers
  • Dual Logging — Structured JSON execution log + timestamped CLI text log capturing all Unicon/Scrapli output
  • Diagnostic Bundling — Pre/post check diffs packaged into a ZIP archive for audit

Pipeline Stages

# Stage Engine Description
1 sync Scrapli Discover device hardware, match to JSON profile
2 readiness Scrapli Validate flash space, compare running version
3 pre_check Scrapli Snapshot device state (commands from JSON profile)
4 distribute Unicon Transfer firmware image with MD5 verification
5 activate Unicon Execute install command with reload dialog handling
6 post_activation_wait Socket TCP sweep on SSH port until device returns online
7 post_check Scrapli Snapshot post-upgrade state
8 verification Scrapli Confirm running version matches golden image
9 diff Generate pre/post diffs and ZIP bundle

Installation

pip install simple-upgrade

Quick Start

from simple_upgrade import UpgradePackage

pkg = UpgradePackage(
    # ── Required Parameters ──
    host="172.20.20.11",
    username="admin",
    password="admin",
    platform="cisco_iosxe",

    # ── Optional Parameters ──
    port=22,                                    # SSH port (default: 22)
    manufacturer="cisco",                       # Manufacturer key (default: "cisco")
    connection_mode="normal",                   # "normal" | "mock" | "dry_run"
    enable_password="admin",                    # Enable/privilege-exec secret
    source_interface="GigabitEthernet0/0",      # Source interface for file transfers
    source_vrf="Mgmt-vrf",                      # VRF for routing file transfers

    # ── Post-Activation Wait Timers ──
    post_wait_delay=30,                         # Seconds before starting SSH probe (default: 600)
    post_wait_retries=60,                       # Max SSH probe attempts at 15s intervals (default: 120)
    post_wait_convergence=60,                   # STP/routing settle time after SSH returns (default: 30)

    # ── Golden Image ──
    golden_image={
        "version": "17.13.1",                   # Target software version
        "image_name": "cat9k_iosxe.17.13.01.SPA.bin",  # Filename (no flash: prefix)
        "image_size": 1234567890,               # Expected file size in bytes
        "md5": "abc123def456...",                # Expected MD5 checksum
        "sha256": "def456ghi789...",             # Optional SHA-256 checksum
    },

    # ── File Server ──
    file_server={
        "protocol": "http",                     # http | https | tftp | ftp | scp
        "ip": "192.168.29.73",                  # File server IP
        "port": 80,                             # Server port (optional)
        "base_path": "/Cisco/C9XXX/",           # URL path on server
        "username": "ftpuser",                  # FTP/SCP username (optional)
        "password": "ftppassword",              # FTP/SCP password (optional)
    }
)

# Run all stages interactively
for stage in pkg.STAGES:
    result = pkg.run_stage(stage)
    print(f"{stage}: {'✓' if result.success else '✗'}{result.message}")

# Or run the full pipeline automatically
# results = pkg.execute()

Constructor Parameters

Required

Parameter Type Description
host str Device IP address or hostname
username str SSH username
password str SSH password
platform str Software platform: cisco_iosxe, cisco_xe, iosxe

Optional

Parameter Type Default Description
port int 22 SSH port
manufacturer str "cisco" Manufacturer key for profile lookup
connection_mode str "normal" normal, mock, or dry_run
enable_password str None Enable / privilege-exec secret
source_interface str None Source interface for file transfer routing (e.g. GigabitEthernet0/0)
source_vrf str None VRF name for file transfer routing (e.g. Mgmt-vrf)
post_wait_delay int 600 Seconds to wait before starting SSH sweep after activation
post_wait_retries int 120 Max SSH probe attempts (at 15-second intervals)
post_wait_convergence int 30 Seconds to wait for routing/STP convergence after SSH restores

golden_image Dictionary

Key Required Type Description
version Yes str Target software version (e.g. 17.13.1)
image_name Yes str Filename only — no flash: prefix
image_size Yes int Expected file size in bytes
md5 Yes str Expected MD5 checksum
sha256 No str Optional SHA-256 checksum

file_server Dictionary

Key Required Type Description
ip Yes str File server IP address
protocol No str Transfer protocol: http, https, tftp, ftp, scp (default: http)
base_path Yes str URL path on the server (e.g. /Cisco/C9XXX/)
port No int Server port (omit to use protocol default)
username No str FTP/SCP username
password No str FTP/SCP password

Note: source_interface and source_vrf can be specified either as top-level parameters or inside file_server. Top-level values take priority.

Connection Modes

Mode SSH Show Commands Upgrade Commands Use Case
normal Real Real Real Production upgrades
mock None Simulated Simulated CI/CD testing
dry_run Real Real Simulated Pre-flight validation

Device Profile Architecture

Device profiles are JSON files in device_profiles/cisco/ that define all commands the orchestrator will execute. No CLI strings are hardcoded in Python.

Structure

device_profiles/
└── cisco/
    ├── groups/
    │   ├── install_mode.json      # Shared template for install-mode devices
    │   └── lab_vios.json          # Lab-specific overrides
    ├── catalyst_9300x.json        # Device profile → inherits from install_mode
    └── catalyst_VIOS.json         # Device profile → inherits from lab_vios

Profile Fields

Field Type Description
manufacturer str "Cisco"
model str Profile identifier
models list[str] Regex patterns matched against show version model
platform list[str] Platform identifiers (e.g. ["IOS-XE", "cisco_xe"])
group str Parent group template to inherit from
commands dict Show commands for pre/post checks
upgrade_commands dict Copy, verify, install templates with {placeholders}
boot_commands list[str] Boot config commands applied before activation
default_image_location str Target filesystem (e.g. flash:/)

Template Placeholders

The upgrade_commands block supports dynamic placeholders:

Placeholder Resolved From
{protocol} file_server.protocol
{server} file_server.ip:port
{path} file_server.base_path
{image} golden_image.image_name
{md5} golden_image.md5

Output Files

After execution, the following files are generated in output/<hostname>/:

File Format Description
execution_log.json JSON Structured pipeline results with all stage data
execution_cli.log Text Timestamped CLI transcript of all terminal output
precheck/*.txt Text Individual pre-check command outputs
postcheck/*.txt Text Individual post-check command outputs
diff/*.txt Text Per-command pre/post diffs
<hostname>_upgrade_report.zip ZIP Bundled diagnostic archive

Supported Devices

Profile Models Matched Group
catalyst_9300 C9300.*, C9300X.*, C9300L.*, C9KV-UADP-8P install_mode
catalyst_VIOS IOSv lab_vios

Additional profiles can be added by creating a new JSON file in device_profiles/cisco/ with appropriate models regex patterns and an optional group reference.

Requirements

  • Python 3.12+
  • scrapli — SSH connections (readiness, checks, verification)
  • genie / pyats / unicon — File distribution and activation (interactive dialogs)
  • netutils — Version comparison utilities
  • pydantic — Data model validation

License

Apache License 2.0

Author

Tarani Debnath

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

simple_upgrade-1.0.0.tar.gz (187.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

simple_upgrade-1.0.0-py3-none-any.whl (45.8 kB view details)

Uploaded Python 3

File details

Details for the file simple_upgrade-1.0.0.tar.gz.

File metadata

  • Download URL: simple_upgrade-1.0.0.tar.gz
  • Upload date:
  • Size: 187.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for simple_upgrade-1.0.0.tar.gz
Algorithm Hash digest
SHA256 5e177ea0da4e53f7fc6e2d9ce2c5a5b572e1bf6dd402bb907a032a093d5ee622
MD5 d16b786386cba1a8762229104b098344
BLAKE2b-256 2ff8f5d37aed821b8e880035130ec329b3938903573f7b6c3b654f04810bf5a2

See more details on using hashes here.

Provenance

The following attestation bundles were made for simple_upgrade-1.0.0.tar.gz:

Publisher: release.yaml on tkdebnath/simple-upgrade

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file simple_upgrade-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: simple_upgrade-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 45.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for simple_upgrade-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d41b69e5a6025fff990020284e976fbcd5e9754cabf39bfb563a9e4b015c3353
MD5 1e2460574d71f121c49827d07cbb1f40
BLAKE2b-256 f84d290a2459ecdce01a36cd33cf3723225edfa44047c52da0e261f6971a9ea8

See more details on using hashes here.

Provenance

The following attestation bundles were made for simple_upgrade-1.0.0-py3-none-any.whl:

Publisher: release.yaml on tkdebnath/simple-upgrade

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page