How to Use Red Hat Ansible Automation Platform to Query and Return Data from NetBox

Exploring the Red Hat Ansible Certified Collection for NetBox Part Four

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 last in a four-part series that takes a deep dive into the collection and shows how to get the most out of this Network Automation power-pairing.

In part one we introduced the collection and showed you how to install it on your system, and in part two we explored the first use case for the collection, that of using NetBox as a Dynamic Inventory source for Ansible. In part three we looked how to define Intended network state in NetBox, and in this post we look at the third use case for the collection – namely using Ansible to query and return data from NetBox.

Introducing the NetBox Lookup Plugin

The use case we are exploring here, makes use of a Plugin for the NetBox Ansible Collection, called netbox.netbox.nb_lookup, and this allows Ansible to query NetBox via its API to return virtually any information capable of being held in NetBox. Once again the documentation is your friend here, and is worth exploring to help you with developing your own playbooks.

As a simple example, the following playbook will query NetBox and return a list of all devices whose role is that of firewall and then report the manufacturer of each device. Note how the query uses the api_filter argument to define the role we are interested in:

---
- name: Lookup NetBox Device Data Based on Role
  hosts: localhost
  gather_facts: no

  vars:
    netbox_url: "{{ lookup('ansible.builtin.env', 'NETBOX_API') }}"
    netbox_token: "{{ lookup('ansible.builtin.env', 'NETBOX_TOKEN') }}"

  tasks:

  - name: "Query NetBox for all sites"
    debug:
      msg: >
        "Device {{ item.value.name }} (ID: {{ item.key }}) was
        manufactured by {{ item.value.device_type.manufacturer.name }}"
    loop: "{{ query('netbox.netbox.nb_lookup', 'devices', api_filter='role=firewall', api_endpoint=netbox_url, token=netbox_token)}}"

So when this playbook runs it loops over all devices with a role of firewall and returns the following output. Notice the Ansible debug message generated to report the device hostname, ID and manufacturer:

PLAY [Lookup NetBox Device Data] ***********************************************************************************************************************************************************************************************************************************************************************************

TASK [Query NetBox for all sites] **********************************************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => (item={'key': 39, 'value': {'id': 39, 'url': 'https://kebab.cloud.netboxapp.com/api/dcim/devices/39/', 'display': 'srx1', 'name': 'srx1', 'device_type': {'id': 36, 'url': 'https://kebab.cloud.netboxapp.com/api/dcim/device-types/36/', 'display': 'SRX320', 'manufacturer': {'id': 35, 'url': 'https://kebab.cloud.netboxapp.com/api/dcim/manufacturers/35/', 'display': 'Juniper', 'name': 'Juniper', 'slug': 'juniper'}, 'model': 'SRX320', 'slug': 'juniper-srx320'}, 'role': {'id': 36, 'url': 'https://kebab.cloud.netboxapp.com/api/dcim/device-roles/36/', 'display': 'Firewall', 'name': 'Firewall', 'slug': 'firewall'}, 'device_role': {'id': 36, 'url': 'https://kebab.cloud.netboxapp.com/api/dcim/device-roles/36/', 'display': 'Firewall', 'name': 'Firewall', 'slug': 'firewall'}, 'tenant': None, 'platform': {'id': 36, 'url': 'https://kebab.cloud.netboxapp.com/api/dcim/platforms/36/', 'display': 'junos', 'name': 'junos', 'slug': 'junos'}, 'serial': 'CW4919AF1116', 'asset_tag': None, 'site': {'id': 35, 'url': 'https://kebab.cloud.netboxapp.com/api/dcim/sites/35/', 'display': 'Home Lab', 'name': 'Home Lab', 'slug': 'home'}, 'location': None, 'rack': None, 'position': None, 'face': None, 'latitude': None, 'longitude': None, 'parent_device': None, 'status': {'value': 'active', 'label': 'Active'}, 'airflow': {'value': 'front-to-rear', 'label': 'Front to rear'}, 'primary_ip': {'id': 39, 'url': 'https://kebab.cloud.netboxapp.com/api/ipam/ip-addresses/39/', 'display': '192.168.1.220/24', 'family': 4, 'address': '192.168.1.220/24'}, 'primary_ip4': {'id': 39, 'url': 'https://kebab.cloud.netboxapp.com/api/ipam/ip-addresses/39/', 'display': '192.168.1.220/24', 'family': 4, 'address': '192.168.1.220/24'}, 'primary_ip6': None, 'oob_ip': None, 'cluster': None, 'virtual_chassis': None, 'vc_position': None, 'vc_priority': None, 'description': '', 'comments': '', 'config_template': None, 'config_context': {}, 'local_context_data': None, 'tags': [], 'custom_fields': {'ccc_device_id': None, 'cisco_catalyst_center': None}, 'created': '2024-03-15T16:48:14.658462Z', 'last_updated': '2024-03-15T18:32:50.667193Z', 'console_port_count': 1, 'console_server_port_count': 0, 'power_port_count': 1, 'power_outlet_count': 0, 'interface_count': 8, 'front_port_count': 0, 'rear_port_count': 0, 'device_bay_count': 0, 'module_bay_count': 0, 'inventory_item_count': 0}}) => 
  msg: |-
    "Device srx1 (ID: 39) was manufactured by Juniper"

