NetAuto Academy

Nornir for Network Engineers

Nornir's Inventory: hosts.yaml, groups.yaml, defaults.yaml

Advanced12 min read

What you'll learn

  • Nornir's three-file inventory schema: hosts, groups, defaults
  • How to translate the SW1-SW5 fleet into it
  • Why credentials belong in none of these three files
  • How custom data (like a site) attaches to a host
🎓 Teach This Lesson

Listen to a guided explanation of this lesson.

Spoken narration isn't supported in this browser.

Three files, one inventory

Nornir's default inventory (the SimpleInventory plugin) reads three YAML files: hosts.yaml (who exists), groups.yaml (shared settings by group), defaults.yaml (settings applying to everything).

inventory/hosts.yaml
SW1:
hostname: 10.10.10.1
groups:
  - ios_switches
data:
  site: HQ

SW2:
hostname: 10.10.10.2
groups:
  - ios_switches
data:
  site: HQ

SW3:
hostname: 10.10.10.3
groups:
  - ios_switches
data:
  site: HQ

SW4:
hostname: 10.10.10.4
groups:
  - ios_switches
data:
  site: Branch1

SW5:
hostname: 10.10.10.5
groups:
  - ios_switches
data:
  site: Branch1

The same SW1-SW5 fleet from every capstone since Phase 2.6 -- hostname is the management IP; groups assigns each host to ios_switches; data.site is custom data, reusing the HQ/Branch1 site grouping from Network Controllers.

inventory/groups.yaml
ios_switches:
platform: cisco_ios

A group holds settings shared by every host that lists it -- here, just the platform, the same cisco_ios string Netmiko has used since Phase 2.7.

Quick checkConcept check
What does the groups.yaml file do that hosts.yaml alone couldn't?

Credentials belong in none of these three files

The tempting-but-wrong pattern

It's common to see defaults.yaml carrying username: admin / password: something. Do not do this — a credential committed to any inventory file is exactly the same mistake as hardcoding it in source code, the rule this curriculum has held since Netmiko Fundamentals.

inventory/defaults.yaml — deliberately empty of credentials
---

Genuinely empty. Credentials are injected at runtime, next.

inject_credentials.py
import os
from nornir import InitNornir

nr = InitNornir(
  inventory={
      "plugin": "SimpleInventory",
      "options": {
          "host_file": "inventory/hosts.yaml",
          "group_file": "inventory/groups.yaml",
          "defaults_file": "inventory/defaults.yaml",
      },
  },
)

nr.inventory.defaults.username = os.environ["NORNIR_USERNAME"]
nr.inventory.defaults.password = os.environ["NORNIR_PASSWORD"]

Credentials come from environment variables, set at runtime, and are assigned onto the already-loaded inventory's defaults -- never written into a file on disk.

output — real, verified
SW1 username (before injection): None
SW1 password (before injection): None

SW1 username (after injection): labuser
SW1 password (after injection): labpass

Real, verified output. Before injection, every host's username/password is None — genuinely absent. After injection, the default cascades to every host that doesn't override it.

Quick checkScenario
A learner writes username: admin directly into defaults.yaml so they don't have to set an environment variable each time. What's wrong with this?
Quick checkPredict output
Given the verified confirm-credentials-not-on-disk check from this lesson, what does grep for 'labuser' or 'labpass' across hosts.yaml, groups.yaml, and defaults.yaml return?

Custom data: the site field

data: under a host is a free-form dict for anything the built-in schema doesn't cover — here, which site a switch belongs to.

reading a host's custom data
sw4 = nr.inventory.hosts["SW4"]
print(sw4.data["site"])
print(sw4["site"])  # a shorthand for the same thing

Real, verified output for both: 'Branch1'. Custom data becomes directly useful in Lesson 4, filtering hosts by exactly this field.

Quick checkIdentify the correct code
Which line correctly adds a custom 'rack' field to SW2's data in hosts.yaml?

Key takeaways

  • Nornir's SimpleInventory reads three files: hosts.yaml (who exists), groups.yaml (shared settings), defaults.yaml (settings for everything).
  • The same SW1-SW5 fleet translates directly — groups assign platform via ios_switches; data.site reuses the HQ/Branch1 grouping from Network Controllers.
  • Credentials belong in none of the three files — verified directly, injected at runtime from environment variables onto the loaded inventory's defaults.
  • Custom data (like site) is a free-form dict under data:, directly useful for filtering in Lesson 4.