By default, Ansible relies on static inventory files (hosts.ini or hosts.yaml). In a dynamic, modern network environment, managing these text files manually becomes an operational nightmare.

To bridge this gap, we can tie Ansible’s execution directly to NetBox, using it as our single source of truth. Before we configure the plugin, your local control machine needs the official NetBox collection along with its underlying Python API wrapper and timezone dependencies:

# Install the official NetBox Ansible collection
ansible-galaxy collection install netbox.netbox

# Install pynetbox and pytz for timezone parsing
pip install pynetbox pytz

⚠️ Note on Python Environments: If you are using a Python virtual environment (venv) for your automation labs, ensure you activate it before running the pip command so Ansible can resolve the dependency.

The Big Picture: How Dynamic Discovery Works

Rather than reading a static list of IP addresses from your local hard drive, our updated pipeline shifts the data gathering process entirely to an on-demand API loop.

Here is exactly how Ansible communicates with NetBox to find your target routers before executing a playbook:

graph TB subgraph Control [Control Machine] A[Ansible Engine] -->|1. Triggers| B(netbox_inv.yml / auto plugin) end subgraph SOT [NetBox Environment] B -->|2. HTTP API Handshake| C[NetBox API Engine] C -->|3. Database Query| D[(PostgreSQL Database)] D -->|4. Node Metadata JSON| C end subgraph Infra [Lab Infrastructure] E[PE1 Nokia SR OS Node] end %% Flowing back out of NetBox to Ansible, then to the Node C -->|5. Dynamic Host Mapping| B A -->|6. Configuration Deployment via network_cli / NETCONF | E %% Styling style A fill:#1A1A1A,stroke:#EE2C34,stroke-width:2px,color:#fff style B fill:#333,stroke:#fff,stroke-width:1px,color:#fff style C fill:#0f172a,stroke:#2563eb,stroke-width:2px,color:#fff style D fill:#1e293b,stroke:#38bdf8,stroke-width:1px,color:#fff style E fill:#022c22,stroke:#10b981,stroke-width:2px,color:#fff

With the conceptual framework clear, let’s build the configuration file that initiates this handshake.

1. Defining the NetBox Dynamic Inventory

Instead of managing a static hosts.ini or hosts.yaml file, we use the netbox.netbox.nb_inventory plugin and create a YAML file that defines the connection.

Create a file named netbox_inv.yml:

---
plugin: netbox.netbox.nb_inventory

# Point directly to your NetBox instance 
api_endpoint: http://127.0.0.1:8000
validate_certs: false

# Your secure API token (Admin > Authentication > API Tokens)
token: "your_generated_netbox_api_token_here"

# Automatically group devices based on NetBox metadata
group_by:
  - device_roles
  - sites
  - platforms

# Map NetBox data models directly to native Ansible variables
compose:
  ansible_host: primary_ip4.address.ip
  ansible_network_os: platform.slug
  ansible_user: "'admin'"
  ansible_ssh_pass: "'NokiaSros1!'"
  ansible_connection: "'network_cli'"

💡 Pro-Tip: Copy your NetBox API token immediately upon creation in the GUI. For security, NetBox only displays the full plain-text string once!

Before executing code against your inventory, you can use native Ansible CLI tools to verify that the dynamic plugin is successfully parsing your database.

Run the following command to print a visual graph of your infrastructure:

ansible-inventory -i netbox_inv.yml --graph

Expected Output:

Ansible automatically queries the API and builds structured groups based on your layout:

@all:
  |--@ungrouped:
  |--@sites_lab-home:
  |  |--PE1
  |--@device_roles_edge-router:
  |  |--PE1
  |--@platforms_nokia_sros:
  |  |--PE1

To see the exact variables passed down from NetBox for a single device, inspect a specific host:

ansible-inventory -i netbox_inv.yml --host PE1

3. Running Your First Automated Task

Because Ansible translates NetBox device roles into executable host groups (@device_roles_edge_router), you can now run ad-hoc commands against whole classes of devices without maintaining text files.

# Ping all active devices found in NetBox
ansible all -i netbox_inv.yml -m ansible.netcommon.net_ping

# Target only edge routers
ansible device_roles_edge_router -i netbox_inv.yml -m ansible.netcommon.net_ping

💡 Pro-Tip on Naming Conventions: Notice that NetBox outputs the group name with a hyphen (device_roles_edge-router), but our command targets it with an underscore (device_roles_edge_router). Ansible automatically converts hyphens to underscores under the hood to ensure group names remain compliant with its internal variable syntax rules.

4. Executing a Nokia SR OS Fact-Gathering Playbook

With the dynamic inventory feeding accurate connection parameters (ansible_host and ansible_network_os) straight to Ansible, you can run structured automation tasks.

Create a playbook named nokia_info.yml:

---
- name: Get Facts from Nokia SR OS
  hosts: device_roles_edge_router
  connection: network_cli
  gather_facts: false
  
  tasks:
    - name: Show System Version
      nokia.sros.sros_command:
        commands: show version
      register: version_output

    - name: Print Version Details
      debug:
        var: version_output.stdout_lines

Execute it locally using standard execution commands:

ansible-playbook -i netbox_inv.yml nokia_info.yml

Conclusion & Next Steps

This architecture shifts your operational workflow completely:

  1. Model: You provision a new node inside your NetBox single source of truth dashboard.
  2. Execute: You run your playbooks seamlessly via the local standard CLI.
  3. Automate: Ansible fetches the real-time target data from the API, constructs the inventory graph on the fly, and applies code variations safely.

Now that our data model speaks directly to our automation engine, we are ready to take this architecture to the next step. In Part 3, we are shifting to Infrastructure-as-Code (IaC).

We will introduce Containerlab — a lightweight, containerized orchestration engine that will allow us to define our entire multi-node router topology as a simple YAML file. Instead of spinning up resource-heavy VMs, you will learn how to launch, tear down, and version-control a lab environment in seconds. Stay tuned!