Table of Contents

Network automation data structure for separating data and configuration is what we discuss in this module.

Each configuration has some data that may be different or the same between devices. SNMP community, IP address of NTP servers, network addresses in EIGRP configuration and IP address and AS number of neighbors in BGP configuration are some examples of data in network automation.

How to store and access the data of the configuration of various network devices is what we call network automation data structure

In this section, we use inventory files to store and access the configuration data as well.

But in the next section we will store and access data of configurations via its own specific data structure.

Network Automation Data Structure (Store and Access)

In network automation, it is always interesting and recommended to create and keep automation code, configuration template and configuration data in three different data types. What we have so far mostly not complied with.

Netowrk Automation Code Components
Netowrk Automation Code Components

Automation code can be cretead with any automation tool such as Python or Ansible. Python programming language with nornir library is the tool that we use throughout this course to create automation codes.

In this course, we will also learn how to completely separate the device configurations from network automation using the jinja2 template.

In the next course, YANG based network automation, we will learn how to remove configuration component altogether from network automation which makes the automation vendor agnostic.

However, the subject of this section is to keep configuration data separate from the configuration itself. In this section, we use existing inventory files to also store network device configuration data, although not recommended.

But in the next section, we will use a separate data structure to store network device configuration data.

Store Configuration Data in Inventory Files

To start adding data to inventory files, remember that we have three main inventory files, hosts.yaml, groups.yaml, and default.yaml.

Structure of inventory files
Structure of inventory files

Just like inventory information, data common to all devices are added in defaults.yaml, data common to devices within a group are added in groups.yaml, and finally data unique to each device are added to the hosts.yaml inventory files.

When adding the same data with different values in different inventory files, the data in hosts.yaml is preferred over groups.yaml and groups.yaml is also preferred over defaults.yaml

Data is added to inventory files in the format of YAML by adding a new key called “data“.

Data is added in one of two data structure formats, dictionary or list.

To better understand, I have already prepared some data inside inventory files.

First, let’s examine the “hosts.yaml” inventory file, where we store data which is unique to each device.

majid@majid-ubuntu:~/devnet/pyhton_nornir/2023/4.configuration_data$ cat hosts.yaml
---

R1:
  hostname: "192.168.1.11"
#  username: "rayka"
#  password: "rayka-co.com"
  groups:
    - router
  data:
    eigrp_as: 1
    eigrp_networks:
      - 192.168.1.0 0.0.0.255
      - 192.168.2.0 0.0.0.255
R2:
  hostname: "192.168.1.12"
#  username: "rayka"
#  password: "rayka-co.com"
  groups:
    - router
  data:
    eigrp_as: 1
    eigrp_networks:
      - 192.168.2.0 0.0.0.255
      - 192.168.3.0 0.0.0.255

S1:
  hostname: "192.168.1.13"
  username: "RAYKA"
  password: "RAYKA-CO.COM"
  groups:
    - switch
  data:
    eigrp_as: 1
    eigrp_networks:
      - 192.168.3.0 0.0.0.255
      - 192.168.4.0 0.0.0.255

As you can see, three devices are added in hosts.yaml. Two of those named R1 and R2 are routers and members of the “router” group and one named S1 is a switch and a member of the “switch” group.

Data unique to each device is added by adding a dictionary key “data”.

All data is added in dictionary format with a “key:value” pair. Value cab be any type, a number, a string or even a list.

In our example, EIGRP AS number and a list if networks are configured for each device. As you can see, the list of networks is different for each device and therefore needs to be configured in the hosts.yaml inventory file.

But EIGRP AS number is the same for all devices and could be configured in the groups.yaml or even in the defaults.yaml inventory file. I added EIGRP AS number in hosts.yaml because in the future we will probably have some devices with a different EIGRP AS number.

In the groups.yaml inventory file, SNMP community is added for each group since all devices in the same group have the same SNMP community, but the SNMP community of routers and switches is different.

majid@majid-ubuntu:~/devnet/pyhton_nornir/2023/4.configuration_data$ cat groups.yaml
---

router:
  platform: ios
  data:
    community: router_comunity

switch:
  platform: junos
  data:
    community: switch_community

And finally inside defaults.yaml, the IP address of NTP server is given since it is common in all devices.

