Professional Documents
Culture Documents
How To Automate Your Network Using Ansible and Napalm Part 4
How To Automate Your Network Using Ansible and Napalm Part 4
In this scenario, we are going to use only juniper vMX nodes in order to simulate the
whole topology and the below diagram outline the network topology.
In the next section, we are going to outline all the above-outlined steps in order to
achieve the service provisioning for the L3VPN service.
The below snippet outline the JINJA2 template for the L3VPN provisioning for JunOS.
Using the same techniques we outlined in the previous posts we can render the final
device configuration for both nodes to get the final per node configuration that will
be pushed by Ansible into the devices. The below snippet outlines the final rendered
configuration for vMX2 router for this L3VPN service.
Resource Validation
After we have generated the required configuration and before deploying this
configuration into the devices we should perform some sanity checks in order to
validate that this configuration when it will be pushed to the device will take effect
as well as it will not impact any other service (other L3VPN customers) running on
these nodes. Thus we need to perform some validation tests in order to verify that
the network is ready and that there is no impact if this configuration went active.
Below are some tests that we will perform in order to validate that the resources are
ready on the network as well as that there will be no impact on existing services.
More complicated checks can be performed like RT/RD overlapping or IP subnet
overlapping however these kind of tests require a backend DB to cross check
against, so the goal is just to illustrate the idea, however for a real world scenario
more advanced tests should be carried out.
The input to this pre-validation is the node data model that we generate in the
previous check, we connect to the devices that will be provisioned for this service
and retrieve some outputs from it (like show interface) and compare it to the node
service model to make sure that all the above check pass. We use an Ansible
playbook to trigger this pre-validation step before service deployment and it is very
similar to the validation script that we use in the previous post. The below snippet
outline the Playbook that we used to do the pre-validation using network state
gathered by NAPALM.
- name: Gather Network Resources
gather_facts: no
connection: local
hosts: all
tags: [ gather ]
vars_files:
- "./l3vpn-node.yml"
tasks:
- name: GET BGP and LLDP output
napalm_get_facts:
hostname: "{{ ansible_host }}"
username: "{{ ansible_user }}"
dev_os: "{{ dev_os }}"
password: "{{ ansible_ssh_pass }}"
optional_args:
port: "{{ ansible_port }}"
filter:
- interfaces_ip
- interfaces
when: inventory_hostname in nodes
- set_fact: node={{nodes[inventory_hostname]}}
when: inventory_hostname in nodes
- set_fact: node_interfaces={{node|map(attribute='links')|list}}
when: inventory_hostname in nodes
- set_fact: node_vlans=''
when: inventory_hostname in nodes
- set_fact: node_vlans="{{ node_vlans|list + item.keys()}}"
with_list: "{{node_interfaces}}"
when: inventory_hostname in nodes
- name: Validate Interfaces are available on the router
assert:
that: item.split('.')[0] in hostvars[inventory_hostname].napalm_interfaces.keys()
msg: |
Interface {{item.split('.')[0]}} Is not available on {{inventory_hostname}}
with_list: "{{node_vlans}}"
when: inventory_hostname in nodes
ignore_errors: true
- name: Validate all VPN Interface is operational
assert:
that: hostvars[inventory_hostname].napalm_interfaces[item.split('.')[0]].is_up == true
msg: |
Interface {{item.split('.')[0]}} Is DOWN on {{inventory_hostname}}
with_list: "{{node_vlans}}"
when: inventory_hostname in nodes
ignore_errors: true
- name: Validate VLANs are not already used on the interfaces
assert:
that: item not in hostvars[inventory_hostname].napalm_interfaces_ip.keys()
msg: |
Interface {{item}} Is already used in {{inventory_hostname}}
with_list: "{{node_vlans}}"
when: inventory_hostname in nodes
ignore_errors: true
Service Deployment
Once we made sure that this new service model is valid and all the resources are
available to provision the service we move forward to deploy the configuration on
the devices. We use another Ansible playbook very similar to the one we used in the
2nd post in order to push the devices using Ansible and NAPALM to each device in
the service model. The below snippet outline the playbook that we used to push the
configuration for this customer L3VPN provisioning task.
---
- hosts: localhost
name: Create node data model
gather_facts: no
tags: [ model ]
vars_files:
- "{{model|default('l3vpn-model.yml')}}"
tasks:
- name: Create per-node data model from fabric data model
template: src=l3vpn-service.j2 dest=./l3vpn-node.yml
- name: Generate Configuration for all routers
gather_facts: no
connection: local
hosts: all
tags: [ template ]
tasks:
- include_vars: "./l3vpn-node.yml"
- file: path=l3vpn-{{common.vrf_name}}-config state=directory
run_once: true
- name: Generate Configuration
template: src=conf-template/jnpr-l3vpn.j2 dest=l3vpn-{{common.vrf_name}}-
config/{{inventory_hostname}}-l3vpn.txt
when: "inventory_hostname in nodes.keys()"
## Third Play
# commit variable is used to control the play
# if commit=0 then we will not commit the changes we will only generate diff
# if commit=1 then we will commit the changes and generate diff
- name: push the configuration to the devices
gather_facts: no
connection: local
hosts: all
tags: [ deploy ]
tasks:
- include_vars: "./l3vpn-node.yml"
- file: path=l3vpn-conf-diff state=directory
run_once: true
- name: load the configuration to the devices
napalm_install_config:
hostname: "{{ ansible_host }}"
username: "{{ ansible_user }}"
dev_os: "{{dev_os}}"
password: "{{ ansible_ssh_pass }}"
optional_args:
port: "{{ ansible_port }}"
config_file: l3vpn-{{common.vrf_name}}-config/{{inventory_hostname}}-l3vpn.txt
commit_changes: "{{commit}}"
diff_file: l3vpn-conf-diff/{{inventory_hostname}}-diff.txt
when: "inventory_hostname in nodes.keys()"
Service Validation
Once the configuration is pushed into the devices we perform another validation
step in order to verify that the configuration was pushed correctly and that the VPN
service is working as expected, again any custom checks can be applied however we
will use the following tests just for illustration.
We again take the node data model and compare it against the state of the network
after the configuration is pushed (retrieve show commands from the provisioned
devices) and validate that all the above test cases have passed. The playbook is very
similar to the one used in the pre validation step and it was illustrated in the 3rd
post.
Conclusion
In this post, we outlined how to use Ansible as an orchestration system for service
deployment and how it can be used to build the data model for the service and how
it can be used to deploy and validate the configuration for a L3VPN. This simple
model can be extended to provide orchestration for other services and the
validation can be as well extended to include other tests for service pre and post
validation.Further, the overall process can be further automated and extended by
providing a front-end to Ansible where the service parameters are entered there
(Like vpn_name, RD/RT,etc..) and then these values are pushed into the service
model, also a backend DB can be used to store this information so as it can be used
for validation. All these enhancements can be used to deliver a carrier-grade service
provisioning solution with Ansible in its core as outlined in this post.