Skip to main content
  1. Posts/

Nautobot Ansible Collection: Devices

·1657 words·8 mins

All of the work through the modules thus far in the series have brought us to what we all want to see. How to get or update device information inside of Nautobot. Adding of sites, device types, device roles are required to get us to this point. Now you can see how to add a device to Nautobot using the networktocode.nautobot.device module.

There are many optional parameters for the module specifically. I encourage you to take a look at the module documentation (linked below) in order to get a good sense of all of the options available. The required parameters for a device that is present are:

  • device_role
  • device_type
  • name
  • site
  • status

An important caveat for me is that this is something that should be done with rarity. Only when truly adding a device to Nautobot, in a programmatic way this should be used. I do not advocate for running this module constantly based on your devices. The idea is to get Nautobot to be your source of truth about devices, not to have devices be the source of truth and updating Nautobot.

So where do I see this being run? I do absolutely see it being a part of a pipeline or a service portal. The idea being that the service portal has a request for a new site to be turned up. That in turn kicks off an Ansible Playbook that will make the necessary updates to Nautobot, and is done in a consistent manor.

Module Documentation #

This module does require pynautobot to execute properly

Environment #

For this demo, here are the versions shown:

ComponentVersion
Nautobotv1.0.0b2
Nautobot Ansible Collectionv1.0.3
pynautobot1.0.1

Data File #

The Nautobot devices file is going to be a little bit more involved. In this particular demo case there are no existing inventories to use. If you want to see a demo of a similar how to add devices to NetBox using an existing Ansible inventory, I encourage you to take a look at my GitHub repository where I did a Meetup video on working with Ansible + NetBox. The same/similar concept can be used with Nautobot.

To simulate the idea that we are going to be running a playbook execution as part of a service request, here is the data file that will be fed to the Ansible playbook:

# group_vars/all/devices.yml
---
devices:
  - name: "grb-rtr01"
    site: "GRB"
    device_role: "Router"
    device_type: "IOSv"
  - name: "msp-rtr01"
    site: "MSP"
    device_role: "Router"
    device_type: "IOSv"

Example #

Example - Adding Device Types #

First if you are following along with the examples thus far, I made a new site here. So in order to accommodate the new site, I added GRB and re-ran the playbook to create sites. That was done successfully and idempotently with only the GRB site being added.


---
- name: "ADD DEVICES"
  hosts: localhost
  connection: local
  gather_facts: false # No gathering facts about the container execution env
  tasks:
    - name: "05 - ADD DEVICES"
      networktocode.nautobot.device:
        url: "{{ lookup('env', 'NAUTOBOT_URL') }}"
        token: "{{ lookup('env', 'NAUTOBOT_TOKEN') }}"
        data:
          name: "{{ item['name'] }}"
          site: "{{ item['site'] }}"
          device_role: "{{ item['device_role'] }}"
          device_type: "{{ item['device_type'] }}"
          platform: "IOS"
          status: "Active" # Newly required for Nautobot, a status of some kind
      loop: "{{ devices }}"

Example - Execution #

Before the execution there are no devices within Nautobot:

Nautobot Without Devices

