Ansible’s inventory management system is one of the strongest features of the platform. The options for using different inventory sources make it quite extensible. Starting with a static inventory of ini or yaml files can be fine for a small deployment or proof-of-concept, but this only scales so far. To scale beyond that, you will likely need to use a dynamic inventory plugin or script. With all the plugins that are available today, it is often better to go with one designed to work with your dynamic inventory source, but keeping in mind, that plugins are limited in their capability as-is.
In the case of the NetBox inventory plugin, there are several options out of the box by which to group hosts using different data points already available within the application (docs here):
sites
site
tenants
tenant
racks
rack
rack_group
rack_role
tags
tag
device_roles
role
device_types
device_type
manufacturers
manufacturer
platforms
platform
region
cluster
cluster_type
cluster_group
is_virtual
services
These are great options for a lot of use cases, but what if there is a need to group hosts by something that is not supported natively? Well, any inventory plugin can be extended with the functionality of the Ansible constructed
builtin (docs here). Custom groupings can be created, using either the groups
(which is based on a boolean) or the keyed_groups
(which is based on naming groups using Jinja2 logic) parameters to dynamically assign hosts into groups… that probably does not mean much right now, but this will be demonstrated shortly by using the keyed_groups
option.
As a simple example, perhaps it is necessary to group on the network OS, which is stored in NetBox under the platform
key, but a different group name is needed. It is possible to use the keyed_groups
parameter to create groups with a custom prefix, network_os
in this example netbox_inventory.yml
file:
keyed_groups:
- key: platform
prefix: "network_os"
separator: "_"
With this configuration, since all the devices in this instance are Cisco IOS, they are in a single group, named network_os_ios
brandomando@brandomando:$ ansible-inventory -i netbox_inventory.yml --graph
@all:
|--@network_os_ios:
| |--LVO-RTR-01
| |--RVA-RTR-01
| |--LVO-SWI-01
| |--RVA-SWI-01
|--@ungrouped:
Here you can see that the result is equivalant to 'network_os' + '_' + platform
which dynamically created a group called network_os_ios
.
This functionality can be extended with any Python code by building a custom filter. Let’s see what that looks like.
One attribute of a device model that you may want to group on is device family, but that is not one of the natively available options, since this is not a field in NetBox. A simple filter can be used to map the device_type
to a device family
, which can then be used to dynamically assign hosts to their associated family group.
class FilterModule(object):
def filters(self):
return {
'devicetype_family': self.devicetype_family
}
def devicetype_family(self, device_type):
devicetype_map = {
'ISR1921': 'isr1k',
'ISR1941': 'isr1k',
'ISR4321': 'isr4k',
'ISR4331': 'isr4k',
'ws-c3560cx-12pc-s': 'cat3k',
'ws-c3650-24ps': 'cat3k',
}
return devicetype_map[device_type]
In the NetBox nb_inventory
plugin configuration file, we can use the keyed_groups
functionality, in combination with the custom filter, to create a dynamic inventory group assignment.
keyed_groups:
- key: device_type | devicetype_family
prefix: "family"
separator: "_"
By running the keyed_groups
key through the devicetype_family
filter, the Ansible dynamic inventory will now have custom groups that are dynamically assigned based on the device_type
parameter returned by NetBox
brandomando@brandomando:$ ansible-inventory -i netbox_inventory.yml --graph
@all:
|--@family_cat3k:
| |--LVO-SWI-01
| |--RVA-SWI-01
|--@family_isr1k:
| |--LVO-RTR-01
|--@family_isr4k:
| |--RVA-RTR-01
|--@role_rtr:
| |--LVO-RTR-01
| |--RVA-RTR-01
|--@role_swi:
| |--LVO-SWI-01
| |--RVA-SWI-01
|--@site_lvo:
| |--LVO-RTR-01
| |--LVO-SWI-01
|--@site_rva:
| |--RVA-RTR-01
| |--RVA-SWI-01
|--@ungrouped:
In addition to being able to group by custom logic, we can also use filters within the compose
section of the NetBox inventory plugin config file to set custom variables in our rendered inventory as well. Let’s use the same filter plugin in this example.
compose:
ansible_network_os: platform.slug
family: device_type.slug | devicetype_family
Looking at an ansible-inventory output for one of the hosts, we can see that ansible_network_os
is now dynamically assigned using the platform
parameter from NetBox, and the family
variable is now set by our filter.
brandomando@brandomando:$ ansible-inventory -i ./lib/netbox_inventory.yml --host LVO-RTR-01 -y
ansible_host: 10.100.0.5
ansible_network_os: ios <--- generated from "platform.slug"
custom_fields: {}
device_type: isr4331
family: isr4k <--- generated from "device_type.slug | devicetype_family"
is_virtual: false
manufacturer: cisco
platform: ios
primary_ip4: 10.100.0.5
regions:
- las-vegas-nv
- us-west
- united-states
- north-america
role: rtr
services: []
site: lvo
tags: []
These options are all features from the Ansible builtin constructed
inventory plugin, which the NetBox community netbox.netbox.nb_inventory
plugin extends.
Demonstrating all of the components together:
plugin: netbox.netbox.nb_inventory
api_endpoint: http://localhost:8000
validate_certs: True
config_context: False
group_by:
- device_roles
device_query_filters:
- has_primary_ip: 'true'
keyed_groups:
- key: platform
prefix: "network_os"
separator: "_"
- key: device_type | devicetype_family
prefix: "family"
separator: "_"
compose:
ansible_network_os: platform.slug
family: device_type.slug | devicetype_family
This functionality is great for both users of the plugin and the plugin writers. The plugin writer no longer has to consider every possible use case that a user might have. The user can leverage the extensibility that is provided by the Ansible plugin framework and can be used for any number of customized groupings or variable assignments within dynamic inventories.
-Brandon
Share details about yourself & someone from our team will reach out to you ASAP!