NetAuto Academy

Your First Network Automation

Building the Inventory Layer

Beginner12 min read

What you'll learn

  • How to load the project's device inventory from a CSV file
  • Why inventory should be validated before anything downstream uses it
  • How to write a small validation function and use it to filter a device list
  • That inventory only holds static facts about a device — not its current state
  • How this stage fits into the overall project, before any connection is attempted
🎓 Teach This Lesson

Listen to a guided explanation of this lesson.

Spoken narration isn't supported in this browser.

The first real stage

Every stage in this project's plan needs the device list before it can do anything — so that's where the actual building starts. This lesson is entirely about getting a trustworthy inventory into the script; nothing here connects to a device, real or simulated. That's deliberate: get the input right first, and every later stage can just trust it.

Loading the inventory

The project's inventory is a CSV file — exactly the shape from "Reading and Writing CSV Inventory Files":

devices.csv
hostname,ip,platform
SW1,10.10.10.1,cisco_ios
SW2,10.10.10.2,cisco_ios
SW3,10.10.10.3,cisco_ios

Hostname, management IP, and platform — the static facts about each device, and nothing about its current state. That distinction matters, and this lesson comes back to it.

load_inventory.py
import csv

with open("devices.csv") as f:
  devices = list(csv.DictReader(f))

for device in devices:
  print(device["hostname"], device["ip"], device["platform"])

csv.DictReader turns the file into a list of dictionaries in one line — exactly the pattern from the Networking Data & Formats module, now the actual starting point of a real project.

Quick checkConcept check
After 'devices = list(csv.DictReader(f))', what does devices contain?

Why validate before using it

A CSV file is just text — nothing stops a row from being incomplete (a blank IP, a missing hostname from a copy-paste mistake) before it ever reaches the rest of the script. Left unchecked, a bad record doesn't fail loudly and immediately; it fails somewhere later, in a way that's much harder to trace back to "the inventory had a typo in row 2."

This is the source-of-truth idea, in code

"Devices, Inventory & Source of Truth" argued that automation is only as reliable as the inventory it trusts. Validating a device record before using it is that idea, made concrete: catch a bad record here, with a clear message, instead of letting it cause a confusing failure three stages downstream.

validate.py
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"))

device.get("hostname") returns an empty string if the field is blank; bool("") is False, bool("SW1") is True — so this function returns True only when both fields actually have something in them.

Quick checkIdentify the correct code
Which line correctly checks whether a device dictionary has a non-empty 'hostname' value?

Filtering the list

With the check written, the next step is using it to separate good records from bad ones — a plain loop, exactly like every other filtering step this curriculum has used:

filter_inventory.py
valid_devices = []

for device in devices:
  if is_valid_device(device):
      valid_devices.append(device)
  else:
      print(f"Skipping invalid inventory record: {device}")

Every device is checked once. A valid one gets added to valid_devices; an invalid one gets a clear, immediate message instead of silently being included — or silently being dropped without anyone noticing.

Quick checkScenario
devices.csv has three rows, but the second one has a blank IP address. What does the filtering code above do?

Inventory vs. state, one more time

Notice what devices.csv does not contain: no reachability, no NTP status, no VLAN information. That's not an oversight — inventory is the static facts about a device (who it is, where it is), while reachability and compliance are state: facts that can only be discovered by actually checking, right now. "Configuration vs State" made exactly this distinction two modules ago; this project keeps it just as clean in real code, and the next lesson is entirely about the stage that discovers state.

Quick checkMyth check
Should reachability and NTP status be included as columns in devices.csv, alongside hostname, ip, and platform?

Key takeaways

  • The inventory layer loads devices.csv into the same list-of-dictionaries shape used throughout this curriculum, using csv.DictReader.
  • A device record should be validated before anything downstream uses it — catching a bad record here means a clear message now, not a confusing failure later.
  • is_valid_device(device) combined with a plain filtering loop separates usable records from broken ones, without silently dropping or silently accepting either.
  • Inventory holds static facts (hostname, IP, platform); reachability and compliance are state, discovered by connecting — which is exactly what the next lesson builds.
  • Getting this stage right first means every later stage in the project can simply trust the device list it's handed.