Lab 04 - Getting Inventory Data Dynamically from Nautobot¶
This lab is focused on how to dynamically import inventory data from Nautobot to Nornir using the nornir-nautobot plugin. The previous labs focused on building a static inventory file.
Nornir is a pluggable system and only basic modules come preinstalled with it. Any other module needs to be installed before they can be used. This link shows what module plugins are currently available and can be installed.
The list below shows what modules are installed in the lab environment.
ntc@ntc-training:nornir$ pip list | grep nornir
nornir 3.3.0
nornir-jinja2 0.2.0
nornir-napalm 0.4.0
nornir-nautobot 2.4.0
nornir-netmiko 0.2.0
nornir-utils 0.2.0
Task 1 - Dynamically Create Inventory Data from Nautobot¶
In this task you will use the nornir-nautobot plugin to make an API call to gather all the devices from Nautobot. That data will be used as inventory input for Nornir to consume and use as devices to target for automation tasks.
Step 1¶
Make sure you're in the /home/ntc/nornir folder and create a file named nr_nautobot.py.
Step 2¶
Add the following code to the nr_nautobot.py file:
Step 3¶
In the nr_nautobot.py file, create the variables that will store the Nautobot server IP, API token, and URL needed for the API requests.
NAUTOBOT_TOKEN = "YOUR_INSTRUCTOR_WILL_PROVIDE_THIS"
NAUTOBOT_BASE_URL = "YOUR_INSTRUCTOR_WILL_PROVIDE_THIS"
Step 4¶
Build the nr variable to instantiate Nornir and import the inventory data from Nautobot.
nr = InitNornir(
inventory={
"plugin":"NautobotInventory",
"options": {
"nautobot_url": NAUTOBOT_BASE_URL,
"nautobot_token": NAUTOBOT_TOKEN,
"filter_parameters": {
"site": "ams01"
}
}
}
)
The full nr_nautobot.py file should look as follows:
from nornir import InitNornir
from rich import print
NAUTOBOT_TOKEN = "YOUR_INSTRUCTOR_WILL_PROVIDE_THIS"
NAUTOBOT_BASE_URL = "YOUR_INSTRUCTOR_WILL_PROVIDE_THIS"
nr = InitNornir(
inventory={
"plugin":"NautobotInventory",
"options": {
"nautobot_url": NAUTOBOT_BASE_URL,
"nautobot_token": NAUTOBOT_TOKEN,
"filter_parameters": {
"site": "ams01"
}
}
}
)
Step 5¶
To access the imported data from Nautobot with Nornir use the print function to view the data stored in nr.inventory.dict(). First, execute the nr_nautobot.py file in an interactive Python shell (notice the -i parameter).
This might be a LOT of data, be warned! If you scroll back and inspect what's returned, you'll notice the plugin provides you with a lot of device data and groups based on information solely in the Nautobot instance.
ntc@ntc-training:nornir$ python -i nr_nautobot.py
>>>
>>> print(nr.inventory.dict())
{
'hosts': {
'ams01-dist-01': {
'name': 'ams01-dist-01',
'connection_options': {},
'groups': [],
'data': {
'pynautobot_object': <pynautobot.models.dcim.Devices ('ams01-dist-01') at 0x7f3f32eec610>,
'pynautobot_dictionary': {
'id': '4d7aecac-addd-4f3c-8efc-e102872b54e5',
'display': 'ams01-dist-01',
'url': 'https://demo.nautobot.com/api/dcim/devices/4d7aecac-addd-4f3c-8efc-e102872b54e5/',
'name': 'ams01-dist-01',
'device_type': {
'display': 'Cisco Catalyst 6509-E',
'id': '09dbb4e4-b258-4614-a85a-125f5c5caa9e',
'url': 'https://demo.nautobot.com/api/dcim/device-types/09dbb4e4-b258-4614-a85a-125f5c5caa9e/',
'manufacturer': {
'display': 'Cisco',
'id': 'a73797b5-a812-4dc8-bffc-bde09b6a5dba',
'url': 'https://demo.nautobot.com/api/dcim/manufacturers/a73797b5-a812-4dc8-bffc-bde09b6a5dba/',
'name': 'Cisco',
'slug': 'cisco'
},
'model': 'Catalyst 6509-E',
'slug': 'catalyst-6509-e'
},
'device_role': {
'display': 'distribution',
'id': '8acdfbc3-c3ae-4b52-b8a3-f8766edce039',
'url': 'https://demo.nautobot.com/api/dcim/device-roles/8acdfbc3-c3ae-4b52-b8a3-f8766edce039/',
'name': 'distribution',
'slug': 'distribution'
},
'tenant': {
'display': 'Nautobot Airports',
'id': '6283d31e-8c08-4fb7-94ad-e34b4694d845',
'url': 'https://demo.nautobot.com/api/tenancy/tenants/6283d31e-8c08-4fb7-94ad-e34b4694d845/',
'name': 'Nautobot Airports',
'slug': 'nautobot-airports'
},
'platform': {
'display': 'Cisco IOS',
'id': 'df107d2a-b84f-4a30-9e48-093e9ad9a550',
'url': 'https://demo.nautobot.com/api/dcim/platforms/df107d2a-b84f-4a30-9e48-093e9ad9a550/',
'name': 'Cisco IOS',
'slug': 'cisco_ios'
},
'serial': '',
'asset_tag': None,
'site': {
'display': 'AMS01',
'id': '42568d63-0f8c-453f-8d13-1355f677af4e',
'url': 'https://demo.nautobot.com/api/dcim/sites/42568d63-0f8c-453f-8d13-1355f677af4e/',
'name': 'AMS01',
'slug': 'ams01'
},
'location': None,
'rack': None,
'position': None,
'face': None,
'parent_device': None,
'status': {'value': 'active', 'label': 'Active'},
'primary_ip': None,
'primary_ip4': None,
'primary_ip6': None,
'secrets_group': None,
'cluster': None,
'virtual_chassis': None,
'vc_position': None,
'vc_priority': None,
'device_redundancy_group': None,
'device_redundancy_group_priority': None,
'comments': '',
'local_context_schema': None,
'local_context_data': None,
'config_context': {
'cdp': True,
'ntp': [{'ip': '10.1.1.1', 'prefer': False}, {'ip': '10.2.2.2', 'prefer': True}],
'lldp': True,
'snmp': {
'host': [{'ip': '10.1.1.1', 'version': '2c', 'community': 'networktocode'}],
'contact': 'John Smith',
'location': 'Network to Code - NYC | NY',
'community': [
{'name': 'ntc-public', 'role': 'RO'},
{'name': 'ntc-private', 'role': 'RW'},
{'name': 'networktocode', 'role': 'RO'},
{'name': 'secure', 'role': 'RW'}
]
},
'aaa-new-model': False,
'acl': {'definitions': {'named': {'PERMIT_ROUTES': ['10 permit ip any any']}}},
'route-maps': {
'PERMIT_CONN_ROUTES': {'seq': 10, 'type': 'permit', 'statements': ['match ip address PERMIT_ROUTES']}
}
},
'created': '2022-11-09',
'last_updated': '2022-11-09T15:13:29.658288Z',
'tags': [],
'notes_url': 'https://demo.nautobot.com/api/dcim/devices/4d7aecac-addd-4f3c-8efc-e102872b54e5/notes/',
'custom_fields': {}
}
},
'hostname': 'ams01-dist-01',
'port': None,
'username': None,
'password': None,
'platform': 'cisco_ios'
},
'ams01-edge-01': {
'name': 'ams01-edge-01',
...OMITTED...
Step 6¶
View all the available hosts from the nr.inventory.hosts object.
>>> print(nr.inventory.hosts)
{
'ams01-dist-01': Host: ams01-dist-01,
'ams01-edge-01': Host: ams01-edge-01,
'ams01-edge-02': Host: ams01-edge-02,
'ams01-leaf-01': Host: ams01-leaf-01,
'ams01-leaf-02': Host: ams01-leaf-02,
'ams01-leaf-03': Host: ams01-leaf-03,
'ams01-leaf-04': Host: ams01-leaf-04,
'ams01-leaf-05': Host: ams01-leaf-05,
'ams01-leaf-06': Host: ams01-leaf-06,
'ams01-leaf-07': Host: ams01-leaf-07,
'ams01-leaf-08': Host: ams01-leaf-08
}
Step 7¶
Filter devices based on the platform (you can also try arista_eos):
Step 8¶
View user data fetched from Nautobot for ams01-leaf-04:
>>> ams_leaf = nr.inventory.hosts["ams01-leaf-04"]
>>> ams_leaf
Host: ams01-leaf-04
>>> print(ams_leaf.dict())
{
'name': 'ams01-leaf-04',
'connection_options': {},
'groups': [],
'data': {
'pynautobot_object': <pynautobot.models.dcim.Devices ('ams01-leaf-04') at 0x7f3f2deedbb0>,
'pynautobot_dictionary': {
'id': 'd2ebc009-5904-4ce3-acc1-2602264144e9',
'display': 'ams01-leaf-04',
'url': 'https://demo.nautobot.com/api/dcim/devices/d2ebc009-5904-4ce3-acc1-2602264144e9/',
'name': 'ams01-leaf-04',
'device_type': {
'display': 'Arista DCS-7150S-24',
'id': '2c1a0e26-2db9-4778-b546-efe089007a27',
'url': 'https://demo.nautobot.com/api/dcim/device-types/2c1a0e26-2db9-4778-b546-efe089007a27/',
'manufacturer': {
'display': 'Arista',
'id': '3386c2ce-0fd8-441c-99ec-89f756dbcb36',
'url': 'https://demo.nautobot.com/api/dcim/manufacturers/3386c2ce-0fd8-441c-99ec-89f756dbcb36/',
'name': 'Arista',
'slug': 'arista'
},
'model': 'DCS-7150S-24',
'slug': 'dcs-7150s-24'
},
'device_role': {
'display': 'leaf',
'id': 'd6a7e464-ab79-48b8-8d7e-e459dbeef2e3',
'url': 'https://demo.nautobot.com/api/dcim/device-roles/d6a7e464-ab79-48b8-8d7e-e459dbeef2e3/',
'name': 'leaf',
'slug': 'leaf'
},
'tenant': {
'display': 'Nautobot Airports',
'id': '6283d31e-8c08-4fb7-94ad-e34b4694d845',
'url': 'https://demo.nautobot.com/api/tenancy/tenants/6283d31e-8c08-4fb7-94ad-e34b4694d845/',
'name': 'Nautobot Airports',
'slug': 'nautobot-airports'
},
'platform': {
'display': 'Arista EOS',
'id': 'fe42bcca-ca6d-45f2-85b5-76949baeb325',
'url': 'https://demo.nautobot.com/api/dcim/platforms/fe42bcca-ca6d-45f2-85b5-76949baeb325/',
'name': 'Arista EOS',
'slug': 'arista_eos'
},
'serial': '',
'asset_tag': None,
'site': {
'display': 'AMS01',
'id': '42568d63-0f8c-453f-8d13-1355f677af4e',
'url': 'https://demo.nautobot.com/api/dcim/sites/42568d63-0f8c-453f-8d13-1355f677af4e/',
'name': 'AMS01',
'slug': 'ams01'
},
'location': None,
'rack': {
'display': 'ams01-104',
'id': 'c2f725ba-1463-45af-a88e-c74f751de424',
'url': 'https://demo.nautobot.com/api/dcim/racks/c2f725ba-1463-45af-a88e-c74f751de424/',
'name': 'ams01-104'
},
'position': 44,
'face': {'value': 'front', 'label': 'Front'},
'parent_device': None,
'status': {'value': 'active', 'label': 'Active'},
'primary_ip': {
'display': '10.11.128.6/32',
'id': '6d98580f-1ca3-440a-9d7a-8c5bcc61fae3',
'url': 'https://demo.nautobot.com/api/ipam/ip-addresses/6d98580f-1ca3-440a-9d7a-8c5bcc61fae3/',
'family': 4,
'address': '10.11.128.6/32'
},
'primary_ip4': {
'display': '10.11.128.6/32',
'id': '6d98580f-1ca3-440a-9d7a-8c5bcc61fae3',
'url': 'https://demo.nautobot.com/api/ipam/ip-addresses/6d98580f-1ca3-440a-9d7a-8c5bcc61fae3/',
'family': 4,
'address': '10.11.128.6/32'
},
'primary_ip6': None,
'secrets_group': None,
'cluster': None,
'virtual_chassis': None,
'vc_position': None,
'vc_priority': None,
'device_redundancy_group': None,
'device_redundancy_group_priority': None,
'comments': '',
'local_context_schema': None,
'local_context_data': None,
'config_context': {
'cdp': True,
'ntp': [{'ip': '10.1.1.1', 'prefer': False}, {'ip': '10.2.2.2', 'prefer': True}],
'lldp': True,
'snmp': {
'host': [{'ip': '10.1.1.1', 'version': '2c', 'community': 'networktocode'}],
'contact': 'John Smith',
'location': 'Network to Code - NYC | NY',
'community': [{'name': 'networktocode', 'role': 'ro'}, {'name': 'secure', 'role': 'rw'}]
},
'aaa-new-model': False,
'acl': {'definitions': {'named': {'PERMIT_ROUTES': ['10 permit ip any any']}}},
'route-maps': {'PERMIT_CONN_ROUTES': {'seq': 10, 'type': 'permit', 'statements': ['match ip address PERMIT_ROUTES']}}
},
'created': '2022-11-09',
'last_updated': '2022-11-09T15:08:32.310316Z',
'tags': [],
'notes_url': 'https://demo.nautobot.com/api/dcim/devices/d2ebc009-5904-4ce3-acc1-2602264144e9/notes/',
'custom_fields': {}
}
},
'hostname': '10.11.128.6',
'port': None,
'username': None,
'password': None,
'platform': 'arista_eos'
}
Step 9¶
Finally, extract the configuration context data for ams01-leaf-04:
>>> print(ams_leaf.data["pynautobot_dictionary"]["config_context"])
{
'cdp': True,
'ntp': [{'ip': '10.1.1.1', 'prefer': False}, {'ip': '10.2.2.2', 'prefer': True}],
'lldp': True,
'snmp': {
'host': [{'ip': '10.1.1.1', 'version': '2c', 'community': 'networktocode'}],
'contact': 'John Smith',
'location': 'Network to Code - NYC | NY',
'community': [{'name': 'networktocode', 'role': 'ro'}, {'name': 'secure', 'role': 'rw'}]
},
'aaa-new-model': False,
'acl': {'definitions': {'named': {'PERMIT_ROUTES': ['10 permit ip any any']}}},
'route-maps': {'PERMIT_CONN_ROUTES': {'seq': 10, 'type': 'permit', 'statements': ['match ip address PERMIT_ROUTES']}}
}