Exploring the Red Hat Ansible Certified Collection for NetBox Part Two
Earlier this year we announced NetBox Labs collaboration with Red Hat to support and certify the hugely popular NetBox Ansible Collection on RedHat Ansible Automation Platform. This blog post is the second in a four-part series that will take a deep dive into the collection and show how to get the most out of this Network Automation power-pairing.
In the first blog post we introduced the collection and showed you how to install it on your system. In this post we look at the first main use case of the collection – namely using NetBox as a Dynamic Inventory source for the Red Hat Ansible Automation Platform.
What Problem Does A Dynamic Inventory Source Solve?
One of the main building blocks of any Ansible solution for Network Automation, is the Inventory. Ansible automates tasks on managed nodes or “hosts” in your infrastructure, using a list or group of lists known as inventory, and as you start out on your automation journey this is normally maintained as a static file either in INI or YAML format. This inventory file defines the nodes to be automated along with groups so that automation playbooks can be run against multiple nodes at the same time. An example inventory file might look like this:
# hosts.ini
---
[network_devices]
# all hosts
router1 ansible_host=192.168.1.1
router2 ansible_host=192.168.1.2
switch1 ansible_host=192.168.1.3
switch2 ansible_host=192.168.1.4
[switches]
# Switch specific group
switch1
switch2
[junos]
# Junos specific group
router1
switch1
The inventory file is typically combined with Group and Host Variable files that allow you to define data for groups of devices or individual devices. This data can include the details of what OS the hosts are running or the credentials that are being used to connect to them. For example
# group_vars/network_devices.yml
---
ansible_network_os: ios
ansible_user: "{{ lookup('env', 'ANSIBLE_USER') }}"
ansible_password: "{{ lookup('env', 'ANSIBLE_PASSWORD') }}"
ansible_connection: network_cli
ansible_become: yes
ansible_become_method: enable
ansible_become_password: "{{ lookup('env', 'ANSIBLE_BECOME_PASSWORD') }}"
# host_vars/router1.yml
---
username: "{{ lookup('env', 'ANSIBLE_USER') }}"
password: "{{ lookup('env', 'ANSIBLE_PASSWORD') }}"
As your inventory expands, you may need more than a single file to organize your hosts and groups, and as you can imagine, maintaining these inventory files can become burdensome and prone to error. The danger then being that you do not know if you are automating against the intended devices and you may inadvertently cause a network outage by running a playbook against the wrong host.
This is where dynamic Inventory sources and more specifically the NetBox Dynamic Inventory Plugin for Ansible comes to the rescue. By using NetBox as the Network Source of Truth (NSoT) for your network infrastructure, you eliminate the need to maintain separate inventory files for your hosts – Ansible is able to build it’s inventory dynamically and directly from NetBox using the NetBox REST API.
This is really powerful and ensures that your Ansible inventory is always up to date and removes the risk of incorrect devices being targeted (or devices not being targeted when they should be) when Ansible automation playbooks are run. Network device and VM details are retrieved dynamically from NetBox and if you add/remove/update device details in NetBox the the inventory is automatically updated.
One point worth mentioning is that you can still use group_vars
and host_vars
alongside the dynamic inventory. The resulting solution architecture looks like this, with Ansible (either running standalone or as Ansible Automation Platform) generating it’s inventory dynamically from NetBox using the REST API:

