image

Scrapli #1

Python script som gör upprepande och enkla uppgifter är toppen! Scriptet gör att utfallet alltid blir vad man säger åt det att genomföra. I den här posten använder jag Scrapli . Scrapli är perfekt för att lära sig grunderna i python och automatisering vilket gör det perfekt för mig. Det är dessutom enkelt och smidigt att komma igång med. Dokumentationen på deras sida, LINK, är lätt att förstå.

Värt att nämna är att Scrapli officiellt inte har stöd för att användas på Windows. Jag använder därför Ubuntu på WSL.

Syftet med det här scriptet är att inventera vilka ip-helpers som används runt om i organisationen. Scriptet loggar in på varje switch, kollar om ett interface har L3 konfigurerat samt om den har en IP-Helper. Skulle båda förutsättningarna stämma kommer IP-helpern att skrivas ut.

TLDR: Vill du inte läsa igenom hela posten kan du bläddra ner längst ner på sidan för att läsa igenom scriptet.

Låt oss börja!

Det vi behöver för att komma igång är att, förutom ha Python, installera scrapli.

pip install scrapli
pip install scrapli[genie]

När Python och scrapli är installerat kan vi börja.

För att python ska ha en möjlighet att använda scrapli behöver modulen först importeras till vårt script. Vi importerar här modulen för IOSXEDrivers samt modulen os för att interagera med operativsystemet.

Vi börjar med att lägga till följande två rader högst upp i vårt script.

from scrapli.driver.core import IOSXEDriver
import os

Vi vill skapa en lista med all utrustning som scriptet ska köras mot.

devices = [
    "10.xx.zzz.nn", #Site1
    "10.xy.zzz.nn", #Site2
    "10.xz.zzz.nn" #Site3
   ]

Vi skapar två stycken varibler där våra användarnamn och lösenord lagras. Här hämtas uppgifterna från en system varibel som lagrats i operativsystemet.

#Användarnamn och lösenord för inlogg mot utrustningen som ska konfigureras. Datat kan sparas som ett systemvariable i OS så slipper den finnas i klartext i koden.
username = os.environ.get("USER")
password = os.environ.get("PASS")

För att lagra ett värde i en systemvariabel kan man göra följande och sedan ropa på dom inifrån python scriptet.

image

Nu behöver vi skapa en Dictionary’n som innehåller en del av den information som ska köras på respektive switch. Dictionary’n innehåller i det här skedet inloggningsuppgifter och den metod som används för transport. Som default används ssh på port 22. Senare kommer vi även addera utrustningen som kommandona ska köras på.

credentials = {
    "auth_username": username,
    "auth_password": password,
    "auth_strict_key": False,
}

Ibland har man tyvärr otur och fortfarande har utrustning som använder telnet som transport och då behöver det specificeras i Dictionary’n.

credentials = {
    "auth_username": username,
    "auth_password": password,
    "auth_strict_key": False,
    "transport": "telnet", #Ifall utrustningen inte har stöd för SSH behöver du speca vilken transport som ska användas
    "port": 23,  # Porten måste specificeras ifall telnet används
}

Nu har vi i gjort grunden för att vi ska komma igång med att ansluta till våra enheter. I och med att vi vill logga in på flera switchar behöver vi loopa igenom listan devices som skapades tidigare. Följande kodblock visar hela logiken i scriptet.

