Automating NX-OS with Netbox and Ansible Automation Platform
This guide contains a few basic examples to get started automating NX-OS based networks with Netbox and Ansible Automation Platform. While this example is not part of the Nexus-as-Code project, it offers more seasoned Ansible users several examples to get started with driving network changes through Netbox.
Open source configuration management tools like Netbox are gaining traction in the industry. Netbox combines traditional IP address management (IPAM) with datacenter infrastructure management (DCIM). It offers a powerful API and event-driven webhooks which makes it ideal for network automation. Some organizations want to use Netbox as their source of truth for their datacenter infrastructure. Others prefer it as a system of records to store information reflecting the state of the infrastructure. In this example, Netbox is leveraged as a SSoT (Single Source of Truth) for network configuration.
This guide assumes a working installation of Netbox and Ansible Automation Platform. For installation instructions please visit:
- Netbox 4.0
- Ansible Automation Platform 2.4
- Git
- A text editor / Integrated Development Environment (IDE) (such as VisualStudio Code)
It also assumes that the reader has the option to create a private repository to store the Ansible inventory and playbooks. This guide makes use of the SaaS version of Gitlab.
Examples covered here include:
- Complete interface configuration
- Switch Virtual Interface (SVI) configuration
It is worth noting that Netbox does not offer many of the Gitops benefits such as branching, versioning, etc. For those that are interested in this, Nautobot is available as an alternative. Nautobot was initially developed as a fork of Netbox. It offers native Git integration along with support for plugins that allow to sync inventory state between different DCIM tools. The examples below can also be used with Nautobot.
Adding device configuration and tags to Netbox
First, Netbox needs to have some device configuration in place so that Ansible Automation Platform can execute Playbooks against those devices. Tags will be used to prevent Ansible Automation Platform from running a job each time a change is made in Netbox. In the Netbox GUI, navigate to Customization
> Tags
and add a new tag named ansible-int
.
Add at least one device to the Netbox inventory. This example assumes 4 Nexus switches as shown below. Tip: Many device types have already been added to the netbox-community devicetype-library.
Add interfaces to the device. Note that it is possible to use make use of ranges to support bulk creation. An example is the range Ethernet1/[1-48]
with Type SFP+ (10GE)
and Ethernet1/[49-54]
with Type QSFP+ (40GE)
for a typical 48-port top of rack switch. Keep in mind that the name of the interfaces should match the actual interface names on the device/switch.
Within the device overview window, navigate to Add Components
> Interfaces
:
Add a range of interfaces to the device:
Note: if the instance of Netbox already contains existing devices and interfaces, This step is optional.
Set up a repository
Now that the initial device configuration has been added to Netbox, the next step is to create a Git repository. As mentioned before, this guide leverages Gitlab. When doing so, be mindful of the visibility settings on the Gitlab project as this repository will store login credentials to the Nexus switches in an inventory.ini
file.
Give the new repository a sensible name and select Create project
.
Go ahead and clone the repository. The URL can be found in the clone
dropdown menu.
git clone git@gitlab.com:<group>/<newrepo>.git
Cloning into '<newrepo>'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
Populating the repository
Open the cloned folder in a text editor / IDE. Within this folder, create a new folder named collections
. In that the collections
folder, create a file named requirements.yml
. Populate the requirements.yml
file with the following:
collections:
- name: cisco.nxos
The cloned folder should now have the following structure:
The requirements.yml
file will instruct Ansible Automation Platform which collection it should use.
Next up is the inventory file. Create a new file inventory.yml
within the root of the cloned folder, and add the code below. Feel free to customize this based on the requirements and devices that are in scope. Make sure to update the device credentials in ansible_user
and ansible_ssh_pass
.
[all:vars]
represents the variables that apply to all devices. As the management IP address for each device is likely unique, these are specified as group variables such as EVPN-LEAF-1
. Make sure to substitute the group variables in the inventory.ini
file with the correct device name
as configured in Netbox. For example, substitute EVPN-LEAF-1
with my-prod-switch-1
if that matches the device name in Netbox. Lastly, make sure to update the management IP address for each device.
[all:vars]
ansible_connection= network_cli
ansible_network_os= nxos
ansible_user= admin
ansible_ssh_pass= "password"
[EVPN-LEAF-1]
10.61.124.182
[EVPN-LEAF-2]
10.61.124.183
[EVPN-SPINE-1]
10.61.124.184
[EVPN-SPINE-2]
10.61.124.185
Creating the first playbook
Now that the environment has been set up with a requirements
and inventory
file, next is the creation of the first Ansible Playbook. This playbook will configure basic interface parameters such as setting the description, speed, duplex, access VLAN, etc.
- Create a file within the root of the cloned folder named
nxos-int.yml
, and add the following code:
- name: Netbox Webhook Ansible Interface
hosts:
- "{{ device_id }}"
gather_facts: no
tasks:
- name: Nxos L2 Interface VLAN
cisco.nxos.nxos_l2_interfaces:
config:
- name: "{{ interface_id }}"
access:
vlan: "{{ vlan_id }}"
state: replaced
tags:
- ansible-int
- name: Nxos Interface
cisco.nxos.nxos_interfaces:
config:
- name: "{{ interface_id }}"
description: "{{ description }}"
duplex: "{{ duplex }}"
mtu: "{{ mtu }}"
speed: "{{ speed }}"
enabled: "{{ enabled }}"
state: merged
tags:
- ansible-int
- Save the
netbox-interfaces.yml
file.
Note that variable values such as
{{ vlan_id }}
will be passed to Ansible Automation Platform through a webhook. These variables will be substituted. When configuring a webhook in Netbox in a later step, the payload is modified in such a way that only the fields that are relevant for the Ansible Playbook are sent. In order to better understand which fields can be passed in the body of the webhook, it can be useful to make use of Postman and the Netbox API. When doing this, make sure to provide the Netbox API key in the authorization tab. An example POST request is shown below. Make sure to substitutedevice.name
with the correct device name andname
with any interface.
The folder should now contain the following files and look like this:
- The next steps are pushing the local changes to the remote repository. This is done by adding the changes to staging, writing a commit message, followed by pushing the changes to the remote git repository.
~/netbox-aap-nxos main ?3 > git add .
~/netbox-aap-nxos main +3 > git status #optional command for verification
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: collections/requirements.yml
new file: inventory.ini
new file: nxos-int.yml
~/netbox-aap-nxos main +3 > git commit -am "initial code"
[main bec08bf] initial code
3 files changed, 15 insertions(+)
create mode 100644 collections/requirements.yml
create mode 100644 inventory.ini
create mode 100644 nxos-int.yml
~/netbox-aap-nxos main >1 > git push
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 601 bytes | 601.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab.com:ecvd/netbox-aap-nxos.git
9a65793..bec08bf main -> main
Setting up Ansible Automation Platform
In order for AAP to read and access the contents of the previously created Git repository it is required to add credentials. In the Ansible Automation Platform GUI, navigate to Resources
> Credentials
, and select Add
. In the Create New Credential
window, perform the following actions:
- Provide a
Name
for the credentials. - Optionally, provide a
description
. - In the
Credential Type
field, select Source Control. - In the
Type Details
section, provide a Username and Password. - Select
Save
.
Add a new project by navigating to Resources
> Projects
and selecting Add
:
In this window, perform the following actions:
- Provide a
name
for the new project. - Select
Git
as the SCM type. - Provide the
SCM URL
. This is the URL to access the Git repository. (an example is https://gitlab.com/your-org/netbox-aap-nxos.git)
After saving the new project configuration, Ansible Automation Platform will trigger an SCM update to read the contents of the repository. The status can be observed in the detailed view or by navigating to Views
> Jobs
.
If repository is read successfully by Ansible Automation Platform, the contents of inventory.ini
can be used to create a new inventory. Navigate to Resources
> Inventories
> Add
and select Add Inventory
to add a new inventory
:
In the Create new inventory
window, select Save
and navigate to the Sources
menu. Within this menu, select add
to add a new source. In this window, perform the following actions:
Provide a
Name
for the inventory.Select
Sourced from a Project
in theSource
dropdown menu.In
Source Details
>Project
. Select the previously created project.In
Source Details
>Inventory File
. Selectinventory.ini
.Select
Save
.Note that if there are frequent changes to the remote repository it can be helpful to check the
update on launch
andupdate variables
update options to refresh the inventory file to the most recent version whenever a job using this inventory is launched.Navigate to the bottom of the Details view and select
Sync
to trigger a one time inventory sync.Ensure that this job runs successfully.
The next step is to create a job template. The job template is where the inventory, playbook and other settings are linked together. Navigate to Resources
> Templates
and select Add
> Add job template
to add a new job template. In the Create New Job Template
window, perform the following actions:
- Provide a
Name
for the job template. - In the
Inventory
menu, select the previously created inventory. - In the
Project
menu, select the previously created project. - In the
Playbook
menu, ensure that the nxos-int.yml playbook is populated and select it. - In the
variables
configuration area, selectPrompt on Launch
. - Navigate the the bottom and check
Prompt on Launch
forJob Tags
.Note: the
prompt on launch
flags are important as this instructs the job to prompt for extra variables and tags. The variables will get substituted with the values in the webhook sent by Netbox. The tags are needed to determine when the playbook should run. - Save the template and take note of the URL to find the Job Template ID. For example, If this is the URL:
https://url/#/templates/job_template/15/details
. The Job ID is 15.
The final steps are adding an Application and Token to authorize the POST requests (webhooks) sent by Netbox to Ansible Automation Platform.
Navigate to Administration
> Applications
and select Add
to add a new application. In the Create New Application
window, perform the following actions:
- Provide a
Name
for the new application. - In the
Authorization grant type
menu, selectResource owner password-based
. - In the
Client type
menu, selectPublic
. - Select
Save
to save the new application.
Navigate to Access
> Users
and select the admin
user. Alternatively, add or use another user. In the Users detailed view, perform the following actions:
- Navigate to the
Tokens
menu tab and selectAdd
to add a new token. - In the
Application
field, select the previously created application. - In the
Scope
field, selectWrite
. - Select
Save
and take note of theToken
andRefresh Token
as this is only displayed once.
Setting up the webhook
In the Netbox GUI, navigate to Other
> Integrations
> Webhooks
and select Add
to add a new Webhook. In the Add a new webhook
window, perform the following actions:
- Provide a
Name
for the Webhook. - In the
URL
field, provide the job template url with thelaunch
parameter. Job ID 15 is used as example. This should match the respective job ID as noted earlier. - In the
Additional headers
addAuthorization: Bearer <your-token>
to authenticate with Ansible Automation Platform. This is theToken
from previous step. - In the
Body template
field, provide the json formatted text from the following snippet:
{ "extra_vars": {
"device_id": "{{ data['device']['name'] }}",
"interface_id": "{{ data['name'] }}",
"vlan_id": "{{ data['untagged_vlan']['vid'] }}",
"description": "{{ data['description'] }}",
"duplex": "{{ data['duplex']['value'] }}",
"mtu": "{{ data['mtu'] }}",
"speed": "{{ data['speed'] }}",
"enabled": "{{ data['enabled'] }}"
},
"job_tags": "{{ data['tags'][0]['name'] }}"
}
Note: the
Body template
field is a Jinja2 template that allows the user to customise what is presented in the payload of the webhook. For basic interface configuration, the body should carry at least some basic parameters. In this configuration example, it should also carry a job tag so that the tag can be used by Ansible Automation Platform whether it should run a playbook.
Note: The line
"job_tags": "{{ data['tags'][0]['name'] }}"
only passes the first instance [0] of a tag applied to an interface. This does not allow passing multiple tags.
- Optionally, disable
SSL verification
.Note: This setting should be left enabled for production usage.
Creating event rules
Now that the Webhook is created, event rules are required to determine when to run the webhook. In the Netbox GUI, navigate to Integrations
> Event Rules
, and select Add
to add a new event rule. In this window, perform the following actions:
In the
Name
field, provide a name for the new event rule.In the
Object Types
, select DCIM > InterfaceIn the
Tags
field, select the previously created tag.In the
Events
configuration section, select Updates.In the
Action
configuration section, forAction Type
, selectWebhook
In the
Action
configuration section, forWebhook
, select the webhook created in previous step.Select
Save
to save the event rule.
Modifying an interface
With the webhook and event rule for interfaces configured, generate an dcim
, interface
update event by modifying some of the configuration on an interface. In the Netbox GUI, Navigate to Devices
, select a Device
, and select any of the interfaces from the Interfaces
tab.
In the interface overview, select edit
and perform the following actions:
- In the
Speed
field, provide an interface speed in Kbps. - In the
Duplex
field, select Full. - In the
Description
field, provide a description. - In the
Tags
menu, select the previously created tag. - In the
MTU
field, provide the MTU. - In the
Operation
configuration section, check Enabled. - In the
802.1Q Switching
menu, select Access. - In the
Untagged VLAN
menu, select a VLAN. (if no VLANs exist, add a VLAN)
Before saving the configuration, open up a terminal and connect to the switch that owns the interface that is about to be modified, so that the changes can be verified later.
- Connect to the respective leaf over SSH and execute the following
show
command on the repsective interface.
EVPN-LEAF-1# show run int eth1/15
!Command: show running-config interface Ethernet1/15
!Running configuration last done at: Wed Jun 19 09:00:29 2024
!Time: Tue Jun 25 16:00:15 2024
interface Ethernet1/15
switchport mode trunk
switchport trunk allowed vlan none
spanning-tree port type edge trunk
mtu 9216
- Navigate back to Netbox and select
Save
to save the interface configuration. This will trigger the Webhook and this will attempt to launch a job in Ansible Automation Platform. - In Ansible Automation Platform, navigate to
Views
>Jobs
and select the job to confirm the configuration by ensuring the job exists, and the rightjob template
,inventory
, andplaybook
are shown. - Connect or return to the respective leaf over SSH and execute the following
show
command on the repsective interface.
LEAF-1(config-if)# show run int eth1/15
!Command: show running-config interface Ethernet1/15
interface Ethernet1/15
description Configured through Ansible Automation Platform
switchport access vlan 5
spanning-tree port type edge trunk
speed 10000
duplex full
Switch Virtual Interface (SVI) creation
An example to create an SVI will be provided here, but without the step by step guidance that was provided up to this point. Create a new job template
for each new playbook.
The following Ansible playbook can be used to create an SVI on a Nexus switch:
cat nxos-l3-interface.yaml
---
- name: Netbox Webhook Ansible Interface
hosts:
- "{{ device_id }}"
gather_facts: no
tasks:
- name: Nxos L3 Interface
cisco.nxos.nxos_l3_interfaces:
config:
- name: "{{ interface_id }}"
ipv4:
- address: "{{ address }}"
state: replaced
tags:
- ansible-l3-int
Note: the current
state
for the task is set toreplaced
. Feel free to modify this to meet other requirements. Also make sure to create theTag
in Netbox.
Following the Playbook above, the webhooks Body Template
should be the following:
{ "extra_vars": {
"device_id": "{{ data['assigned_object']['device']['name'] }}",
"address": "{{ data['address'] }}",
"interface_id": "{{ data['assigned_object']['name'] }}"
},
"job_tags": "{{ data['tags'][0]['name'] }}"
}
The Webhook should be configured to trigger on Create
and Update
events. The Event Content Type
is IPAM
> IP Address
.