majid@majid-ubuntu:~/devnet/pyhton_nornir/2023/4.configuration_data$ cat defaults.yaml
---

username: "rayka"
password: "rayka-co.com"
platform: "ios"

data:
  ntp_server: 1.1.1.1

Access Configuration Data from Inventory Files

Now the question is how to access data through python code stored in inventory files?

To access data in Nornir, regardless of the type of task you are running on devices, you can use “task.host” to access the root of the data dictionary structure for each device on which the task is running.

Depending on the type of data value, which is a simple value or a list, you can then access it from your Python code just like any other dictionary or list.

from nornir import InitNornir
from nornir_utils.plugins.functions import print_result

nr = InitNornir(config_file="config.yaml")

def access_configuration_data_via_inventory_files(task):
    print("###########################################")
    print("eigrp AS number of device ", task.host, " is ", task.host['eigrp_as'])
    for network in task.host['eigrp_networks']:
      print("eigrp network of device ", task.host, " is: ", network)

    print("community of device ", task.host, " is ", task.host['community'])

    print("ntp server address of device ", task.host, " is ", task.host['ntp_server'])

results = nr.run(task=access_configuration_data_via_inventory_files)
print("###########################################")
print_result(results)

For example, as you can see in the Python code, to access the EIGRP AS number of each device, we have used task.host[‘eigrp_as’]). To access the SNMP community of each device, we have used task.host[ ‘ community’]) and to access the IP address of the NTP server we used task.host[‘ntp_server’]).

But to access the list of networks in EIGRP we used a “for loop” like traversing any other list along with task.host[‘eigrp_networks’].

Now let’s run the script to see the result of the script.

Just to see clean output of running script, I modified the Nornir config file to only process one device at a time. Otherwise, data values for different devices are printed between each other and it was not easy to read.

majid@majid-ubuntu:~/devnet/pyhton_nornir/2023/4.configuration_data$ cat config.yaml
---

inventory:
  plugin: SimpleInventory
  options:
    host_file: "hosts.yaml"
    group_file: "groups.yaml"
    defaults_file: "defaults.yaml"

runner:
  plugin: threaded
  options:
    num_workers: 1
majid@majid-ubuntu:~/devnet/pyhton_nornir/2023/4.configuration_data$ python3 4.1.access_configuration_data_via_inventory_files.py
###########################################
eigrp AS number of device  R1  is  1
eigrp network of device  R1  is:  192.168.1.0 0.0.0.255
eigrp network of device  R1  is:  192.168.2.0 0.0.0.255
community of device  R1  is  router_comunity
ntp server address of device  R1  is  1.1.1.1
###########################################
eigrp AS number of device  R2  is  1
eigrp network of device  R2  is:  192.168.2.0 0.0.0.255
eigrp network of device  R2  is:  192.168.3.0 0.0.0.255
community of device  R2  is  router_comunity
ntp server address of device  R2  is  1.1.1.1
###########################################
eigrp AS number of device  S1  is  1
eigrp network of device  S1  is:  192.168.3.0 0.0.0.255
eigrp network of device  S1  is:  192.168.4.0 0.0.0.255
community of device  S1  is  switch_community
ntp server address of device  S1  is  1.1.1.1
###########################################
access_configuration_data_via_inventory_files***********************************
* R1 ** changed : False ********************************************************
vvvv access_configuration_data_via_inventory_files ** changed : False vvvvvvvvvv INFO
^^^^ END access_configuration_data_via_inventory_files ^^^^^^^^^^^^^^^^^^^^^^^^^
* R2 ** changed : False ********************************************************
vvvv access_configuration_data_via_inventory_files ** changed : False vvvvvvvvvv INFO
^^^^ END access_configuration_data_via_inventory_files ^^^^^^^^^^^^^^^^^^^^^^^^^
* S1 ** changed : False ********************************************************
vvvv access_configuration_data_via_inventory_files ** changed : False vvvvvvvvvv INFO
^^^^ END access_configuration_data_via_inventory_files ^^^^^^^^^^^^^^^^^^^^^^^^^
Back to: CLI based Network Automation using Python Nornir > Make Configuration Data and Configuration Itself Seperate in Nornir

Leave a Reply

Your email address will not be published. Required fields are marked *


Post comment