Junos PyEZ am Beispiel der Aufgabe der Suche nach freien IPv4-Subnetzen

Ein Artikel über die Arbeit mit Junos PyEZ – „Python-Mikroframework, mit dem Sie Geräte verwalten und automatisieren können, auf denen Junos OS ausgeführt wird“ – Automatisierung und Verwaltung, alles, was wir lieben. Das Schreiben des in diesem Artikel beschriebenen Skripts hatte mehrere Ziele – das Erlernen von Python und die Automatisierung von Aufgaben zum Sammeln von Informationen oder Ändern von Konfigurationen auf Geräten, auf denen Junos OS ausgeführt wird. Die Wahl dieser speziellen Kombination aus Python + Junos PyEZ wurde aufgrund der geringen Einstiegshürde in die Programmiersprache Python und der Benutzerfreundlichkeit der Junos PyEZ-Bibliothek getroffen, die keine Expertenkenntnisse von Junos OS erfordert.

Aufgabe

Prüfung der freien IPv4-Subnetze des Unternehmens. Das Kriterium dafür, dass ein Subnetz frei ist, ist das Fehlen eines Eintrags darüber in den Routen auf dem Switch, der als Router mit Junos OS fungiert.

Implementierung

Python + Junos PyEZ, obwohl die Versuchung bestand, dies über paramiko und ssh.exec_command zu tun, Daher müssen Sie das Netconf-Gerätenetzwerkverwaltungsprotokoll auf dem abgefragten Gerät konfigurieren. Netconf arbeitet mit der Hardware über den Remote-Prozeduraufruf RPC und verwendet in diesem Beispiel XML, um die empfangenen Informationen bereitzustellen.

Die Installation der aktuellen Version von Junos PyEZ von PyPI erfolgt mit dem folgenden Befehl:

$ pip install junos-eznc

Sie können mit dem folgenden Befehl auch vom Hauptzweig des Projekts auf GitHub installieren:

$ pip install git+https://github.com/Juniper/py-junos-eznc.git

Und noch eine Option über

$ pip install -r requirements.txt 

Dieser Befehl installiert Bibliotheken, die im System fehlen und für den Betrieb notwendig sind. In meiner Version requirements.txt Es gibt nur zwei davon, die neuesten Versionen sind zum Zeitpunkt des Schreibens des Skripts angegeben:

junos-eznc
netaddr

Standardmäßig übernimmt das Skript den Namen des aktuellen Benutzers im System; Sie können sich mit dem Schlüssel show_route.py -u unter dem Namen eines anderen Benutzers anmelden getpass.getpass übernimmt das Passwort von stdin, sodass das Passwort nicht im System verbleibt. Um eine Verbindung zum Gerät herzustellen, müssen Sie bei entsprechender Aufforderung auch seinen Hostnamen oder seine IP-Adresse eingeben. Alle für die Autorisierung auf dem Gerät notwendigen Daten wurden empfangen.

Junos PyEZ unterstützt die Verbindung mit Geräten, auf denen Junos OS ausgeführt wird, über die Konsole, Telnet oder Netconf über SSH. Der Artikel diskutiert die letztere Option.

Um eine Verbindung zu Geräten herzustellen, verwenden Sie die Device-Klasse des jnpr.junos-Moduls

with jnpr.junos.Device(host=router,
                           user=args.name,
                           passwd=password) as dev:

Es werden alle dem Router bekannten Routen per Remote Procedure Call oder Remote Procedure Call abgefragt, je nachdem, was bequemer ist.

data = dev.rpc.get_route_information()

Ähnlicher Befehl unter Junos OS

user@router> show route | display xml

Durch das Hinzufügen von rpc am Ende des Befehls erhalten wir ein Anforderungs-Tag und können es mit dem Namen der RPC-Methode abgleichen. Auf diese Weise können wir andere interessante Namen herausfinden. Es ist zu beachten, dass sich die Syntax zum Schreiben des Anforderungs-Tags vom Methodennamen unterscheidet. Sie sollten nämlich die Bindestriche durch Unterstriche ersetzen.