This execution shows that all of the device types are added.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
josh-v@1297da6292df:~$ ansible-playbook add_devices.yml -vv
ansible-playbook 2.10.6
  config file = /local/ansible.cfg
  configured module search path = ['/local/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.7/site-packages/ansible
  executable location = /usr/local/bin/ansible-playbook
  python version = 3.7.10 (default, Feb 16 2021, 19:28:34) [GCC 8.3.0]
Using /local/ansible.cfg as config file
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
redirecting (type: callback) ansible.builtin.yaml to community.general.yaml
redirecting (type: callback) ansible.builtin.yaml to community.general.yaml
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: add_devices.yml *******************************************************************************************************
1 plays in add_devices.yml

PLAY [ADD DEVICES] **************************************************************************************************************
META: ran handlers

TASK [05 - ADD DEVICES] *********************************************************************************************************
task path: /local/add_devices.yml:7
changed: [localhost] => (item={'name': 'grb-rtr01', 'site': 'GRB', 'device_role': 'Router', 'device_type': 'IOSv'}) => changed=true 
  ansible_loop_var: item
  device:
    asset_tag: null
    cluster: null
    comments: ''
    config_context: {}
    created: '2021-03-28'
    custom_fields: {}
    device_role: c6909cfd-0fd9-4ab1-b0e7-58493fff84b7
    device_type: 70504d2c-1641-4e6d-be40-192eb1d6e0c0
    display_name: grb-rtr01
    face: null
    id: 7757ffbd-cca8-49ee-978f-66fbdb3f6b14
    last_updated: '2021-03-28T15:48:29.324146Z'
    local_context_data: null
    name: grb-rtr01
    parent_device: null
    platform: 96d58cc1-ad7e-43c7-a79f-db748e6eb894
    position: null
    primary_ip: null
    primary_ip4: null
    primary_ip6: null
    rack: null
    serial: ''
    site: c92f368a-93a0-472b-a391-b9e9665b42a4
    status: active
    tags: []
    tenant: null
    url: http://nautobot-demo.josh-v.com/api/dcim/devices/7757ffbd-cca8-49ee-978f-66fbdb3f6b14/
    vc_position: null
    vc_priority: null
    virtual_chassis: null
  item:
    device_role: Router
    device_type: IOSv
    name: grb-rtr01
    site: GRB
  msg: device grb-rtr01 created
changed: [localhost] => (item={'name': 'msp-rtr01', 'site': 'MSP', 'device_role': 'Router', 'device_type': 'IOSv'}) => changed=true 
  ansible_loop_var: item
  device:
    asset_tag: null
    cluster: null
    comments: ''
    config_context: {}
    created: '2021-03-28'
    custom_fields: {}
    device_role: c6909cfd-0fd9-4ab1-b0e7-58493fff84b7
    device_type: 70504d2c-1641-4e6d-be40-192eb1d6e0c0
    display_name: msp-rtr01
    face: null
    id: 72f14290-865d-43a6-af7b-4e29c6400460
    last_updated: '2021-03-28T15:48:30.966452Z'
    local_context_data: null
    name: msp-rtr01
    parent_device: null
    platform: 96d58cc1-ad7e-43c7-a79f-db748e6eb894
    position: null
    primary_ip: null
    primary_ip4: null
    primary_ip6: null
    rack: null
    serial: ''
    site: c72cce62-1dd6-483e-90a3-3331ea3155a8
    status: active
    tags: []
    tenant: null
    url: http://nautobot-demo.josh-v.com/api/dcim/devices/72f14290-865d-43a6-af7b-4e29c6400460/
    vc_position: null
    vc_priority: null
    virtual_chassis: null
  item:
    device_role: Router
    device_type: IOSv
    name: msp-rtr01
    site: MSP
  msg: device msp-rtr01 created
META: ran handlers
META: ran handlers

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

The second execution of playbook shows that with these three settings the module is idempotent:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
josh-v@1297da6292df:~$ ansible-playbook add_devices.yml -vv
ansible-playbook 2.10.6
  config file = /local/ansible.cfg
  configured module search path = ['/local/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.7/site-packages/ansible
  executable location = /usr/local/bin/ansible-playbook
  python version = 3.7.10 (default, Feb 16 2021, 19:28:34) [GCC 8.3.0]
Using /local/ansible.cfg as config file
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
redirecting (type: callback) ansible.builtin.yaml to community.general.yaml
redirecting (type: callback) ansible.builtin.yaml to community.general.yaml
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: add_devices.yml *******************************************************************************************************
1 plays in add_devices.yml

PLAY [ADD DEVICES] **************************************************************************************************************
META: ran handlers

TASK [05 - ADD DEVICES] *********************************************************************************************************
task path: /local/add_devices.yml:7
ok: [localhost] => (item={'name': 'grb-rtr01', 'site': 'GRB', 'device_role': 'Router', 'device_type': 'IOSv'}) => changed=false 
  ansible_loop_var: item
  device:
    asset_tag: null
    cluster: null
    comments: ''
    config_context: {}
    created: '2021-03-28'
    custom_fields: {}
    device_role: c6909cfd-0fd9-4ab1-b0e7-58493fff84b7
    device_type: 70504d2c-1641-4e6d-be40-192eb1d6e0c0
    display_name: grb-rtr01
    face: null
    id: 7757ffbd-cca8-49ee-978f-66fbdb3f6b14
    last_updated: '2021-03-28T15:48:29.324146Z'
    local_context_data: null
    name: grb-rtr01
    parent_device: null
    platform: 96d58cc1-ad7e-43c7-a79f-db748e6eb894
    position: null
    primary_ip: null
    primary_ip4: null
    primary_ip6: null
    rack: null
    serial: ''
    site: c92f368a-93a0-472b-a391-b9e9665b42a4
    status: active
    tags: []
    tenant: null
    url: http://nautobot-demo.josh-v.com/api/dcim/devices/7757ffbd-cca8-49ee-978f-66fbdb3f6b14/
    vc_position: null
    vc_priority: null
    virtual_chassis: null
  item:
    device_role: Router
    device_type: IOSv
    name: grb-rtr01
    site: GRB
  msg: device grb-rtr01 already exists
ok: [localhost] => (item={'name': 'msp-rtr01', 'site': 'MSP', 'device_role': 'Router', 'device_type': 'IOSv'}) => changed=false 
  ansible_loop_var: item
  device:
    asset_tag: null
    cluster: null
    comments: ''
    config_context: {}
    created: '2021-03-28'
    custom_fields: {}
    device_role: c6909cfd-0fd9-4ab1-b0e7-58493fff84b7
    device_type: 70504d2c-1641-4e6d-be40-192eb1d6e0c0
    display_name: msp-rtr01
    face: null
    id: 72f14290-865d-43a6-af7b-4e29c6400460
    last_updated: '2021-03-28T15:48:30.966452Z'
    local_context_data: null
    name: msp-rtr01
    parent_device: null
    platform: 96d58cc1-ad7e-43c7-a79f-db748e6eb894
    position: null
    primary_ip: null
    primary_ip4: null
    primary_ip6: null
    rack: null
    serial: ''
    site: c72cce62-1dd6-483e-90a3-3331ea3155a8
    status: active
    tags: []
    tenant: null
    url: http://nautobot-demo.josh-v.com/api/dcim/devices/72f14290-865d-43a6-af7b-4e29c6400460/
    vc_position: null
    vc_priority: null
    virtual_chassis: null
  item:
    device_role: Router
    device_type: IOSv
    name: msp-rtr01
    site: MSP
  msg: device msp-rtr01 already exists
META: ran handlers
META: ran handlers

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

Post Execution #

After the execution and notice that the module is idempotent, the two devices shown are all set to be added.

Nautobot Devices

Summary #

Now that you have some devices, you can start to do a little bit more with your Nautobot environment. This playbook purposely did not add more information about the device yet, such as the serial number, interfaces, or IP addressing. This is all information that you can add more about the device as well using Ansible Facts and Resource Modules to continue to develop your source of truth. More likely to come in the future, or you can check out the content on GitHub and YouTube referenced above for immediate reference.

Getting devices into Nautobot provides a powerful place to put your source of truth for automation. It does take a small bit to get to a good place, but with a little bit of effort up front you can get things done in a consistent and repeatable fashion. No more having to do things by hand with the data points.

Hope this has helped. If so, let me know with a comment below or give a thumbs up on the post.