Project: a network inventory report (models, serials, versions)
In short: Knowing exactly what hardware and software you run is the base of patching, support contracts and audits. This project collects facts such as model, serial number and OS version from every device with NAPALM and writes them to CSV and HTML. It is read-only, quick to build and immediately useful.
Goal and what you will build
Ask most teams for a list of their switches with serial numbers and software versions and you will get an out-of-date spreadsheet. Accurate inventory matters: support renewals need serial numbers, security advisories need software versions, and frameworks such as the CIS Controls start with knowing your assets. In this project you will build a script that logs in to each device, gathers the same set of facts and writes a clean report.
You need Python 3, a handful of lab devices you are allowed to access, and a read-only account on each.
Design
NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support) provides the same function, get_facts(), across vendors such as Cisco IOS, IOS-XR, NX-OS, Juniper Junos and Arista EOS. It returns a dictionary with hostname, vendor, model, serial number, OS version and uptime, so you do not have to write a parser for each vendor’s show version.
| Field | Why it matters |
|---|---|
| hostname | Matches what engineers see in the CLI |
| vendor, model | Lifecycle and spare-parts planning |
| serial_number | Support contracts and warranty claims |
| os_version | Vulnerability and patch tracking |
| uptime | Long uptimes often mean missed patches |
Build it step by step
- Install the packages:
pip install napalm pyyaml jinja2. - Create
hosts.yamllisting each device’s name, IP address and NAPALM driver (for exampleios,eos,junos). - Create
approved_versions.yamlwith the minimum software version you accept for each platform. - Run the script, open the CSV in a spreadsheet and check one or two rows against the device CLI.
- Add the HTML output and schedule a weekly run.
#!/usr/bin/env python3
import csv, os, datetime
import yaml
from napalm import get_network_driver
FIELDS = ["name", "ip", "vendor", "model", "serial_number",
"os_version", "uptime_days", "status", "note"]
def collect(dev, minimum):
row = {"name": dev["name"], "ip": dev["host"]}
driver = get_network_driver(dev["driver"])
try:
with driver(dev["host"], os.environ["NET_USER"], os.environ["NET_PASS"],
timeout=30) as conn:
f = conn.get_facts()
row.update({k: f[k] for k in ("vendor", "model", "serial_number", "os_version")})
row["uptime_days"] = round(f["uptime"] / 86400, 1)
floor = minimum.get(dev["driver"])
row["status"] = "ok"
if floor and floor not in f["os_version"]:
row["note"] = f"check against approved {floor}"
except Exception as e:
row.update(status="unreachable", note=type(e).__name__)
return row
def main():
hosts = yaml.safe_load(open("hosts.yaml", encoding="utf-8"))
minimum = yaml.safe_load(open("approved_versions.yaml", encoding="utf-8"))
rows = [collect(d, minimum) for d in hosts]
out = f"inventory-{datetime.date.today()}.csv"
with open(out, "w", newline="", encoding="utf-8") as fh:
w = csv.DictWriter(fh, fieldnames=FIELDS)
w.writeheader()
w.writerows(rows)
print(f"Wrote {len(rows)} devices to {out}")
if __name__ == "__main__":
main()
Tip: version strings do not sort reliably as text (for example "17.9" vs "17.12"). For a proper comparison, split them into numbers or use the packaging.version module when the format allows.
For the HTML report, pass the rows to a small Jinja2 template that builds a table and highlights unreachable devices and version notes. Keep the HTML file on an internal share; it contains serial numbers and IP addresses that should not be public.
How to extend it
- Add stack members, modules and power supplies with
get_environment()or platform-specific commands. - Compare each run with the previous CSV and report new, missing and changed devices.
- Push the results into a source of truth such as NetBox through its REST API.
- Add a lookup table of vendor end-of-sale and end-of-support dates that you maintain from official notices.
- Speed it up with Nornir to run many devices in parallel.
Showing it in your portfolio
Publish the code with a sanitised sample report: replace serials with fake values such as LAB0001 and use documentation IP ranges. In the README, explain the business problem (contracts, patching, audits), why you chose NAPALM, and how the script handles unreachable devices. A before-and-after comparison, such as "manual spreadsheet updated twice a year" versus "accurate report every Monday", tells an employer you understand the value of automation.
Practice
Why use NAPALM get_facts() rather than parsing show version yourself?
Why might a very long uptime be a warning sign?
Why should the generated report not be published publicly?
Key takeaways
- An accurate inventory is the base of patching, support and audits.
- NAPALM get_facts() returns vendor, model, serial, OS version and uptime.
- Handle unreachable devices and record them in the report.
- Flag versions below your approved baseline for patching.
- Sanitise serials and IP addresses before sharing samples.
Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.