NetBox / Source of Truth
NetBox as Nornir's Inventory Source
What you'll learn
- That nornir_netbox is a real, installable Nornir inventory plugin -- verified, not assumed
- A genuine discovery: its older class is deprecated; the current one is NetBoxInventory2
- A real, executed Nornir inventory built entirely from NetBox records
- How this connects directly back to Phase 3.5/3.6's driver-selection mechanism
Listen to a guided explanation of this lesson.
Spoken narration isn't supported in this browser.
A real plugin, verified before being trusted
Verified, not assumed to exist
Nornir's inventory system (Phase 3.4) is pluggable -- SimpleInventory (static YAML) is only the default. nornir_netbox is a real, separately-installed package providing a NetBox-backed inventory plugin. It was installed and inspected directly in this authoring environment before anything below was written.
pip install nornir_netbox
# Successfully installed nornir_netbox-0.3.0
# Requires: nornir (<4,>=3 -- compatible with the existing 3.6.0), requestsVerified directly: installs cleanly alongside the exact nornir 3.6.0 already used since Phase 3.4, with no version conflict.
A genuine discovery: one class is deprecated
Found by reading the real source, not the package name alone
nornir_netbox exports two inventory classes: NBInventory and NetBoxInventory2. Reading NBInventory's real source directly revealed a real, live DeprecationWarning inside its own init -- "netbox.NBInventory is deprecated, use netbox.NetBoxInventory2 instead." This lesson uses NetBoxInventory2 throughout, never the deprecated one.
class NBInventory:
def __init__(self, ...):
msg = "netbox.NBInventory is deprecated, use netbox.NetBoxInventory2 instead"
warnings.warn(msg, DeprecationWarning)
...Verified directly via inspect.getsource. This is exactly the kind of thing 'verify before authoring' catches that reading a package's name alone would miss.
A real, executed inventory build
def __init__(
self, nb_url=None, nb_token=None, ssl_verify=True,
flatten_custom_fields=False, filter_parameters=None,
include_vms=False, use_platform_slug=False,
use_platform_napalm_driver=False,
group_file="groups.yaml", defaults_file="defaults.yaml",
**kwargs,
) -> None: ...Verified via inspect.signature. group_file/defaults_file still read local YAML for shared settings/credentials -- NetBox supplies identity and platform; local files still handle credential injection exactly as Phase 3.4 taught.
from nornir import InitNornir
nr = InitNornir(
inventory={
"plugin": "NetBoxInventory2",
"options": {
"nb_url": "http://127.0.0.1:8002",
"nb_token": os.environ.get("NETBOX_TOKEN", "test-token"),
"use_platform_slug": True,
},
},
)
for name, host in nr.inventory.hosts.items():
print(name, "platform:", host.platform, "hostname:", host.hostname, "groups:", list(host.groups))No hosts.yaml anywhere -- nb_url points at this module's local mock backend, standing in for a real NetBox instance.
SW1 platform: cisco_ios hostname: 10.10.10.1 groups: [Group: site__hq, Group: platform__cisco_ios, Group: device_role__switch, Group: manufacturer__cisco, Group: device_type__catalyst-3850]
SW2 platform: arista_eos hostname: 10.10.10.2 groups: [Group: site__hq, Group: platform__arista_eos, Group: device_role__switch, Group: manufacturer__arista, Group: device_type__vEOS]
SW3 platform: cisco_ios hostname: 10.10.10.3 groups: [Group: site__branch1, Group: platform__cisco_ios, Group: device_role__switch, Group: manufacturer__cisco, Group: device_type__catalyst-3850]Real, verified output. hostname came from each device's primary_ip; groups were auto-derived from site/platform/device_role/manufacturer/device_type -- none of this was written by hand anywhere.
The direct connection to Phase 3.5/3.6
This closes the loop, verified
use_platform_napalm_driver=True maps NetBox's platform.napalm_driver field directly onto host.platform -- resolving straight into the exact driver name get_network_driver() (Phase 3.5) and nornir_napalm's connection plugin (Phase 3.6) already expect. Verified directly, not assumed.
nr = InitNornir(
inventory={"plugin": "NetBoxInventory2", "options": {
"nb_url": "http://127.0.0.1:8003",
"nb_token": os.environ.get("NETBOX_TOKEN", "test-token"),
"use_platform_napalm_driver": True,
}},
)
for name, host in nr.inventory.hosts.items():
print(name, "napalm platform:", host.platform)Real, executed. use_platform_napalm_driver reads each device's platform record's own napalm_driver field (Lesson 2's platform records) instead of its slug or name.
SW1 napalm platform: ios
SW2 napalm platform: eos
SW3 napalm platform: iosReal, verified output. host.platform is now exactly 'ios'/'eos' -- ready to hand straight to nornir_napalm's Napalm.open(), which calls get_network_driver(host.platform) with zero adaptation needed (Phase 3.6, Lesson 2).
A real, honest caveat about currentness
nornir_netbox's real, verified functionality is not in question -- every example above genuinely executed. Its last release on PyPI was 2021-09-20 -- confirmed directly, not assumed. It still installs cleanly and works correctly against the current nornir 3.6.0, but it has not been updated in several years. Stated honestly rather than presented as actively maintained.
Key takeaways
- nornir_netbox is a real, verified, separately-installed Nornir inventory plugin -- installs cleanly alongside the existing nornir 3.6.0.
- A genuine discovery: NBInventory is deprecated in its own source (a live DeprecationWarning); NetBoxInventory2 is the current, correct class -- used exclusively in this lesson.
- A real, executed inventory build: hostname and groups were entirely derived from NetBox device records, verified directly, with zero hand-authored YAML.
- use_platform_napalm_driver=True resolves NetBox's platform.napalm_driver field directly into the exact format Phase 3.5/3.6's driver-selection mechanism expects -- verified, not assumed.
- Honest caveat: nornir_netbox's last release was 2021-09-20 -- functional and verified, but not actively maintained.