Followers

Tuesday, April 10, 2018

Cisco ASR9K Configuration via Python , JINJA and YAML


Network Automation becomes a mandatory now and Network engineers should adapt themsleves to write a code.

I started  from more than a year  reading in multiple python libraries like paramiko , netmiko , napalm and Ciscoconfparse and i learned how to loop over devices to push and pop configuration from network devices  and parse the output via regex 
then i took a break for the CCIE SP and now am back again 😉 


This Article will go through : 
  1. What are the Network Devices Configuration Templates ?
  2. What are the methods to merge the variables of each device with the template ? 
  3. What are jinja and YAML ? 
  4.  Live example on generating configuration files for Cisco ASR9K devices by the use of jinja2 and YAML python libraries.  

What are the Network Devices Configuration Templates ?

Any Network device's configuration has a static part for each service 
for e.g. the ospf configuration in ASR9k is like the below 


==============================
router ospf  1
 log adjacency changes
 router-id 100.100.100.100
 area 0
  interface Loopback0
  !
  interface GigabitEthernet0/0/0/0
  !
  interface GigabitEthernet0/0/0/1
  !
  interface GigabitEthernet0/0/0/2
  !
  interface GigabitEthernet0/0/0/3
  !
 !
!
=========================================
   
you will find that find we have that always the variable part is the process id , router-id , area number and the interfaces. 

and the fixed part for sure the other things. 

Configuration templating means that we want to define the fixed part in a seperate place and the variable parts in another place. 

then merging them via a method. 

in that Case the fixed part will be the jinja file 
the variables of each devices will be defined in the YAML file. 


What are the methods to merge the variables of each device with the template ? 

 we have 2 methods to do that 

> via Python Code
> via Ansible module 
here in that post we will cover the python method and 
Ansible one will be covered in the coming post. 


What are jinja and YAML ? 

Jinja :

it is a Python library for creating configuration based on templates. Jinja2 defines a templating language with which templates are created. 

jinja files extensions  .j2 or .txt


YAML : 

YAML is a human friendly data serialization standard for all programming languages. It is not a markup language. It is more human-friendly compared to XML or JSON. Python has a YAML library to parse the YAML files into dictionaries. Once the dictionaries are created, these can be used to create the configuration from templates using Jinja2.

YAMl files extensions  .yml or .yaml
 
Now let's cut it short and go to the  example :

Prerequisites
  1. you have to install python on your system
  2. you have to install jinja2 and yaml libraries
 you should reach to the below status to complete  if you wanna practice the example.




