Skip to content
This repository has been archived by the owner on Oct 11, 2020. It is now read-only.

09. OpenConfig demo with Ansible

Khelil Sator edited this page Jan 22, 2018 · 7 revisions

Ansible to interact with Junos

Ansible librairies to interact with Junos:

There are two Ansible librairies to interact with Junos.
Both of them are used into this repository.

  • An Ansible library for Junos built by Juniper.
  • An Ansible library for Junos built by Ansible.
Ansible core modules for Junos, built by Ansible:

Installation: core modules. They are shipped with ansible itself (from Ansible 2.1) (batteries included). Ansible 2.1 or above is required.
Documentation: http://docs.ansible.com/ansible/list_of_network_modules.html
Source code: https://github.com/ansible/ansible-modules-core/tree/devel/network/junos

Ansible modules for Junos, built by Juniper:

Hosted on the Ansible Galaxy website (https://galaxy.ansible.com/Juniper/junos/).
Documentation: http://junos-ansible-modules.readthedocs.io/
Source code: https://github.com/Juniper/ansible-junos-stdlib
Installation: They are hosted on the Ansible Galaxy website (https://galaxy.ansible.com/Juniper/junos/). You need to install them.
To download and install the last version available on galaxy to the Ansible server, you need to execute the command:

sudo ansible-galaxy install Juniper.junos

To download and install the version 1.4.3 to the Ansible server, you need to execute the command:

sudo ansible-galaxy install Juniper.junos,1.4.3

Requirements on the Ansible server:

Ansible 2.1 or above is required to use the Ansible core modules for Junos.
It is also require to install the python libraries py-junos-eznc (PyEZ) and jxmlease on the Ansible server.

This repository has been tested using Ubuntu 16.04 and Ansible 2.4.2.0.

Run these commands on Ubuntu 16.04 to install these tools:

sudo -s
apt-get update
apt-get install -y python-dev libxml2-dev python-pip libxslt1-dev build-essential libssl-dev libffi-dev git
pip install junos-eznc jxmlease wget jsnapy ansible==2.4.2.0 requests ipaddress cryptography 

Get locally the content of the remote repository

sudo -s
git clone https://github.com/ksator/openconfig-demo-with-juniper-devices.git
ls openconfig-demo-with-juniper-devices

Move to the local copy of the remote repo

cd openconfig-demo-with-juniper-devices
sudo -s

Download and install the junos modules version 1.4.3 from galaxy

ansible-galaxy install Juniper.junos,1.4.3

Check the Ansible version:

ansible --version

Verify you have the Juniper.junos role:

ls /etc/ansible/roles/

This repository has been tested using the version 1.4.3 of the Juniper.junos role available on Galaxy. Use this command to see the name and version of each role installed:

ansible-galaxy list

You need to run the below commands within the root of the project tree.

Requirements on the Junos devices:

Except for the Ansible core module junos_netconf, all the Ansible modules for Junos require Netconf to be configured on the Junos devices:

set system services netconf ssh
commit
Looking for examples on of how to use Ansible with Juniper devices?

you can visit this repository https://github.com/ksator/ansible-training-for-junos

Ansible Inventory file:

The default 'hosts' file is supposed to live in /etc/ansible/hosts
The inventory file we are using in this repository is hosts. It is at the root of the repository (https://github.com/ksator/openconfig-demo-with-juniper-devices/blob/master/hosts), so it is not at the default place.
There are 2 devices in the inventory file: fabric-01 and fabric-02. They belong to the group Openconfig_Routers.
This file also defines the ip address of each device with the variable junos_host. This variable is used in the playbooks.

Ansible config file for ansible:

There is an ansible.cfg file at the root of the repository (https://github.com/ksator/openconfig-demo-with-juniper-devices/blob/master/ansible.cfg).
It refers to our inventory file (hosts): So, despite the inventory file is not /etc/ansible/hosts, there is no need to add -i hosts to the ansible-playbook commands: the playbooks will find automatically the inventory file.

Ansible variables:

group_vars and host_vars directories at the root of this repository define the variables. group_vars defines the variables for the groups, host_vars defines the variables for the hosts.
The inventory file (hosts file at the root of the repository) also defines some variables (junos_host).
Ansible can find automatically the variables defined in the group_vars and host_vars directories and the hosts file.

Ansible playbooks:

All playbooks are named pb.*.yml. They are at the root of the repository.

$ ansible-playbook pb.check.interfaces.yml

PLAY [Check if interfaces are up] **********************************************

TASK [Check if Physical Interfaces are up] *************************************
ok: [fabric-01] => (item={u'interface': u'xe-0/0/0', u'neighbor': u'fabric-02', u'address': u'192.168.1.1'})
ok: [fabric-02] => (item={u'interface': u'xe-0/0/0', u'neighbor': u'fabric-01', u'address': u'192.168.1.2'})

TASK [Send Slack notification to the team] *************************************
ok: [fabric-01 -> localhost]
ok: [fabric-02 -> localhost]

PLAY RECAP *********************************************************************
fabric-01                  : ok=2    changed=0    unreachable=0    failed=0
fabric-02                  : ok=2    changed=0    unreachable=0    failed=0
  • pb.conf.interfaces.yml - This playbook confgures the routers interfaces: It renders the jinja2 template interfaces.j2 for each device and applies (push and commit) the configuration file on each devices. It then send a slack notification.
$ ansible-playbook pb.conf.interfaces.yml

PLAY [create interfaces configuration] *****************************************

TASK [Push on interfaces config from templates, and commit.] *******************
changed: [fabric-02]
changed: [fabric-01]

TASK [Send Slack notification to the team] *************************************
ok: [fabric-01 -> localhost]
ok: [fabric-02 -> localhost]

PLAY RECAP *********************************************************************
fabric-01                  : ok=2    changed=1    unreachable=0    failed=0
fabric-02                  : ok=2    changed=1    unreachable=0    failed=0

  • pb.check.L2.L3.yml - This playbook checks if there is no cabling error (It compares the expected topology (described in a yaml file) with the topology discovered with LLDP). It also executes pings on routers (i.e ICMP ping. To not confuse with the Ansible core module ping) to check if there is no IP connectivity issue between our routers.
$ ansible-playbook pb.check.L2.L3.yml

PLAY [L2 and L3 checks] ********************************************************

TASK [check if lldp neighbors are the ones we expect] **************************
ok: [fabric-02] => (item={u'interface': u'xe-0/0/0', u'neighbor': u'fabric-01', u'address': u'192.168.1.2'})
ok: [fabric-01] => (item={u'interface': u'xe-0/0/0', u'neighbor': u'fabric-02', u'address': u'192.168.1.1'})

TASK [check if junos devices can ping ip of their neighbors (directly connected)] ***
ok: [fabric-01] => (item={u'local_address': u'192.168.1.1', u'as': 110, u'group': u'OC', u'address': u'192.168.1.2'})
ok: [fabric-02] => (item={u'local_address': u'192.168.1.2', u'as': 104, u'group': u'OC', u'address': u'192.168.1.1'})

TASK [Send Slack notification to the team] *************************************
ok: [fabric-01 -> localhost]
ok: [fabric-02 -> localhost]

PLAY RECAP *********************************************************************
fabric-01                  : ok=3    changed=0    unreachable=0    failed=0
fabric-02                  : ok=3    changed=0    unreachable=0    failed=0
$ ansible-playbook pb.render.template.yml

PLAY [create BGP Openconfig configuration from a template] *********************

TASK [Build OC BGP configuration files from a template and save them locally] **
ok: [fabric-01]
ok: [fabric-02]

PLAY RECAP *********************************************************************
fabric-01                  : ok=1    changed=0    unreachable=0    failed=0
fabric-02                  : ok=1    changed=0    unreachable=0    failed=0

$ ls *.conf
fabric-01.oc.bgp.conf  fabric-02.oc.bgp.conf
  • pb.conf.bgp.oc.yaml - This playbook backups locally (in the directory backup) the running configuration of the routers. It then renders the jinja2 template bgp.j2 for each device and applies (push and commit) the Openconfig BGP configuration file on each devices. It then checks on the configured devices if the actual new operational state is equal to the expected operational state. It send slack notifications.
$ ansible-playbook pb.conf.bgp.oc.yaml --check --tags "configuration"

PLAY [create BGP Openconfig configuration] *************************************

TASK [Backup locally the config from the routers. Push on routers OC BGP config from templates, and commit.] ***
changed: [fabric-02]
changed: [fabric-01]

TASK [Send Slack notification to the team] *************************************
skipping: [fabric-01]
skipping: [fabric-02]

PLAY [wait for peers to establish BGP connections] *****************************

PLAY [check bgp states] ********************************************************

PLAY RECAP *********************************************************************
fabric-01                  : ok=1    changed=1    unreachable=0    failed=0
fabric-02                  : ok=1    changed=1    unreachable=0    failed=0

$ ansible-playbook pb.conf.bgp.oc.yaml --check --diff --limit fabric-01 --tags "configuration"

PLAY [create BGP Openconfig configuration] *************************************

TASK [Backup locally the config from the routers. Push on routers OC BGP config from templates, and commit.] ***
changed: [fabric-01]

[edit policy-options]
+   policy-statement bgp-in {
+       then accept;
+   }
+   policy-statement bgp-out {
+       then accept;
+   }
[edit]
+  openconfig-bgp:bgp {
+      neighbors {
+          neighbor 192.168.1.2 {
+              config {
+                  peer-as 110;
+                  peer-group OC;
+              }
+          }
+      }
+      peer-groups {
+          peer-group OC {
+              config {
+                  local-as 104;
+                  peer-type EXTERNAL;
+              }
+              apply-policy {
+                  config {
+                      import-policy bgp-in;
+                      export-policy bgp-out;
+                  }
+              }
+          }
+      }
+  }

TASK [Send Slack notification to the team] *************************************
skipping: [fabric-01]

PLAY [wait for peers to establish BGP connections] *****************************
skipping: no hosts matched

PLAY [check bgp states] ********************************************************

PLAY RECAP *********************************************************************
fabric-01                  : ok=1    changed=1    unreachable=0    failed=0
$ ansible-playbook pb.conf.bgp.oc.yaml

PLAY [create BGP Openconfig configuration] *************************************

TASK [Backup locally the config from the routers. Push on routers OC BGP config from templates, and commit.] ***
changed: [fabric-02]
changed: [fabric-01]

TASK [Send Slack notification to the team] *************************************
ok: [fabric-02 -> localhost]
ok: [fabric-01 -> localhost]

PLAY [wait for peers to establish BGP connections] *****************************

TASK [pause] *******************************************************************
Pausing for 20 seconds
(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)
ok: [localhost]

PLAY [check bgp states] ********************************************************

TASK [check bgp peers states] **************************************************
ok: [fabric-02] => (item={u'local_address': u'192.168.1.2', u'as': 104, u'group': u'OC', u'address': u'192.168.1.1'})
ok: [fabric-01] => (item={u'local_address': u'192.168.1.1', u'as': 110, u'group': u'OC', u'address': u'192.168.1.2'})

TASK [check if junos devices learnt some routes with BGP] **********************
ok: [fabric-01] => (item={u'local_address': u'192.168.1.1', u'as': 110, u'group': u'OC', u'address': u'192.168.1.2'})
ok: [fabric-02] => (item={u'local_address': u'192.168.1.2', u'as': 104, u'group': u'OC', u'address': u'192.168.1.1'})

TASK [Send Slack notification to the team] *************************************
ok: [fabric-02 -> localhost]
ok: [fabric-01 -> localhost]

PLAY RECAP *********************************************************************
fabric-01                  : ok=5    changed=1    unreachable=0    failed=0
fabric-02                  : ok=5    changed=1    unreachable=0    failed=0
localhost                  : ok=1    changed=0    unreachable=0    failed=0

$ ls backup/
fabric-01_config.2016-11-14@16:57:20  fabric-02_config.2016-11-14@16:57:12
$ ansible-playbook pb.conf.bgp.oc.yaml --check --tags "configuration"

PLAY [create BGP Openconfig configuration] *************************************

TASK [Backup locally the config from the routers. Push on routers OC BGP config from templates, and commit.] ***
ok: [fabric-02]
ok: [fabric-01]

TASK [Send Slack notification to the team] *************************************
skipping: [fabric-01]
skipping: [fabric-02]

PLAY [wait for peers to establish BGP connections] *****************************

PLAY [check bgp states] ********************************************************

PLAY RECAP *********************************************************************
fabric-01                  : ok=1    changed=0    unreachable=0    failed=0
fabric-02                  : ok=1    changed=0    unreachable=0    failed=0
$ ansible-playbook pb.conf.bgp.oc.yaml --tags "audit"

PLAY [create BGP Openconfig configuration] *************************************

PLAY [wait for peers to establish BGP connections] *****************************

PLAY [check bgp states] ********************************************************

TASK [check bgp peers states] **************************************************
ok: [fabric-02] => (item={u'local_address': u'192.168.1.2', u'as': 104, u'group': u'OC', u'address': u'192.168.1.1'})
ok: [fabric-01] => (item={u'local_address': u'192.168.1.1', u'as': 110, u'group': u'OC', u'address': u'192.168.1.2'})

TASK [check if junos devices learnt some routes with BGP] **********************
ok: [fabric-01] => (item={u'local_address': u'192.168.1.1', u'as': 110, u'group': u'OC', u'address': u'192.168.1.2'})
ok: [fabric-02] => (item={u'local_address': u'192.168.1.2', u'as': 104, u'group': u'OC', u'address': u'192.168.1.1'})

TASK [Send Slack notification to the team] *************************************
ok: [fabric-02 -> localhost]
ok: [fabric-01 -> localhost]

PLAY RECAP *********************************************************************
fabric-01                  : ok=3    changed=0    unreachable=0    failed=0
fabric-02                  : ok=3    changed=0    unreachable=0    failed=0
  • pb.backup.yml - This playbook backups locally the configuration on the devices. It writes the configuration files of devices in the local directory backup
$ ansible-playbook pb.backup.yml
PLAY [make sure the directory backup exists] ***********************************

TASK [create a directory] ******************************************************
ok: [localhost]

PLAY [Collect configuration from devices] **************************************

TASK [Collect configuration from devices] **************************************
ok: [fabric-02]
ok: [fabric-01]

TASK [Save configuration to file in local directory] ***************************
ok: [fabric-01]
ok: [fabric-02]

TASK [Send Slack notification] *************************************************
ok: [fabric-01 -> localhost]
ok: [fabric-02 -> localhost]

PLAY RECAP *********************************************************************
fabric-01                  : ok=3    changed=0    unreachable=0    failed=0
fabric-02                  : ok=3    changed=0    unreachable=0    failed=0
localhost                  : ok=1    changed=0    unreachable=0    failed=0

$ cd backup
$ ls -l *.conf
-rw-rw-r-- 1 administrator administrator 7808 Nov 14 13:08 fabric-01.conf
-rw-rw-r-- 1 administrator administrator 7730 Nov 14 13:08 fabric-02.conf

  • pb.rollback.yml - This playbook rollbacks the configuration on the devices. The rollback id value (0 to 49) is a variable: You can pass extra variables definition when you execute a playbook. It writes the diff in the local directory rollback. It send slack notifications.
$ ansible-playbook pb.rollback.yml --extra-vars rbid=2

PLAY [Rollback configuration on junos devices] *********************************

TASK [Rollback junos configuration task] ***************************************
changed: [fabric-02]
changed: [fabric-01]

TASK [Send Slack notification to the team] *************************************
ok: [fabric-02 -> localhost]
ok: [fabric-01 -> localhost]

PLAY RECAP *********************************************************************
fabric-01                  : ok=2    changed=1    unreachable=0    failed=0
fabric-02                  : ok=2    changed=1    unreachable=0    failed=0

$ ls -l *.diff
-rw-rw-r-- 1 administrator administrator 872 Nov 14 17:02 fabric-01.diff
-rw-rw-r-- 1 administrator administrator 872 Nov 14 17:02 fabric-02.diff