NetAuto Academy

Advanced Python Automation for Network Engineers

Capstone: A Reusable Network Automation Package

Advanced20 min read

What you'll learn

  • How every lesson's piece fits into one complete, working package
  • That the package is genuinely tested, not just executed once and trusted
  • The full progression: CLI through report, with nothing skipped
  • That this closes the exact question Lesson 1 opened with
🎓 Teach This Lesson

Listen to a guided explanation of this lesson.

Spoken narration isn't supported in this browser.

The question this module opened with, answered

  1. CLInetwork-tool check — Lesson 8
  2. ConfigurationCLI arg > env var > default — Lesson 8
  3. Inventoryload_inventory() — Lesson 2, upgraded in Lesson 3
  4. Reusable automation enginecheck_device() — Lessons 3-5
  5. Connection abstractionConnection class + @retry — Lesson 4
  6. Executionconcurrent, bounded — Lesson 7
  7. Structured resultsAutomationResult dataclasses — Lesson 3
  8. Validationrequired vs actual VLANs — Lesson 3
  9. Loggingevery step, secret-safe — Lesson 5
  10. Reportreport.json

One-off script → reusable tool, proven, not asserted

This is the exact progression Lesson 1 named. Every stage above is real, working code from an earlier lesson in this module — nothing here is new automation logic. What makes this a capstone is that all nine pieces now run together as one package, tested and invokable, instead of living in nine separate lesson examples.

Quick checkConcept check
How much genuinely new automation logic does this capstone introduce?

The package, assembled

network_automation/ — final structure
network_automation/
  __init__.py
  inventory.py       -- load_inventory()                      (Lesson 2, 3)
  models.py           -- Device, Vlan, AutomationResult, Status (Lesson 3)
  exceptions.py        -- AutomationError and subclasses        (Lesson 3)
  connections.py         -- Connection, @retry                  (Lesson 4)
  logging_config.py       -- configure_logging(), get_logger()   (Lesson 5)
  automation.py             -- check_device()                    (Lessons 3-5)
  cli.py                     -- argparse entrypoint, concurrency  (Lessons 7, 8)
tests/
  test_automation.py           -- unit tests, fakes               (Lesson 6)

Every file traces back to exactly one earlier lesson. This is the full package, not a summary of it.

Quick checkIdentify the correct code
Which file is responsible for translating requests' own exceptions and status codes into this package's DeviceUnreachableError/AuthenticationError?

Running it: the complete, real output

terminal
$ export AUTOMATION_TOKEN=demo-token
$ python -m network_automation.cli check --inventory devices.csv --workers 5 --report report.json

Genuinely runnable exactly as shown, against this module's mock backend (Option B).

output — real, verified
Checked 5 devices
already-compliant: 1
validation-failed: 2
auth-failed: 1
unreachable: 1
Report written to report.json

Real, verified output — the same 5-device fleet and the same four outcomes every module since Phase 2.6 has ultimately produced, now via a tested package instead of a single script.

report.json
[
  {
      "hostname": "SW1",
      "status": "already-compliant",
      "detail": "no change needed"
  },
  {
      "hostname": "SW2",
      "status": "validation-failed",
      "detail": "missing VLANs: [10]"
  },
  {
      "hostname": "SW5",
      "status": "auth-failed",
      "detail": "SW5 rejected the credentials"
  },
  {
      "hostname": "SW3",
      "status": "validation-failed",
      "detail": "missing VLANs: [30]"
  },
  {
      "hostname": "SW4",
      "status": "unreachable",
      "detail": "SW4 timed out"
  }
]

Real, verified output — diffed exactly against a real run. Order reflects concurrent completion (Lesson 7), not submission order — SW1/SW2/SW5 finish first, SW3's retry and SW4's timeout finish later.

Quick checkPredict output
Why does the report list devices in the order SW1, SW2, SW5, SW3, SW4 rather than the CSV's own SW1-SW5 order?

Actually tested — run again here, not just claimed

terminal
$ python -m unittest discover -v -s tests

Genuinely re-run for this capstone, not assumed from Lesson 6.

output — real, verified
test_already_compliant ... ok
test_authentication_failure ... ok
test_missing_vlan_is_validation_failed ... ok
test_unreachable_device ... ok

----------------------------------------------------------------------
Ran 4 tests in 1.002s

OK

Real, verified output. The full package's core logic is proven correct without a live target — the actual, concrete meaning of 'reusable and maintainable' this module has been building toward since Lesson 1.

Two ways to run it

Option A — a real backend is available
  1. Any device/controller/API matching Connection's interfacesubject to availability
  2. Point --base-url at it, with real credentials
  3. A real report.json
Option B — no real backend needed
  1. This module's own mock backend
  2. Nothing beyond Python and requests
  3. The exact report.json shown above

Option A — Connection's interface (get_state/apply_state) is deliberately generic; pointing --base-url at a real device, controller, or API that speaks the same shape works without changing any calling code — the concrete payoff of the abstraction built in Lesson 4. Never executed in this authoring environment; not claimed as tested. Option B — this module's own mock backend is a complete, required, fully-executed path: every result above is real.

Quick checkMyth check
Does completing this capstone require pointing the package at a real device, controller, or API?

What this module actually built

Nothing here replaced Netmiko, Ansible, requests, or the controller client from earlier modules — every one of them remains exactly as valid a way to reach a device or API as when it was taught. What changed is how the code around those capabilities is organized: a package instead of a script, dataclasses instead of loose dicts, a real exception hierarchy instead of compared strings, a class where state and behavior belong together, real logging, real tests against fakes, bounded concurrency, and a real CLI. One-off script → reusable tool — not a claim, a package that was actually run and actually tested.

Key takeaways

  • Every piece of this capstone — inventory, models, exceptions, connections, logging, concurrency, CLI — is exactly what Lessons 2 through 8 already built and verified. This lesson is integration, not new capability.
  • The CLI was actually run: 5 devices, 4 outcomes, a real report.json, diffed exactly against a real run.
  • The test suite was actually re-run here: 4 tests, 1.002s, OK — proof, not a claim.
  • Result order (SW1, SW2, SW5, SW3, SW4) is a direct, visible consequence of concurrent execution — not arbitrary.
  • Option A (a real backend) is optional and was not executed here — the package's completeness rests on what was genuinely run: the mock-backend capstone and the real test suite.