Now you can go to your IDE or text editor  (Pycharm , Sublime , Atom , .... ) to create the project
which will consists of those files
  1. Devices_meta_data.yaml
  2. ASR9K-temlate.j2
  3. ASR9K-generate-config.py

    Python Code
    
    
    from jinja2 import Environment, FileSystemLoader
    import yaml
    import os
    
    
    with open("Devices_meta_data.yaml", 'r') as stream:
        Devices = (yaml.load(stream))
    
    THIS_DIR = os.path.dirname(os.path.abspath(__file__))
    print THIS_DIR
    j2_env = Environment(loader=FileSystemLoader(THIS_DIR), trim_blocks=True)
    
    
    for device, data in Devices.iteritems():
        configuration = j2_env.get_template('template.j2').render(data)
        with open(os.path.join(THIS_DIR, device + ".txt"), 'w') as config_file:
            config_file.write(configuration) 


    Click on the below photo to see it in your browser which declare what is happening at each part of the code.






















    Here is the YAML Code of 2 ASR9K devices at each one we are definning
    > hostname 
    > interfaces
    > ospf 
    > bgp 
    > mpls 

    To apply connectivity to the other routers at the topology ,
    for sure also we can do that for other ios routers but to make it simple here we applied that just for ASR9K devices.
















    YAML Code 


    ASR9K-1:
      hostname: XR1-0
      interfaces:
        loopback0:
          ipaddr: 100.100.100.100
          sm: 32
        GigabitEthernet0/0/0/0:
          ipaddr: 70.70.111.1
          sm: 24
        GigabitEthernet0/0/0/1:
          ipaddr: 70.70.112.1
          sm: 24
        GigabitEthernet0/0/0/2:
          ipaddr: 70.70.113.1
          sm: 24
        GigabitEthernet0/0/0/3:
          ipaddr: 70.70.114.1
          sm: 24
        GigabitEthernet0/0/0/4:
          ipaddr: 70.70.115.1
          sm: 24
        GigabitEthernet0/0/0/5:
          ipaddr: 70.70.100.1
          sm: 24
        GigabitEthernet0/0/0/6:
          ipaddr: 70.70.123.1
          sm: 24
    
      ospf:
        ospf_id: 100.100.100.100
        area : 0
        interfaces:
          - loopback0
          - GigabitEthernet0/0/0/0
          - GigabitEthernet0/0/0/1
          - GigabitEthernet0/0/0/2
          - GigabitEthernet0/0/0/3
          - GigabitEthernet0/0/0/4
          - GigabitEthernet0/0/0/5
          - GigabitEthernet0/0/0/6
      mpls:
        mpls_id: 100.100.100.100
        interfaces:
          - loopback0
          - GigabitEthernet0/0/0/0
          - GigabitEthernet0/0/0/1
          - GigabitEthernet0/0/0/2
          - GigabitEthernet0/0/0/3
          - GigabitEthernet0/0/0/4
          - GigabitEthernet0/0/0/5
          - GigabitEthernet0/0/0/6
      bgp:
        bgp_id: 100.100.100.100
        local_as: 1
        neighbors:
          ABR-1:
            neighbor_address: 11.11.11.11
            neighbor_as: 1
          ABR-2:
            neighbor_address: 12.12.12.12
            neighbor_as: 1
          ABR-31:
            neighbor_address: 13.13.13.13
            neighbor_as: 1
          ABR-32:
            neighbor_address: 23.23.23.23
            neighbor_as: 1
          ABR-4:
            neighbor_address: 14.14.14.14
            neighbor_as: 1
          ABR-5:
            neighbor_address: 15.15.15.15
            neighbor_as: 1
          ASBR1-0:
            neighbor_address: 10.10.10.10
            neighbor_as: 1
    
    ASR9K-2:
      hostname: XR2-0
      interfaces:
        loopback0:
          ipaddr: 200.200.200.200
          sm: 32
        GigabitEthernet0/0/0/0:
          ipaddr: 80.80.111.1
          sm: 24
        GigabitEthernet0/0/0/1:
          ipaddr: 80.80.112.1
          sm: 24
        GigabitEthernet0/0/0/2:
          ipaddr: 80.80.113.1
          sm: 24
        GigabitEthernet0/0/0/3:
          ipaddr: 80.80.114.1
          sm: 24
        GigabitEthernet0/0/0/4:
          ipaddr: 80.80.115.1
          sm: 24
        GigabitEthernet0/0/0/5:
          ipaddr: 80.80.100.1
          sm: 24
    
      ospf:
        ospf_id: 100.100.100.100
        area : 0
        interfaces:
          - loopback0
          - GigabitEthernet0/0/0/0
          - GigabitEthernet0/0/0/1
          - GigabitEthernet0/0/0/2
          - GigabitEthernet0/0/0/3
          - GigabitEthernet0/0/0/4
          - GigabitEthernet0/0/0/5
      mpls:
        mpls_id : 200.200.200.200
        interfaces:
          - loopback0
          - GigabitEthernet0/0/0/0
          - GigabitEthernet0/0/0/1
          - GigabitEthernet0/0/0/2
          - GigabitEthernet0/0/0/3
          - GigabitEthernet0/0/0/4
          - GigabitEthernet0/0/0/5
      bgp:
        bgp_id: 200.200.200.200
        local_as: 1
        neighbors:
          ABR-1:
            neighbor_address: 11.11.11.11
            neighbor_as: 1
          ABR-2:
            neighbor_address: 12.12.12.12
            neighbor_as: 1
          ABR-31:
            neighbor_address: 13.13.13.13
            neighbor_as: 1
          ABR-32:
            neighbor_address: 23.23.23.23
            neighbor_as: 1
          ABR-4:
            neighbor_address: 14.14.14.14
            neighbor_as: 1
          ABR-5:
            neighbor_address: 15.15.15.15
            neighbor_as: 1
          ASBR1-0:
            neighbor_address: 10.10.10.10
            neighbor_as: 1
    


    Hints about YAML  :
    - Begin any YAML file with ---
    - No TABs no TABs no TABs  just spaces.
    - Take Care of the indentation.

    let's Zoom in the YAML and what  if we wanna map it to python

    it's more better right ?  Not a lot of curl prackets and Commas.

    YAML
    Python
      ospf:
        ospf_id: 100.100.100.100
        area : 0
        interfaces:
          - loopback0
          - GigabitEthernet0/0/0/0
          - GigabitEthernet0/0/0/1
          - GigabitEthernet0/0/0/2
          - GigabitEthernet0/0/0/3
          - GigabitEthernet0/0/0/4
          - GigabitEthernet0/0/0/5
          - GigabitEthernet0/0/0/6
    {   'ospf': {   'area': 0,
                    'interfaces': [   'loopback0',
                                      'GigabitEthernet0/0/0/0',
                                      'GigabitEthernet0/0/0/1',
                                      'GigabitEthernet0/0/0/2',
                                      'GigabitEthernet0/0/0/3',
                                     'GigabitEthernet0/0/0/4',
                                      'GigabitEthernet0/0/0/5',
                                      'GigabitEthernet0/0/0/6'],
                    'ospf_id': '100.100.100.100'
                   }
    }

    So we will complete in the same manner each section of configuration for each device.

    Kepping in mind that all devices are exist in the Same YAML File.


    Now let's jump to the Jinja part . Jinja not Ninja 😉


    Jinja Code 

    hostname {{hostname}}
    {%if interfaces%}
    {%for intf , int_config in interfaces.items()%}
    interface {{intf}}
      ipv4 address {{int_config['ipaddr']}}/{{int_config['sm']}}
      no shutdown
    !
    {%endfor%}
    {%endif%}
    
    {%if ospf %}
    router ospf 1
      router-id {{ospf['ospf_id']}}
      area {{ospf['area']}}
    {%for ospf_intf in ospf['interfaces']%}
        interface {{ospf_intf}}
        !
    {%endfor%}
    {%endif%}
    
    {%if bgp %}
    router bgp {{bgp['local_as']}}
      bgp router-id {{bgp['bgp_id']}}
      address-family ipv4 unicast
      !
    {%for neighbor , neighbor_info in bgp['neighbors'].items()%}
      neighbor {{neighbor_info['neighbor_address']}}
       remote-as {{neighbor_info['neighbor_as']}}
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
    {%endfor%}
    {%endif%}
    
    
    {%if mpls %}
    mpls ldp
     router-id {{mpls['mpls_id']}}
     address-family ipv4
     !
    {%for interface in mpls['interfaces']%}
     interface {{interface}}
     !
    {%endfor%}
    !
    end
    {%endif%}
    

    Jinja file is simple just contain the fixed the part of the configuration and
    we are calling the variables in the YAML  ((accessing dictionaries)) which is in green colour in the above .

    also it is a normal text file with python conditional expressions and iteration embedded  in it

    like if and for  , but here it should be between {%   %} unlike Python.



    the below image shows now side by side both 3 files





    Finally after running the python code we will get the 2 Configuration files of both devices and they will appear in the place that we predefined in the python code.



    ASR9k-1
    ASR9k-2
    hostname XR1-0

    interface loopback0
      ipv4 address 100.100.100.100/32
      no shutdown
    !
    interface GigabitEthernet0/0/0/6
      ipv4 address 70.70.123.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/5
      ipv4 address 70.70.100.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/4
      ipv4 address 70.70.115.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/3
      ipv4 address 70.70.114.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/2
      ipv4 address 70.70.113.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/1
      ipv4 address 70.70.112.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/0
      ipv4 address 70.70.111.1/24
      no shutdown
    !

    router ospf 1
      router-id 100.100.100.100
      area 0
        interface loopback0
        !
        interface GigabitEthernet0/0/0/0
        !
        interface GigabitEthernet0/0/0/1
        !
        interface GigabitEthernet0/0/0/2
        !
        interface GigabitEthernet0/0/0/3
        !
        interface GigabitEthernet0/0/0/4
        !
        interface GigabitEthernet0/0/0/5
        !
        interface GigabitEthernet0/0/0/6
        !



    router bgp 1
      bgp router-id 100.100.100.100
      address-family ipv4 unicast
      !
      neighbor 10.10.10.10
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 15.15.15.15
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 14.14.14.14
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 13.13.13.13
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 12.12.12.12
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 11.11.11.11
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 23.23.23.23
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !


    mpls ldp
     router-id 100.100.100.100
     address-family ipv4
     !
     interface loopback0
     !
     interface GigabitEthernet0/0/0/0
     !
     interface GigabitEthernet0/0/0/1
     !
     interface GigabitEthernet0/0/0/2
     !
     interface GigabitEthernet0/0/0/3
     !
     interface GigabitEthernet0/0/0/4
     !
     interface GigabitEthernet0/0/0/5
     !
     interface GigabitEthernet0/0/0/6
     !
    !
    end

    hostname XR2-0

    interface loopback0
      ipv4 address 200.200.200.200/32
      no shutdown
    !
    interface GigabitEthernet0/0/0/5
      ipv4 address 80.80.100.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/4
      ipv4 address 80.80.115.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/3
      ipv4 address 80.80.114.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/2
      ipv4 address 80.80.113.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/1
      ipv4 address 80.80.112.1/24
      no shutdown
    !
    interface GigabitEthernet0/0/0/0
      ipv4 address 80.80.111.1/24
      no shutdown
    !





    router ospf 1
      router-id 100.100.100.100
      area 0
        interface loopback0
        !
        interface GigabitEthernet0/0/0/0
        !
        interface GigabitEthernet0/0/0/1
        !
        interface GigabitEthernet0/0/0/2
        !
        interface GigabitEthernet0/0/0/3
        !
        interface GigabitEthernet0/0/0/4
        !
        interface GigabitEthernet0/0/0/5
        !





    router bgp 1
      bgp router-id 200.200.200.200
      address-family ipv4 unicast
      !
      neighbor 10.10.10.10
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 15.15.15.15
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 14.14.14.14
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 13.13.13.13
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 12.12.12.12
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 11.11.11.11
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !
      neighbor 23.23.23.23
       remote-as 1
       update-source Loopback0
       address-family ipv4 unicast
        route-reflector-client
       !
      !
    !


    mpls ldp
     router-id 200.200.200.200
     address-family ipv4
     !
     interface loopback0
     !
     interface GigabitEthernet0/0/0/0
     !
     interface GigabitEthernet0/0/0/1
     !
     interface GigabitEthernet0/0/0/2
     !
     interface GigabitEthernet0/0/0/3
     !
     interface GigabitEthernet0/0/0/4
     !
     interface GigabitEthernet0/0/0/5
     !
    !
    end


    Hope that this example is clear and please if there is some thing not explained well let me know to clarify it in detail.

    Happy Labbing 😉

    Regards ,
    Mostafa Hassan Ahmed


    10 comments:

    1. Hi Amr,
      Nice article in that I liked. For consistency can You replace in this post in the python program "template.j2" with "ASR9K-temlate.j2" or just metion in the article that you are using "template.j2" in the place or "ASR9K-temlate.j2" wich have a missing "p" =)
      Hassan HBAR
      hassanhbar@gmail.com

      ReplyDelete
    2. Most people fear the essay exam because they are required to write about things they may not know, but actually the opposite is true ccnp 350 401 dumps. Essays are an opportunity to speak about what you do know. 

      ReplyDelete
    3. A recent IDC report sponsored by the Cisco Learning Institute reveals a huge networking skills gap is emerging in North America, which spells trouble for enterprises. Listen to this: "600,000 IT workers were needed to install Google Professional Cloud Architect Dumps, configure, manage and secure networks in North America in 2007, 14% of the total IT workforce.

      ReplyDelete
    4. Great write-up, I am a big believer in commenting on blogs to inform the blog writers know that they’ve added something worthwhile to the world wide web!.. Networking routers in Kenya

      ReplyDelete