HomeGuidesAPI Reference
GuidesAPI ReferenceGitHubAirheads Developer CommunityLog In

Day 0 Provisioning

Day 0 provisioning workflows with AOS-CX and Ansible

Let's create a Day 0 provisioning workflow that dynamically generates a device configuration from a template and then pushes the configuration to a switch.

Template, Generate, and Upload

Among the most popular Day 0 processes in networking, this workflow operates as follows:

  • Dynamically generate a configuration for a switch from a Jinja2 template
  • Instruct the device to TFTP-download the resultant configuration to itself

Concepts

  • template module: this module accepts a template and renders an output file.
  • TFTP server: this server hosts files that a switch can download using the TFTP mechanism. This example assumes that the Ansible control machine is also acting as the TFTP server.

Workflow

  1. Create a Jinja2 template. This file should resemble an AOS-CX switch configuration, except with parts of the configuration parametrized using variables. These dynamic fields will be populated when the template is rendered. An easy way to create the template is to first manually configure a device fully using the CLI, then copy that "final" configuration from the switch into a Jinja2 file, and then generalize it using variables. Jinja2 templates should reside in a directory named "templates" and possess the ".j2" file extension.

Examples of AOS-CX templates can be found here:

hostname {{hostname}}
!
!
!
ssh server vrf mgmt
!
!
!
!
!
vlan 1
interface mgmt
    no shutdown
    ip static {{oobm_ip}}/{{oobm_mask}}
    default-gateway {{oobm_default_gateway}}
system interface-group 1 speed 10g
    !interface group 1 contains ports 1/1/1-1/1/12
system interface-group 3 speed 10g
    !interface group 3 contains ports 1/1/25-1/1/36
system interface-group 4 speed 10g
    !interface group 4 contains ports 1/1/37-1/1/48    
interface {{vsx_ka}} 
    no shutdown
    description VSX KA
{% if vsx_role == 'primary' %}
    ip address {{vsx_ka_ip_primary}}/31
{% else %}
    ip address {{vsx_ka_ip_secondary}}/31
{% endif %}    
interface {{vsx_isl}} 
    no shutdown
    description VSX ISL
    no routing
    vlan trunk native 1 tag
    vlan trunk allowed all
interface {{spine1_int}} 
    no shutdown
    description Spine1
    ip address {{spine1_int_ip}}/31
interface {{spine2_int}} 
    no shutdown
    description Spine2
    ip address {{spine2_int_ip}}/31
interface loopback 0
    ip address {{loopback0_ip}}/32
interface loopback 1
    ip address {{loopback1_ip}}/32
vsx
    inter-switch-link {{vsx_isl}}
    role {{vsx_role}}
{% if vsx_role == 'primary' %}
    keepalive peer {{vsx_ka_ip_secondary}} source {{vsx_ka_ip_primary}}
{% else %}
    keepalive peer {{vsx_ka_ip_primary}} source {{vsx_ka_ip_secondary}}
{% endif %}
    no split-recovery
router bgp {{asn}}
    bgp router-id {{loopback0_ip}}
    bgp fast-external-fallover
    bgp bestpath as-path multipath-relax
    neighbor {{spine1_a_ip}} remote-as {{spine1_asn}}
    neighbor {{spine1_b_ip}} remote-as {{spine1_asn}}
    neighbor {{spine2_a_ip}} remote-as {{spine2_asn}}
    neighbor {{spine2_b_ip}} remote-as {{spine2_asn}}
    address-family ipv4 unicast
        neighbor {{spine1_a_ip}} activate
        neighbor {{spine1_b_ip}} activate
        neighbor {{spine2_a_ip}} activate
        neighbor {{spine2_b_ip}} activate
        redistribute connected
        network {{loopback0_ip}}/32
        network {{loopback1_ip}}/32
    exit-address-family
!
https-server rest access-mode read-write
https-server vrf mgmt
hostname Leaf1b
!
!
!
ssh server vrf mgmt
!
!
!
!
!
vlan 1
interface mgmt
    no shutdown
    ip static 10.100.1.21/24}
    default-gateway 10.10.10.254
system interface-group 1 speed 10g
    !interface group 1 contains ports 1/1/1-1/1/12
system interface-group 3 speed 10g
    !interface group 3 contains ports 1/1/25-1/1/36
system interface-group 4 speed 10g
    !interface group 4 contains ports 1/1/37-1/1/48
interface 1/1/22
    no shutdown
    description VSX KA
    ip address 10.1.2.1/31
interface 1/1/23
    no shutdown
    description VSX ISL
    no routing
    vlan trunk native 1 tag
    vlan trunk allowed all
interface 1/1/19
    no shutdown
    description Spine1
    ip address 192.168.2.4/31
interface 1/1/20
    no shutdown
    description Spine2
    ip address 192.168.2.6/31
interface loopback 0
    ip address 192.168.1.2/32
interface loopback 1
    ip address 192.168.100.2/32
vsx
    inter-switch-link 1/1/23
    role secondary
    keepalive peer 10.1.2.0 source 10.1.2.1
    no split-recovery