for device in devices:
    interfacesList = []
    connection = credentials
    connection["host"] = device

    print("----------------------------------------")
    print(f"Connecting to switch {device}")
    print("----------------------------------------")

    with IOSXEDriver(**connection) as conn:
        #Skicka "show ip interface brief" kommando till switchen.
        showIpInt = conn.send_command(f'show ip interface brief')
        
        #gå igenom svaret med genie för att få en resultat som är strukturerat
        showIpIntParsed = showIpInt.genie_parse_output()

        #Samla in all interface i en lista från showIpIntParsed
        for interfaces in showIpIntParsed["interface"]:
            interfacesList.append(interfaces)
        
        #iterate över alla interfaces i listan interfacesList
        for interfaceslisted in interfacesList:

            #Kolla om interfacet i listan interfacesList har L3 konfiguration
            if showIpIntParsed["interface"][interfaceslisted]["ip_address"] != "unassigned":

                #Skickar kommandot "show running-config interface INTERFACE
                showRunInt = conn.send_command(f'show running-config interface {interfaceslisted}')

                #Genie kunde inte känna igen ip helper i resultatet så jag var tvungen att få ut datat på annorlunda vis
                showRunIntResult = showRunInt.result

                #Ser om interfacet har strängen "helper address" i sig
                if "helper-address" in showRunIntResult:

                    #Skapar en lista utan showRunIntResult. Varje ny rad kommer bli ett object i listan. Vi använder /n för att visa att den ska splitta vid ny rad
                    showRunIntResultList = showRunIntResult.split("\n")

                    #iterate över varje rad och skriver ut ip-helper configurationen
                    for configRows in showRunIntResultList:
                        if "ip helper-address" in configRows:
                            print(configRows)

Vid en närmare titt i kodblocket ovan har en print placerats i början av loopen för att se vilken switch som scriptet jobbar på.

interfacesList = [] skapar en lista där vi kommer lagra interfacen som finns i respektive switch. De här listan kommer nollställas varje gång loopen börjar om.

connection = credentials sparar inloggningsuppgifterna i en ny dictionary.

connection["host"] = device sparar ip adressen för enheten vi ansluter till i vår dictionary med keyn “host”.

for device in devices:
    interfacesList = []
    connection = credentials
    connection["host"] = device

    print("----------------------------------------")
    print(f"Connecting to switch {device}")
    print("----------------------------------------")

För att öppna en anslutning mot switchen behöver vi börja använda scrapli, det görs med with IOSXEDriver(**connection) as conn:. I våra kommande kommandon som skickas till utrustningen kommer vi nyttja conn som en variabel.

with IOSXEDriver(**connection) as conn:skapar en anslutning till switchen

showIpInt = conn.send_command(f'show ip interface brief')skickar show kommandot show ip interface brief till switchen och lagrar resultatet i variablen showIpInt

För att vi ska kunna använda resultatet vi får tillbaka på ett enklare sätt kommer vi använda oss av genie. Genie fungerar kanon för att strukturera data som kommer tillbaka från utrustningen.

    with IOSXEDriver(**connection) as conn:
        #Skicka "show ip interface brief" kommando till switchen.
        showIpInt = conn.send_command(f'show ip interface brief')
        
        #gå igenom svaret med genie för att få en resultat som är strukturerat
        showIpIntParsed = showIpInt.genie_parse_output()

Med hjälp av listan interfacesList som vi fyllt på med interfaces kommer vi nu undersöka vilka interface i den listan som faktiskt innehåller en IP-address. Det tar jag reda på genom att se vilka interface som inte har unassigned som adress.

När vi fått svar på om ett interface inte innehåller unassigned, alltså har en IP-adress går vi vidare och kör show running-config interface {interfaceslisted} där interfaceslisted är det interface som har en IP adress konfigurerad, eller i det här fallet inte har unassigned.

Jag upptäckte att Genie inte lyckades sortera ut IP-helper ur resultatet och var därför tvungen strukturera datat på ett annat sätt - som är lite omständingare och det görs med hjälpa av .result

        #iterate över alla interfaces i listan interfacesList
        for interfaceslisted in interfacesList:

            #Kolla om interfacet i listan interfacesList har L3 konfiguration
            if showIpIntParsed["interface"][interfaceslisted]["ip_address"] != "unassigned":

                #Skickar kommandot "show running-config interface INTERFACE
                showRunInt = conn.send_command(f'show running-config interface {interfaceslisted}')

                #Genie kunde inte känna igen ip helper i resultatet så jag var tvungen att få ut datat på annorlunda vis
                showRunIntResult = showRunInt.result

Det strukturerade datat vi fått fram med hjälp av .result har sparats som en string i showRunIntResult. Vi kan därför se om stringen innehåller stringen helper-address. Om stringen innehåller helper-address skapar vi en lista av varje rad av resultatet. Listan går nu att loopa över varje rad och vi kan därför matcha på dom rader som innehåller ip helper-address och då skriva ut den raden i konsolen.

                #Ser om interfacet har strängen "helper address" i sig
                if "helper-address" in showRunIntResult:

                    #Skapar en lista utan showRunIntResult. Varje ny rad kommer bli ett object i listan. Vi använder /n för att visa att den ska splitta vid ny rad
                    showRunIntResultList = showRunIntResult.split("\n")

                    #iterate över varje rad och skriver ut ip-helper configurationen
                    for configRows in showRunIntResultList:
                        if "ip helper-address" in configRows:
                            print(configRows)