So with your Ansible Inventory built dynamically from Network Intent data in NetBox, you can rest easy knowing that you will always be targeting the most accurate and up to date list of hosts with your automation playbooks. This also gives you a really solid foundation to be working from and allows you to scale your network automation efforts easily as your network infrastructure grows.
Setting Up A Dynamic Inventory Source
This article will focus on using Ansible via the command line, but you can just as easily set this up on the Ansible Automation Platform (AAP) if you have access to it. See part one of this series if you need instructions on how to install everything you need to get started.
Edit your ansible.cfg
file to tell Ansible to source the inventory from a file. In this example we are specifying that the inventory should be sourced from the file called netbox_inv.yml
(the file can be called anything you like):
# ansible.cfg
[defaults]
inventory = ./netbox_inv.yml
In this case we are simply going to group the hosts by the device_roles
and sites
as defined in the NetBox database, so my file netbox_inv.yml
looks like this:
# netbox_inv.yml
plugin: netbox.netbox.nb_inventory
validate_certs: False
group_by:
- device_roles
- sites
With these two files configured, we can now run some commands to verify what we have in our in inventory. To view a graph of the inventory retrieved from NetBox, you can run the ansible-inventory
command and use the -i
flag to specify the netbox_inv.yml
file as the source, followed by --graph
:
ansible-inventory -i netbox_inv.yml --graph
From the returned output we can see that our NetBox instance has returned the data expected grouped the devices by device_roles
and sites
:
@all:
|--@device_roles_access_switch:
| |--AUSYD01-SW-1
| |--NLAMS01-SW-1
| |--NLAMS01-SW-2
|--@device_roles_console_server:
| |--NLAMS01-CON-1
|--@device_roles_patch_panel:
| |--NLAMS01-PAN-1
|--@device_roles_pdu:
| |--NLAMS01-PDU-1
| |--NLAMS01-PDU-2
|--@device_roles_vsphere:
| |--NLAMS01-VSP-1
| |--NLAMS01-VSP-2
|--@device_roles_wan_router:
| |--NLAMS01-RTR-1
|--@device_roles_wireless_ap:
| |--NLAMS01-AP-1
| |--NLAMS01-AP-2
|--@sites_amsterdam:
| |--NLAMS01-AP-1
| |--NLAMS01-AP-2
| |--NLAMS01-CON-1
| |--NLAMS01-PAN-1
| |--NLAMS01-PDU-1
| |--NLAMS01-PDU-2
| |--NLAMS01-RTR-1
| |--NLAMS01-SQL-01
| |--NLAMS01-SW-1
| |--NLAMS01-SW-2
| |--NLAMS01-VSP-1
| |--NLAMS01-VSP-2
| |--NLAMS01-WIN-01
|--@sites_chicago:
|--@sites_london:
|--@sites_los_angeles:
|--@sites_singapore:
|--@sites_sydney:
| |--AUSYD01-SW-1
|--@ungrouped:
To list all the devices in the inventory, use the same command, but with the --list
suffix:
ansible-inventory -i netbox_inv.yml --list
The output below has been shortened to show the inventory data returned for a single device, and all of this can be used in further playbooks to automate operations against the target device:
"NLAMS01-SW-1": {
"ansible_host": "192.168.2.1",
"custom_fields": {},
"device_roles": [
"access-switch"
],
"device_types": [
"ex4300-48p"
],
"is_virtual": false,
"local_context_data": [
null
],
"locations": [
"comms-room"
],
"manufacturers": [
"juniper"
],
"platforms": [
"juniper-junos"
],
"primary_ip4": "192.168.2.1",
"rack_role": "infrastructure",
"racks": [
"NLAMS01-RK-01"
],
"regions": [
"netherlands",
"europe"
],
"serial": "",
"services": [],
"site_groups": [
"branch"
],
"sites": [
"amsterdam"
],
"status": {
"label": "Active",
"value": "active"
},
"tags": [],
"tenants": [
"consulting"
]
},
Running Playbooks Using the Dynamic Inventory Plugin
To run a playbook that uses the dynamic inventory, you simply specify the inventory file when you run the playbook, for example:
ansible-playbook -i netbox_inv.yml <PLAYBOOK NAME>
To target hosts or groups from the inventory in your playbook, reference the hosts or groups as normal in the playbook:
---
- name: Playbook using NetBox Inventory Plugin for Ansible
hosts: device_roles_access_switch
What Else Can I do With the Dynamic Inventory?
The inventory plugin is highly configurable in terms of filtering hosts and groupings etc, so I would highly recommend consulting the docs for more information, but here are a couple of examples to get you started:
Filter Hosts
Filtering is a very powerful feature of the inventory plugin, allowing you to be really granular in defining which hosts you are targeting with your playbooks. In this example we filter hosts to target only those with the role
of network-edge-router
, that also have a primary IP address assigned (this could also be used to filter out patch panels and other passive devices) and only those with a manufacturer ID of 1:
query_filters:
- role: network-edge-router
device_query_filters:
- has_primary_ip: 'true'
- manufacturer_id: 1
Set Host Variables
You can use the compose
option set host_vars
for your hosts, which could complement or replace your host_vars
files. For example:
compose:
foo: last_updated
bar: display_name
Learn More By Attending Our Webinar
That’s it for part two of this series, and hopefully you now have a feel for the power of the NetBox Inventory Plugin for Ansible. In part three we will explore the second use case of the Ansible Collection for NetBox – Defining the intended network state in NetBox. Don’t forget to check out the NetBox Learning Git Repo for all the code used in this blog series, as well as other great NetBox Learning resources.
If you want to learn more and see all three use cases in action then register for the upcoming Webinar: Exploring the Red Hat Ansible Certified Collection for NetBox on August 13, 2024 11:00 ET | 15:00 UTC | 17:00 CET.