Your First Network Automation
Putting It All Together: The Complete Project
What you'll learn
- How the inventory, simulated connection, and validation stages combine into one complete project
- How to read a multi-function script end to end, stage by stage
- How to trace the sample inventory through to the exact terminal output and JSON report it produces
- That this project's structure is exactly what 'Netmiko Fundamentals' builds on, not replaces
- A small extension challenge to test your own understanding of the whole project
Listen to a guided explanation of this lesson.
Spoken narration isn't supported in this browser.
Every stage, assembled
Three lessons built three separate pieces: an inventory layer that loads and validates devices, a simulated connection function that stands in for real SSH, and validation logic that turns raw state into a categorized report. This lesson wires all three together into one complete, real script — your first finished network automation tool.
- CSV inventorydevices.csv
- Load devicescsv.DictReader
- Process each devicefor device in valid_devices:
- Simulated connectionsimulate_connection(device)
- Simulated command / resultNTP + VLAN state returned
- Validationcheck_compliance(state)
- Categorize resultcompliant / non-compliant / unreachable
- JSON reportcompliance_report.json
- Terminal summarycounts + where to find the report
No real devices, no Netmiko
This script doesn't connect to anything real — simulate_connection() still stands in for that, exactly as Lesson 3 built it. It's runnable right now, on your own machine, with nothing beyond the Python standard library.
The complete script
import csv
import json
def is_valid_device(device):
"""A device record needs at least a hostname and an IP to be usable."""
return bool(device.get("hostname")) and bool(device.get("ip"))
def simulate_connection(device):
"""
Stands in for a real SSH connection — this exact function is what
gets replaced with a real Netmiko call in the next module. Returns
the device's current NTP and VLAN compliance state, or raises
ConnectionError if the device can't be reached.
"""
simulated_state = {
"SW1": {"reachable": True, "ntp_synced": True, "vlan_compliant": True},
"SW2": {"reachable": True, "ntp_synced": False, "vlan_compliant": True},
"SW3": {"reachable": False, "ntp_synced": None, "vlan_compliant": None},
}
state = simulated_state.get(device["hostname"])
if state is None or not state["reachable"]:
raise ConnectionError(f"{device['hostname']} is unreachable")
return state
def check_compliance(state):
"""Turn a device's raw state into a plain-language compliance status."""
if state["ntp_synced"]:
if state["vlan_compliant"]:
return "compliant"
else:
return "vlan non-compliant"
else:
return "ntp non-compliant"
# --- Load and validate inventory ---
with open("devices.csv") as f:
devices = list(csv.DictReader(f))
valid_devices = []
for device in devices:
if is_valid_device(device):
valid_devices.append(device)
else:
print(f"Skipping invalid inventory record: {device}")
# --- Process every device ---
results = []
for device in valid_devices:
print(f"Checking {device['hostname']}...")
try:
state = simulate_connection(device)
except ConnectionError:
print(f"{device['hostname']}: unreachable")
results.append({
"hostname": device["hostname"],
"ip": device["ip"],
"status": "unreachable",
})
continue
status = check_compliance(state)
print(f"{device['hostname']}: {status}")
results.append({
"hostname": device["hostname"],
"ip": device["ip"],
"status": status,
})
# --- Write the report ---
with open("compliance_report.json", "w") as f:
json.dump(results, f, indent=4)
# --- Terminal summary ---
compliant = 0
needs_attention = 0
for result in results:
if result["status"] == "compliant":
compliant += 1
else:
needs_attention += 1
print()
print("--- Summary ---")
print(f"Checked: {len(results)} devices")
print(f"Compliant: {compliant}")
print(f"Needs attention: {needs_attention}")
print("Report written to compliance_report.json")Save this as network_health_check.py alongside devices.csv and run 'python network_health_check.py' — no installs, no real switches.
Nothing here is new: every function, every loop, every try/except is exactly what the last three lessons built, copied in and called in order.
The sample input
hostname,ip,platform
SW1,10.10.10.1,cisco_ios
SW2,10.10.10.2,cisco_ios
SW3,10.10.10.3,cisco_iosThe same three-device inventory used throughout this module — SW1 fully healthy, SW2 reachable but out of NTP sync, SW3 unreachable.
Each stage, explained
- Load and validate inventory —
csv.DictReaderreadsdevices.csv;is_valid_devicefilters out any incomplete record before anything tries to use it. (Lesson 2.) - Process each device — one loop, visiting every valid device exactly once. (The core "ONE workflow, MANY devices" mechanic from the Python module.)
- Simulated connection —
simulate_connection(device)returns the device's state, or raisesConnectionError— the seam that becomes a real Netmiko call next module. (Lesson 3.) - Validation —
check_compliance(state)turns raw NTP/VLAN facts into one plain-language status. (Lesson 4.) - Categorize result — every device, reachable or not, gets exactly one entry appended to
results. - JSON report —
json.dump(results, f, indent=4)saves the full, categorized result set tocompliance_report.json. - Terminal summary — a short, human-readable count, so nobody has to open the JSON file just to know whether anything needs attention.
Running it: expected terminal output
Checking SW1...
SW1: compliant
Checking SW2...
SW2: ntp non-compliant
Checking SW3...
SW3: unreachable
--- Summary ---
Checked: 3 devices
Compliant: 1
Needs attention: 2
Report written to compliance_report.jsonOne 'Checking...' / result line per device, then a short summary — three checked, one fully compliant, two needing attention (SW2's NTP drift, SW3 being down).
The generated report
[
{
"hostname": "SW1",
"ip": "10.10.10.1",
"status": "compliant"
},
{
"hostname": "SW2",
"ip": "10.10.10.2",
"status": "ntp non-compliant"
},
{
"hostname": "SW3",
"ip": "10.10.10.3",
"status": "unreachable"
}
]Every device from the inventory has exactly one entry — nothing silently dropped, every status traceable back to what simulate_connection() and check_compliance() actually decided for it.
A small challenge
Try this yourself, without looking at the script above while you predict the answer first:
Add a fourth device to devices.csv — SW4,10.10.10.4,cisco_ios — and add a matching entry to simulated_state inside simulate_connection(): "SW4": {"reachable": True, "ntp_synced": True, "vlan_compliant": False}.
What to change: exactly those two additions — one CSV row, one dictionary entry. Nothing else in the script needs to change.
Expected behavior: the terminal should print a fourth "Checking SW4..." line followed by SW4: vlan non-compliant, compliance_report.json should gain a fourth entry with that status, and the summary should update to Checked: 4 devices, Compliant: 1, Needs attention: 3.
What's ahead
One function changes; everything else stays
"Netmiko Fundamentals," next, replaces simulate_connection() with a function that opens a real SSH session and runs real commands — everything else in this script (the inventory layer, check_compliance, result collection, the JSON report, the terminal summary) carries over unchanged. You're not about to learn automation from scratch with a real device — you're about to plug a real connection into a tool you already built and understand completely.
Key takeaways
- This project combines three functions — is_valid_device, simulate_connection, check_compliance — with a main loop, exception handling, and JSON reporting into one complete, runnable tool.
- Every device gets exactly one categorized result, whether it was compliant, non-compliant, or unreachable — the report and the terminal summary both reflect that honestly.
- You can trace any device's final status back through the exact function calls that produced it — nothing in this script is a black box.
- simulate_connection() is the one piece designed to be replaced — everything downstream of it (validation, reporting) doesn't change when a real device enters the picture.
- This is a complete, working automation tool, built and fully understood before touching any real network hardware.