PLAY RECAP *********************************************************************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Going Further – Looking Up Site and Device Data

Taking things a step further, in the example playbook lookup_site_and_device_data.yml we first of all query the NetBox sites API endpoint and then print a list of all the sites. Then we query the devices API endpoint, filter on the site cisco-devnet and print a list of the devices at that site. This playbook makes also makes use of the community.general.json_query filter filter plugin for Ansible, that lets you query a complex JSON structure and iterate over it using a loop:

# lookup_site_and_device_data.yml
---
- name: Lookup NetBox Site and Device Data
  hosts: localhost
  gather_facts: no

  vars:
    netbox_url: "{{ lookup('ansible.builtin.env', 'NETBOX_API') }}"
    netbox_token: "{{ lookup('ansible.builtin.env', 'NETBOX_TOKEN') }}"

  tasks:

  - name: "Query NetBox for all sites"
    set_fact:
      sites: "{{ query('netbox.netbox.nb_lookup', 'sites', api_endpoint=netbox_url, token=netbox_token) }}"

  - name: "Print the list of sites"
    debug:
      msg: "{{ sites | json_query('[*].value.name') }}"

  - name: "Query NetBox for devices at the Cisco DevNet Site"
    set_fact:
      devices: "{{ query('netbox.netbox.nb_lookup', 'devices', api_filter='site=cisco-devnet', api_endpoint=netbox_url, token=netbox_token) }}"

  - name: "Print a list of devices at Cisco DevNet Site"
    debug:
      msg: "{{ devices | json_query('[*].value.name') }}"

The playbook run results in the following output that first of all lists the sites from NetBox and then lists the devices at the cisco-devnet site:

ansible-playbook lookup_site_and_device_data.yml
PLAY [Lookup NetBox Site and Device Data] *********************************************************************************************************************

TASK [Query NetBox for all sites] *****************************************************************************************************************************
ok: [localhost]

TASK [Print the list of sites] ********************************************************************************************************************************
ok: [localhost] =>
  msg:
  - Cisco DevNet
  - Meraki Sandbox

TASK [Query NetBox for devices at the Cisco DevNet Site] ******************************************************************************************************
ok: [localhost]

TASK [Print a list of devices at Cisco DevNet Site] ***********************************************************************************************************
ok: [localhost] =>
  msg:
  - sw1
  - sw2
  - sw3
  - sw4

PLAY RECAP ****************************************************************************************************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

So, that’s how easy it is to use the Ansible collection for NetBox to query NetBox via its API to return virtually any information capable of being held in NetBox. The Git Repository that accompanies this blog series has the example playbooks that you can use as a starting point to develop your own playbooks to query and return data from NetBox. The possibilities are endless really, from generating simple reports to extracting configuration data to be used in other Ansible playbooks that deploy changes out to the network devices. Dive in and get started!

Learn more at our Ansible Collection for NetBox webinar

So that just about wraps up this blog series. I hope you have enjoyed reading it as much as I enjoyed writing it, and if you have got this far then thanks for reading! Hopefully you now have a good understanding of how Ansible and NetBox work together seamlessly when you make use of the Red Hat Certified Ansible Collection for 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.

Share the Post:

Related Posts