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
- 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:
- For Spine / Leaf OSPF Fabric:
- For Spine / VSX Leaf eBGP EVPN VXLAN Fabric:
- VSX Leaf in eBGP VXLAN DC Fabric
- Spine in eBGP VXLAN DC Fabric
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 mgmthostname 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
- 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:
-
For Spine / Leaf OSPF Fabric:
* Inventory file: 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. -
For Spine / VSX Leaf eBGP EVPN VXLAN Fabric:
* Inventory file: 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
- group_vars/branch1_dcn_switches
- group_vars/leafs
- group_vars/spines
########################## # 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 Spine2ansible_user: admin ansible_password: admin ansible_net_user: admin ansible_net_password: admin ansible_connection: localconfig_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/48hostname: 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
-
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' -
Lastly, add another task, using the
aoscx_upload_configmodule, 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'
Updated 12 days ago