Här har vi resultatet av scriptet:

image Här är scriptet i sin helhet.

from scrapli.driver.core import IOSXEDriver
import os

#Lista med enheter som ska kommandon ska köras på, listan kommer itereras vid senare tillfälle
devices = [
    "10.xx.zzz.nn", #Site1
    "10.xy.zzz.nn", #Site2
    "10.xz.zzz.nn" #Site3
   ]

#Användarnamn och lösenord för inlogg mot utrustningen som ska konfigureras. Datat kan sparas som ett systemvariable i OS så slipper den finnas i klartext i koden.
username = os.environ.get("USER")
password = os.environ.get("PASS")

credentials = {
    "auth_username": username,
    "auth_password": password,
    "auth_strict_key": False,
    "transport": "telnet", #Ifall utrustningen inte har stöd för SSH behöver du speca vilken transport som ska användas
    "port": 23,  # Porten måste specificeras ifall telnet används
}


for device in devices:
    interfacesList = []
    connection = credentials
    connection["host"] = device

    print("----------------------------------------")
    print(f"Connecting to switch {device}")
    print("----------------------------------------")

    with IOSXEDriver(**connection) as conn:
        #Skicka "show ip interface brief" kommando till switchen.
        showIpInt = conn.send_command(f'show ip interface brief')
        
        #gå igenom svaret med genie för att få en resultat som är strukturerat
        showIpIntParsed = showIpInt.genie_parse_output()

        #Samla in all interface i en lista från showIpIntParsed
        for interfaces in showIpIntParsed["interface"]:
            interfacesList.append(interfaces)
        
        #iterate över alla interfaces i listan interfacesList
        for interfaceslisted in interfacesList:

            #Kolla om interfacet i listan interfacesList har L3 konfiguration
            if showIpIntParsed["interface"][interfaceslisted]["ip_address"] != "unassigned":

                #Skickar kommandot "show running-config interface INTERFACE
                showRunInt = conn.send_command(f'show running-config interface {interfaceslisted}')

                #Genie kunde inte känna igen ip helper i resultatet så jag var tvungen att få ut datat på annorlunda vis
                showRunIntResult = showRunInt.result

                #Ser om interfacet har strängen "helper address" i sig
                if "helper-address" in showRunIntResult:

                    #Skapar en lista utan showRunIntResult. Varje ny rad kommer bli ett object i listan. Vi använder /n för att visa att den ska splitta vid ny rad
                    showRunIntResultList = showRunIntResult.split("\n")

                    #iterate över varje rad och skriver ut ip-helper configurationen
                    for configRows in showRunIntResultList:
                        if "ip helper-address" in configRows:
                            print(configRows)

Consultant


2025

Acebit expanderar

1 minute read

Acebit expanderar – automationsess från Dalarna öppnar i Stockholm

Back to Top ↑

2024

Acebit i Falu-Kuriren

less than 1 minute read

Även Falu-Kuriren har intresserat sig för Acebit och besökt oss i Falun!

Back to Top ↑

2023

Meraki API & Mgmt interface

4 minute read

Nyligen stötte jag på ett scenario som innebar att ca 200 Meraki-enheter behövde byta inställning från DHCP till statisk IP-adressering. Istället för att gör...

Arbeta med VPC Del3 - Konfiguration

3 minute read

I mina tidigare inlägg om virtuella port-channels kikade vi på vad det är och vilka delar de utgör. Det här avsnittet kommer beröra hur en grundkonfiguration...

Få upp farten med concurrency

3 minute read

Bakgrund Idag tänkt jag skriva några rader om att skriva concurrent kod, eller “samtidighet” om vi prompt ska översätta det till svenska. För att enklare för...

Back to Top ↑

2022

Back to Top ↑

2021

Back to Top ↑