NetAuto Academy

Professional Project

Automated Network Change Planner

Advanced65 min

Objective

Validate a batch of proposed network changes against a device inventory -- without ever connecting to a device or applying anything -- to produce a reviewable, sequenced change plan that flags unknown devices, conflicting requests, and devices that must be excluded.

Builds on Reliable Automation and Production Automation.

Prerequisites

  • Comfortable with dictionaries, sets, and safe .get()-based lookups
  • Familiar with dry-run thinking -- validating a change before anything is applied (Dry-Run Mode and Safe Change Workflows)
  • Familiar with why a production rollout needs more than a clean dry-run (Why Production Rollout Needs More Than Dry-Run and Review)

Deliverables

  • A conflict detector that flags any device targeted by more than one requested change in the same batch
  • A validation pass that safely rejects a change targeting a device that doesn't exist in inventory
  • An exclusion pass that removes devices currently under maintenance from the batch
  • One ordered, human-readable change plan with a rollback note per ready item -- never an executed change
Local/offline only. The inventory and change request below are fixed sample data. This project never connects to a device, never pushes configuration, and never executes anything -- it only plans and validates.

The problem

Not the same task as the existing Git-diff or canary-sizing labs

"Reviewing a Configuration Change for Risk" already has a Git diff and applies one risk heuristic to it. "A Canary Sizing Decision" already assumes a rollout is underway and asks how big the canary should be. This project happens before either of those: a batch of requested changes has just come in, as plain structured requests -- no diff exists yet, and nothing has been staged. The question here is simpler and earlier: is this batch of requests even safe to hand to a reviewer as-is?

Planning only -- nothing here is ever applied

This project never connects to a device, never generates a diff, and never pushes configuration. Every function below only reads structured Python data and produces a plan. That plan is what a human reviewer would look at next -- this project stops there.

Five changes were requested against a small fleet in one batch. One device doesn't exist in inventory at all -- a typo, or a device that was decommissioned. One device is under maintenance and shouldn't be touched this cycle. And one device has two different changes requested against it in the same batch -- nobody caught that two people proposed changes to the same box. Your job: build the validation and planning layer that catches all three problems automatically, before a human ever has to notice them by reading the raw list.

Starter data

DEVICE_INVENTORY and CHANGE_REQUEST -- safe sample data
DEVICE_INVENTORY = [
  {"name": "RTR1", "site": "hq", "status": "active"},
  {"name": "RTR2", "site": "hq", "status": "active"},
  {"name": "SW1", "site": "branch1", "status": "maintenance"},
]

CHANGE_REQUEST = [
  {"device": "RTR1", "change": "add acl GUEST-ACL permit tcp any any eq 443"},
  {"device": "RTR1", "change": "remove ntp server 10.60.10.2"},
  {"device": "RTR2", "change": "configure ntp server 10.60.10.9"},
  {"device": "SW1", "change": "add vlan 20 name GUEST"},
  {"device": "SW9", "change": "add vlan 20 name GUEST"},
]

Fixed sample data. RTR1 has two separate changes requested against it (a conflict); SW1 is under maintenance; SW9 doesn't exist in DEVICE_INVENTORY at all; only RTR2's change is clean.

Milestones

  1. Load the change request and device inventorystructured requests, not a diff or a live device
  2. Validate each change against inventorydetect an unknown device safely
  3. Detect conflicting requestsmore than one change targeting the same device
  4. Exclude devices under maintenanceremove them from this batch
  5. Build the ready change sequenceordered, with a rollback note per item
  6. Produce the final change plan summaryone human-readable plan, nothing executed

Task

Write three functions:

  1. find_conflicting_devices(change_items) -- return a set of device names that appear more than once across change_items.
  2. rollback_note(change_text) -- return a short string describing how to revert the change, based on how change_text starts: "add " → a note about removing what was added; "remove " → a note about re-adding what was removed; "configure " → a note about restoring the previous value; anything else → a generic fallback note.
  3. build_change_plan(change_items, inventory) -- for every item in change_items, in order: if its device isn't in inventory, add it to blocked with a reason. Otherwise, if its device is in the conflicting-devices set, add it to conflicts with a reason. Otherwise, if its device's status is "maintenance", add it to excluded with a reason. Otherwise, add it to ready with a rollback note attached. Sort ready by device name. Return {"summary": {...}, "change_sequence": ready, "conflicts": [...], "excluded": [...], "blocked": [...]}, where summary includes total_requested_changes, ready, conflicts, excluded_maintenance, and blocked_unknown_device counts.
starter.py
DEVICE_INVENTORY = [
  {"name": "RTR1", "site": "hq", "status": "active"},
  {"name": "RTR2", "site": "hq", "status": "active"},
  {"name": "SW1", "site": "branch1", "status": "maintenance"},
]

CHANGE_REQUEST = [
  {"device": "RTR1", "change": "add acl GUEST-ACL permit tcp any any eq 443"},
  {"device": "RTR1", "change": "remove ntp server 10.60.10.2"},
  {"device": "RTR2", "change": "configure ntp server 10.60.10.9"},
  {"device": "SW1", "change": "add vlan 20 name GUEST"},
  {"device": "SW9", "change": "add vlan 20 name GUEST"},
]


def find_conflicting_devices(change_items):
  # Your code here.
  ...


def rollback_note(change_text):
  # Your code here.
  ...


def build_change_plan(change_items, inventory):
  # Your code here.
  ...


if __name__ == "__main__":
  plan = build_change_plan(CHANGE_REQUEST, DEVICE_INVENTORY)
  print(plan["summary"])

Copy into a local .py file and run with plain python3 -- no install needed. find_conflicting_devices(), rollback_note(), and build_change_plan() are intentionally incomplete.

Hints

Expected output

terminal output -- real, verified run
--- Change Plan Summary ---
Total requested changes:  5
Ready:                    1
Conflicts:                2
Excluded (maintenance):   1
Blocked (unknown device): 1

--- Change sequence (ready to review, in order) ---
RTR2: configure ntp server 10.60.10.9
rollback: Restore the previous configured value to revert: configure ntp server 10.60.10.9

--- Conflicts ---
RTR1: add acl GUEST-ACL permit tcp any any eq 443 -- multiple requested changes target this device in the same batch
RTR1: remove ntp server 10.60.10.2 -- multiple requested changes target this device in the same batch

--- Excluded ---
SW1: add vlan 20 name GUEST -- device is under maintenance -- exclude from this batch

--- Blocked ---
SW9: add vlan 20 name GUEST -- unknown device: not found in inventory

Real, verified output from a working solution against the exact starter data above. Your own report's formatting can differ, but the counts and per-item classifications must match.

Validation checklist

Self-check only -- nothing here is submitted or graded. Compare against your own output manually.

Solution

Solution

Try the task yourself first -- the full solution and explanation stay hidden until you click above.

Key takeaways

  • Validating a change request against inventory, for conflicts, and against device status are three independent checks -- and the order they run in matters when a later check assumes the earlier ones already passed.
  • A planning tool's job is to produce a reviewable plan, not to decide anything on its own -- every item that fails a check gets a named reason, and a human still makes the final call.
  • A rollback note attached at planning time, before anything is applied, is cheaper to write and easier to trust than reconstructing 'what would revert this' after a change has already gone out.
  • Nothing in this project connects to a device, generates a diff, or applies a configuration change -- every function here only reads and reasons about structured Python data.

Related lessons

Done with this project?