Search This Blog

Saturday 16 January 2021

Nornir get ntp associations status

 The below script will connect to Cisco network devices and collect "show ntp associations" using Nornir and will parse the data using genie.

The result will look like this:

R1 uses NTP Server: 10.0.0.1 which is: synchronized
R2 uses NTP Server: 10.0.0.2 which is: synchronized


from nornir import InitNornir
from nornir.plugins.functions.text import print_result
from nornir.plugins.tasks.networking import netmiko_send_command
from nornir.plugins.tasks.files import write_file
from nornir.core.exceptions import NornirExecutionError
import csv, pprint
from datetime import datetime

def dev_info(task):
    try:
        r = task.run(netmiko_send_command, command_string="show ntp associations"use_genie=True)
        task.host["facts"] = r.result
        ntp_server = task.host["facts"]["clock_state"]["system_status"]["associations_address"]
        ntp_status = task.host["facts"]["clock_state"]["system_status"]["clock_state"]
        print(f"{task.host} uses NTP Server: " + ntp_server + " which is: " + ntp_status)
    except:
        print(f"{task.host} had some kind on unknown issue")

def main() -> None:
    nr = InitNornir(config_file="config.yml")
    result = nr.run(task=dev_info)
    #print_result(result)

if __name__ == "__main__":
    main()

Python regex to extract IP addresses from text file

 If you need to extract IP Addresses from a text file with thousands or even millions of lines of text and you have something better to do than do this manually, the below script is your friend.

Device IP Address=        Not really regex, just simple text finding

(?P<NAS>\w+\.\w+\.\w+\.\w+)    This is where it becomes interesting. <NAS> is creating s a variable for the IP Address matched by the regex. \w+ matches any word character (equal to [a-zA-Z0-9_])

import re
for line in open("acs-logs-concatenated.txt""r"):
    m = re.compile("Device IP Address=(?P<NAS>\w+\.\w+\.\w+\.\w+)")
    print(re.findall(m, line))

Python concatenate text files

 If you, like me, had to extract logs in the form of multiple files and then extract specific information out of it then the below python script will show you how to read text files from a folder, open each file one by one then saving the contents to a new concatenated file containing all of the contents from all the text files.


from os import walk
f = []
for (dirpath, dirnames, filenames) in walk("acslogs"):
    f.extend(filenames)
    break
print(f)
with open("acs-logs-concatenated.txt""w"as outfile:
    for fname in f:
        with open("acslogs/" + fname) as infile:
            for line in infile:
                outfile.write(line)

Thursday 14 January 2021

Nornir uptime and version check

This script uses Nornir 2.5 and genie to return structured data and check for devices uptime and validate software versions.

from nornir import InitNornir

from nornir.plugins.tasks.networking import netmiko_send_command, netmiko_send_config

from nornir.plugins.functions.text import print_result

import os

from rich import print


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


nr.inventory.defaults.username = os.environ["NORNIR_USER"]

nr.inventory.defaults.password = os.environ["NORNIR_PASS"]


def structured_test(task):

    r = task.run(task=netmiko_send_command, command_string="show version", use_genie=True)

    task.host["facts"] = r.result

    uptime = task.host["facts"]["version"]["uptime"]

    version = task.host["facts"]["version"]["version"]

    hostname = task.host["facts"]["version"]["hostname"]

    #print("The uptime of " + hostname + " is " + uptime)

    print(f"{task.host} running version " + version + " has been up for " + uptime)

    if version > "15.4":

        print(f"{task.host}: [green]PASSED[/green]")

    else:

        print(f"{task.host}: [red]FAILED VERSION CHECK[/red]")


result = nr.run(task=structured_test)

Use virtual environment for testing + requirements.txt

 It recommended to use a virtual environment for testing. All software and libraries installed in the virtual environment will be used if they exist, then the software/libraries on the host OS will be used.


python3 -m venv TestingLab

source bin/activate

pip3 install -r requirements.txt


Example of requirement.txt file

nornir==2.5 

python-gnupg==0.4.6

pyats==20.12

genie==20.12.2

ipdb==0.13.4

rich==9.8.1

ntc-templates==1.6.0

Use Environment variables in Python script

 This avoids using clear text user/pass in the code. While the user/pass are not encrypted they are stored on the local device where the script is running on.

Edit the bashrc file and add the key value pairs; location doesn't matter:

nano ~/.bashrc

export NORNIR_USERNAME="cisco"

export NORNIR_PASSWORD="cisco"

To use these variable in the python code (nornir 2.5) add the following:

nr.inventory.default.username = os.environ["NORNIR_USERNAME"]

nr.inventory.default.password = os.environ["NORNIR_PASSWORD"]

 That's it!

GPG Encryption for Python scripts

Install GPG:

pip3 install python3-gnupg

Generate key and provide name, email and passphrase:

gpg --gen-key

 Create a text file:

nano creds.txt

DEFAULT_USERNAME=cisco

DEFAULT_PASSWORD=cisco

(Ctrl+O to save, then Enter) 

Encrypt the file:

gpg --symmetric -o encrypted.env.gpg creds.txt

 To decrypt the file:

gpg --decrypt encrypted.env.gpg

To flush the password cache:

echo RELOADAGENT | gpg-connect-agebt

OK

When you decrypt the file again you will be prompted for the passphrase.

To use this file in Nornir 2.5 use these variables in the code:

nr.invetory.defaults.username = os.getenv("DEAFAULT_USERNAME")

nr.invetory.defaults.password = os.getenv("DEAFAULT_PASSWORD")

To execute the python script using the encrypted file use:

env $(gpg --decrypt encrypted.env.gpg) python3 encrypted-showipintbrief.py

Nornir Compliance Check