user@router> show route | display xml rpc
<rpc-reply >route_list = data.xpath("//rt-destination/text()")

Der Rest des Teils wurde in eine While-Schleife eingeschlossen, um die Anfrage an den Router nicht zu wiederholen, wenn es notwendig wäre, ein anderes Subnetz einzuchecken als diejenigen, die der Router bereits kennt. Es ist erwähnenswert, dass der Router, auf dem ich die Anfrage stelle, Routen nur über OSPF kennt. Bei einem Edge-Router ist es daher besser, die Anfrage ein wenig zu ändern, um die Laufzeit des Skripts zu verkürzen

data = dev.rpc.get_ospf_route_information()

Schauen wir uns nun den Inhalt der while-Schleife an

Zu Beginn wird der Benutzer aufgefordert, ein Subnetz mit einer Maske und maximal drei Oktetten aus dem Netzwerk desselben Subnetzes einzugeben. Dies ist erforderlich, um den Suchbereich festzulegen. Diese Implementierung der Angabe der Kriterien und des Suchbereichs gefällt mir nicht wirklich, aber ich habe bisher keine bessere Lösung gefunden. Als nächstes wähle ich aus der resultierenden Liste der Subnetze route_list mithilfe einer Variablen, die nicht mehr als drei Oktette enthält, die Subnetze aus, die mich interessieren

tmp = re.search(r'^%sS*' % subnet_search, route_list[i])

Über IPNetwork, das netaddr-Modul, erhalte ich Subnetze in Form einer Liste von IPv4-Adressen

range_subnet = netaddr.IPNetwork(tmp.group(0))

Mit IPNetwork erhalte ich einen Adressbereich aus einem vom Benutzer eingegebenen Netzwerk mit einer Maske und erstelle eine Liste aller Adressen aus diesem Bereich zum Vergleich mit der Liste der belegten Adressen.

for i in set(net_list).difference(set(busyip)):
        freeip.append(i)

Die resultierende Liste der freien Adressen zeige ich in Form von Subnetzen an

print(netaddr.IPSet(freeip))

Nachfolgend finden Sie das vollständige Skript, getestet auf Switches, die als Router verwendet werden, Modelle ex4550, ex4600


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import getpass
import netaddr
import re
import sys

import jnpr.junos

parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user',
                    action='store',
                    dest='name',
                    help='Enter login from tacacs if it differs from the '
                         'username in the system.')
args = parser.parse_args()

if not args.name:
    args.name = getpass.getuser()    # Return the “login name” of the user.
router = input("Full routers name: ")
password = getpass.getpass("Password: ")

try:
    # Authenticates to a device running Junos, for get information about routs
    # into xml format and selects by tag.
    route_list = []
    with jnpr.junos.Device(host=router,
                           user=args.name,
                           passwd=password) as dev:
        data = dev.rpc.get_route_information()
    route_list = data.xpath("//rt-destination/text()")
except (jnpr.junos.exception.ConnectRefusedError,
        jnpr.junos.exception.ConnectUnknownHostError) as err:
    print("Equipment name or password wrong.")
    sys.exit(1)

while True:
    subnet = input("Net with mask: ")
    subnet_search = input("Input no more three octet: ")
    # Gets a list of busy IP addresses from the received subnets.
    busyip = []
    for i in range(len(route_list)):
        tmp = re.search(r'^%sS*' % subnet_search, route_list[i])
        if tmp:
            range_subnet = netaddr.IPNetwork(tmp.group(0))
            for ip in range_subnet:
                busyip.append("%s" % ip)
    range_subnet = netaddr.IPNetwork(subnet)
    # Gets list ip adresses from subnetworks lists.
    net_list = []
    for ip in range_subnet:
        net_list.append("%s" % ip)
    # Сomparing lists.
    freeip = []
    for i in set(net_list).difference(set(busyip)):
        freeip.append(i)
    print(netaddr.IPSet(freeip))

    request = input("To run request again enter yes or y, "
                    "press 'enter', complete request: ")
    if request in ("yes", "y"):
        continue
    else:
        print('Bye')
        break

Source: habr.com

Kommentar hinzufügen