A peek at network automation: using python, nornir, ntc_templates, and jinja2 to isolate devices in the same vlan

I started a journey to understand and get the most out of network automation with python; and I recently came accross nornir and ntc_templates. In this article, I'm going to share some things I find interesting to do with these tools.

1-   Our scenario:

Let’s say we have a network (obviously), with some printers in a dedicated vlan (vlan 200) which spans across multiple switches (or not). Printers (and usually end devices in a typical network) are not supposed to communicate with each other even if they are in the same vlan so we want to isolate them from one another while maintaining their vlan unchanged.

We are going to explore two ways of doing things

o  Configure each individual port of this vlan as a protected port

o  Configure the printers vlan to be a secondary isolated vlan (see private vlans)

In this post I will share how we can achieve our goal using the first option (protected ports).

2-   Our goal

Our goal is to configure every port in our target vlan(or vlans) on some switches while trying to automate the process as much as we can.

The python libraries I intend to use:

-         Nornir (https://nornir.readthedocs.io/en/latest/)

-         Ntc-templates (https://github.com/networktocode/ntc-templates)

3-   Our environment

My lab setup (on a windows 10 machine)

-         VMWare Player version 14.1.5 build-10950780

-         VMware-VIX-1.17.0-6661328

-         GNS3 version 2.2.3 with GNS3VM for vmware with 4vCPU and 4096MB of RAM

-         GNS3 images I used for this lab        

o  Virl ios Layer 2 qemu VM (vios_l2-adventerprisek9-m.SSA.high_iron_20180619.qcow2) with 2048MB memory, 2vCPU and 8 network adapters

o  A docker centos8 image (which is the latest version as of 1st feb 2020) built with the following commands inside the gns3vm

§ sudo docker pull centos

§ nano Dockerfile

FROM centos

RUN yum clean all

RUN yum groupinstall -y “Development tools”

RUN yum install -y openssh iputils python36

RUN python3 -m pip install nornir

RUN git clone https://github.com/networktocode/ntc-templates.git

§ sudo docker build -t toto/centostoto:nornir

o  I added the following environment variable in the gns3 centos docker template (go to ‘General settings’ tab) NET_TEXTFSM=/ntc-templates/templates

o  I also set /code as a persistent directory in the gns3 container template (advanced tab of the template)

Now let’s hope we’ll have fun.

1-   Our network topology and initial configuration

Aucun texte alternatif pour cette image

I’m using the same centos8 container image to simulate network printers

sw1 configuration

!!! we will need a priv 15 user and scp server to be enabled for NAPALM
ip scp server enable
username toto privilege 15 secret 0 toto
!!! vlan configuration
vtp mode transparent
vlan 100
name mgmt
vlan 200
name printers
exit
!!! interfaces configuration
interface GigabitEthernet0/0
 switchport access vlan 100
 switchport mode access
 no shutdown
!
interface GigabitEthernet0/1
 description Trunk to sw2
 switchport access vlan 200
 switchport trunk encapsulation dot1q
 switchport mode trunk
 no shutdown
!
interface GigabitEthernet0/2
 switchport access vlan 200
 switchport mode access
 no shutdown
!
interface GigabitEthernet1/1
 switchport mode access
 switchport access vlan 200
 no shutdown
!
interface GigabitEthernet1/2
 switchport mode access
 switchport access vlan 200
 shutdown
!
interface GigabitEthernet1/3
 switchport mode access
 switchport access vlan 100
 no shutdown
!!!!! SVIs configuration
interface Vlan100
 ip address 10.1.100.1 255.255.255.0
 no shutdown


interface Vlan200
 description Printers default gw
 ip address 10.1.200.1 255.255.255.0
 no shutdown
!
!!!!! ssh configuration
hostname sw1
ip domain-name toto.lab
crypto key generate rsa modulus 1024
ip ssh version 2
!!!! lines configuration
line con 0
 escape-character 3
line vty 0 15
 login local
 escape-character 3
!
!
end

sw2 configuration

!!! we will need a priv 15 user and scp server to be enabled for NAPALM
ip scp server enable
username toto2 privilege 15 secret 0 toto2
!!! vlan configuration
vtp mode transparent
vlan 100
name mgmt
vlan 200
name printers
exit
!!! interfaces configuration
interface GigabitEthernet0/1
 description Trunk to sw1
 switchport trunk encapsulation dot1q
 switchport mode trunk
 no shutdown
interface GigabitEthernet0/2
 switchport access vlan 200
 switchport mode access
 no shutdown
!!!!! SVIs configuration
interface Vlan100
 ip address 10.1.100.2 255.255.255.0
 no shutdown
!!!!! ssh configuration
hostname sw2
ip domain-name toto.lab
crypto key generate rsa modulus 1024
ip ssh version 2
!!!! lines configuration
line con 0
 escape-character 3
line vty 0 15
 login local
 escape-character 3
end

o  Preliminary verifications

Aucun texte alternatif pour cette image

Everything seems ok so far.

1-   Our action plan and script

-         This is what we’ll try to do with our python script

o  We are going to issue the command “show interfaces switchport” on each switch

o  Then we will extract the interfaces that satisfy two conditions:

§ Condition1 – The interface must be in static access mode

§ Condition2 – The interface belongs to vlan 200

o  And we are finally going to apply some commands to those interfaces. The configuration we are going to apply to each interface is obtained by rendering a jinja2 template

Let’s do that!

o  First of all we need to let nornir know about our network devices by providing an inventory in yaml format.

§  mkdir /code/inventory

§  vi /code/inventory/hosts.yaml

---
sw1:
   hostname: 10.1.100.1
   username: toto
   password: toto
   platform: ios
   groups:
      - switches
sw2:
   hostname: 10.1.100.2
   username: toto2
   password: toto2
   platform: ios
   groups:
      - switches

§ We want to group our switches so, we also need a groups.yaml file (vi /code/inventory/groups.yaml)

---

switches:

    data:

        domain: toto.lab

Now Let’s test and see if our inventory is good by initializing a nornir object in a python interactive session.

Aucun texte alternatif pour cette image

Our inventory seems good, so far. Now we’ll use netmiko_send_command module to issue “show interfaces switchport” and see what the result looks like for switch1. We are still in our interactive session.

from nornir.plugins.tasks import networking

result1=nr.run(task=networking.netmiko_send_command, command_string='show interfaces switchport')

result1['sw1'][0].result

type(result1['sw1'][0].result)
Aucun texte alternatif pour cette image

As we can see, without ntc_templates, we get all the output of our command as a single string. Trying, with only this string, to figure out which ports are in static access mode and belong to vlan 200, is a headache (at least for me). So TextFSM to the rescue!

Now let’s try with ntc_templates (use_textfsm=True) and see the difference.

result2=nr.run(task=networking.netmiko_send_command, command_string='show interfaces switchport', use_textfsm=True)

result2['sw1'][0].result

type(result2['sw1'][0].result)
Aucun texte alternatif pour cette image

We get a nice python list of dictionaries, which is simpler to use. Great!

Now that we know how to use ntc_templates (use_textfsm=True), we will create a jinja2 template file in which we will put de configuration commands we would like to apply to every port that satisfy our two conditions

o  mkdir /code/templates && vi /code/templates/interfaces_config.j2

{% for iface in interface_list %}

 

interface {{ iface }}

switchport protected

spanning-tree portfast

spanning-tree bpduguard enable

 

{% endfor %}

end

Now everything seems to be in place for our final code

o  vi toto.py

from nornir import InitNornir
from nornir.plugins.tasks import networking , text
from nornir.plugins.functions.text import print_result
from nornir.core.filter import F
import os


nr=InitNornir(
       core={"num_workers": 2},
       inventory={
          "plugin": "nornir.plugins.inventory.simple.SimpleInventory",
          "options": {
             "host_file": "/code/inventory/hosts.yaml",
             "group_file": "/code/inventory/groups.yaml",
          }
       }
    )


#we define a group of tasks


def interfaces_config(task, vlans_to_find):
    #Find interesting interfaces to configure
    r1 = task.run(task=networking.netmiko_send_command, command_string="show interfaces switchport", use_textfsm=True)
    interesting_interfaces = [ i['interface'] for i in r1.result if ((i['access_vlan'] in vlans_to_find) and (i['admin_mode'] == 'static access'))]
    if interesting_interfaces:
        #Generate config for inventoried host
        r = task.run(task=text.template_file, template='interfaces_config.j2', path='/code/templates', interface_list=interesting_interfaces)


        #Save config in a host variable
        task.host["intconfig"] = r.result


        #Deploy the interface configuration usin napalm
        task.run(task=networking.napalm_configure, name="Loading config to device", replace=False, configuration=task.host["intconfig"])






res=nr.run(task=interfaces_config, vlans_to_find=['200',])
print_result(res)

We run the script (python3 toto.py) and we cross fingers!

Aucun texte alternatif pour cette image

Nothing red on our screen, so it seems good but let’s verify things.

Aucun texte alternatif pour cette image

Printer1 can no longer ping printer2 BUT it can still reach printer3. In effect, the protected port feature is only meaningful to the local switch (Link).

It is the reason why our next step is to take a more global approach by implementing Private VLANs. But that is another story, and another article if God permits ??…


Sédjro AGBORAZE

Ingénieur Systèmes, Réseaux | IT Associate at Sun King

5 年

Great job !!!

回复
abdul amine bakpali

Certifications ICSI | CNSS, CCNP/CCNA, ZD

5 年

Hi Bro. thank you for this new way of resolving problems. I have read your work and it look like in Trunking configuration of SW1 at interface GigabitEthernet0/1 there as something to ajust (no switchport access vlan 200). My question is that. How will the packet flows in real production, at the end of implementing this solution?

回复
Dipankar Shaw

IP MPLS product/protocol Testing (Manual/Automation)

5 年

Well written Thierry DADANEMA

回复

要查看或添加评论,请登录

社区洞察

其他会员也浏览了