NetAuto Academy

Your First Network Automation

Validating Results and Building the Report

Beginner12 min read

What you'll learn

  • Why a successful connection doesn't automatically mean a device is compliant
  • How to turn raw NTP/VLAN state into a single, plain-language status
  • How to categorize every device's result, including ones that couldn't be reached
  • How to collect results into the shape this project's JSON report needs
  • How this stage fits between the simulated connection and the finished report
🎓 Teach This Lesson

Listen to a guided explanation of this lesson.

Spoken narration isn't supported in this browser.

Connected successfully still isn't the same as compliant

The last lesson's loop printed a clean line for SW2 — no exception, no error. It's tempting to read that as "SW2 passed." It didn't: simulate_connection() succeeding only means the (simulated) connection worked. SW2's actual state came back with ntp_synced: False. This is the exact distinction "Validation, Safety & Failure Handling" made two modules ago, now sitting directly in this project's own code.

Turning state into a status

check_compliance.py
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"

Two checks, nested: a device only counts as fully 'compliant' if it passes both. This is the same if/else you've used all module — just one level deeper, checking a second thing only once the first has already passed.

Reading it top to bottom: if NTP isn't synced, the device is "ntp non-compliant" — full stop, the VLAN check never even runs, because a device that isn't synced doesn't need a second reason to need attention. If NTP is synced, only then does the function look at VLAN compliance, returning "compliant" or "vlan non-compliant" accordingly.

Quick checkConcept check
Why does check_compliance() check ntp_synced first, and only check vlan_compliant if that passes?
Quick checkPredict output
A device's simulated state is {"ntp_synced": True, "vlan_compliant": False}. What does check_compliance(state) return?

Categorizing every result — including failures

A real report needs an entry for every device, not just the ones that connected successfully. This is where the try/except from the last lesson and this lesson's compliance check come together:

build_results.py
results = []

for device in valid_devices:
  try:
      state = simulate_connection(device)
  except ConnectionError:
      results.append({
          "hostname": device["hostname"],
          "ip": device["ip"],
          "status": "unreachable",
      })
      continue

  status = check_compliance(state)
  results.append({
      "hostname": device["hostname"],
      "ip": device["ip"],
      "status": status,
  })

Every device gets exactly one entry in results — 'unreachable' if the connection failed, or a real compliance status if it succeeded. Nothing is silently skipped, and nothing needs to succeed for the loop to keep going.

Quick checkScenario
After running the code above against this project's three devices, how many entries does results contain, and what's SW3's status?

Writing the report

The last step this lesson covers: saving results as JSON — exactly the pattern from "Working with JSON in Python":

write_report.py
import json

with open("compliance_report.json", "w") as f:
  json.dump(results, f, indent=4)

json.dump writes the whole results list out as a readable JSON file — a saved record, not just something printed once and gone.

Quick checkIdentify the correct code
Which line correctly writes the results list out to compliance_report.json as JSON?

Key takeaways

  • A successful (simulated) connection only means the device responded — its actual compliance still has to be checked separately.
  • check_compliance() turns raw NTP/VLAN state into one plain-language status, using a nested if/else that checks the second condition only if the first already passed.
  • Every device gets exactly one entry in the results list, whether it was compliant, non-compliant, or unreachable — nothing gets silently dropped.
  • json.dump(results, f, indent=4) saves the collected results as a real report file, not just terminal output that disappears.
  • This lesson's three pieces — compliance checking, result collection, and report writing — are the last building blocks before Lesson 5 assembles the complete project.