router bgp 65001
    bgp router-id 192.168.1.2
    bgp fast-external-fallover
    bgp bestpath as-path multipath-relax
    neighbor 192.168.2.1 remote-as 65101
    neighbor 192.168.2.5 remote-as 65101
    neighbor 192.168.2.3 remote-as 65102
    neighbor 192.168.2.7 remote-as 65102
    address-family ipv4 unicast
        neighbor 192.168.2.1 activate
        neighbor 192.168.2.5 activate
        neighbor 192.168.2.3 activate
        neighbor 192.168.2.7 activate
        redistribute connected
        network 192.168.1.2/32
        network 192.168.100.2/32
    exit-address-family
!
https-server rest access-mode read-write
https-server vrf mgmt
  1. Define any variables required for the template. It is best to define common variables at the group level to avoid unnecessary repetition and promote proper abstraction.

Examples of inventories can be found here:

  1. For Spine / Leaf OSPF Fabric:
* [Inventory file](https://github.com/aruba/aruba-switch-ansible/blob/master/inventory/ospf_fabric_inventory.yml): This is an example in which all the template variables are defined in a single file. Although it's easy to locate the variable-containing file, the file itself is lengthy and somewhat repetitive.
  1. For Spine / VSX Leaf eBGP EVPN VXLAN Fabric:
* [Inventory file](https://github.com/aruba/aruba-switch-ansible/blob/master/inventory/ebgp_evpn_vxlan_fabric.yml): This is an INI-formatted example in which the devices in the environment are grouped, with multiple levels of grouping.
* Group variable files:
  * [group_vars/aoscx_switches](https://github.com/aruba/aruba-switch-ansible/blob/master/group_vars/aoscx_switches.yml)
  * [group_vars/branch1_dcn_switches](https://github.com/aruba/aruba-switch-ansible/blob/master/group_vars/branch1_dcn_switches.yml)
  * [group_vars/leafs](https://github.com/aruba/aruba-switch-ansible/blob/master/group_vars/leafs.yml)
  * [group_vars/spines](https://github.com/aruba/aruba-switch-ansible/blob/master/group_vars/spines.yml)
##########################
# EBGP EVPN VXLAN VSX SPINE LEAF FABRIC DEPLOY
# Example Inventory
##########################

[aoscx_switches]
Spine1 ansible_host=10.100.1.1
Spine2 ansible_host=10.100.1.2
Leaf1a ansible_host=10.100.1.11
Leaf1b ansible_host=10.100.1.21
Leaf2a ansible_host=10.100.1.12
Leaf2b ansible_host=10.100.1.22
Leaf3a ansible_host=10.100.1.13
Leaf3b ansible_host=10.100.1.23

[branch1_dcn_switches]
Leaf1a
Leaf1b
Leaf2a
Leaf2b
Leaf3a
Leaf3b
Spine1
Spine2

[leafs]
Leaf1a
Leaf1b
Leaf2a
Leaf2b
Leaf3a
Leaf3b

[spines]
Spine1
Spine2
ansible_user: admin
ansible_password: admin
ansible_net_user: admin
ansible_net_password: admin
ansible_connection: local
config_template: spine.j2
leaf1b_int: 1/1/43
leaf1a_int: 1/1/44
leaf2a_int: 1/1/45
leaf2b_int: 1/1/46
leaf3a_int: 1/1/47
leaf3b_int: 1/1/48
hostname: Spine2
oobm_ip: 10.100.1.2
asn: "{{spine2_asn}}"
leaf1a_int_ip: 192.168.2.3
leaf1b_int_ip: 192.168.2.7
leaf2a_int_ip: 192.168.2.11
leaf2b_int_ip: 192.168.2.15
leaf3a_int_ip: 192.168.2.19
leaf3b_int_ip: 192.168.2.23
loopback0_ip: 192.168.1.12
leaf1a_ip: 192.168.2.2
leaf1b_ip: 192.168.2.6
leaf2a_ip: 192.168.2.10
leaf2b_ip: 192.168.2.14
leaf3a_ip: 192.168.2.18
leaf3b_ip: 192.168.2.22
  1. Create the Ansible playbook. Write a play and task to render the configuration using the template module, referencing the module documentation page linked in Concepts if necessary. The destination will be the full path to the file wherein the final configuration will be rendered. It is recommended that you validate the generated configuration file by copying its contents onto the switch and checking that the switch reflects the expected state.
---
- hosts: aoscx_switches
  tasks:
    - name: Generate Config from Template for Device
      template: src="leaf.j2" dest="/var/lib/tftpboot/switch_config.conf" mode='0777'
  1. Lastly, add another task, using the aoscx_upload_config module, to make the switch pull the resulting configuration onto itself with TFTP. Since this task calls an AOS-CX module, don't forget to include the role (or collection) in the play!
---
- hosts: aoscx_switches
  roles:
    - role: arubanetworks.aoscx_role
  tasks:
    - name: Generate Config from Template for Device
      template: src="golden_config_template.j2" dest="/var/lib/tftpboot/switch_config.conf" mode='0777'

    - name: Copy Config from TFTP Server to Running Config
      aoscx_upload_config:
        config_name: 'running-config'
        remote_config_file_tftp_path: 'tftp://192.168.1.2/switch_config.conf'
        vrf: 'mgmt'

What’s Next