Junos PyEZ am Beispiel der Aufgabe, freie ipv4-Subnetze zu finden

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“ - alles, was wir lieben. Das Schreiben des in diesem Artikel beschriebenen Skripts verfolgte mehrere Ziele - Lernen von Python und Automatisieren der Aufgaben des Sammelns von Informationen oder Ändern von Konfigurationen auf Geräten, auf denen Junos OS ausgeführt wird. Die Wahl dieses speziellen Python + Junos PyEZ-Pakets wurde aufgrund des niedrigen Schwellenwerts für die Eingabe der Python-Programmiersprache und der einfachen Verwendung der Junos PyEZ-Bibliothek getroffen, für die keine Junos OS-Kenntnisse erforderlich sind.

Herausforderung


Prüfung firmeneigener IPv4-freier Subnetze. Das Kriterium, dass das Subnetz frei ist, ist das Fehlen eines Datensatzes in den Routen auf dem Switch, der als Router mit Junos OS fungiert.

Implementierung


Python + Junos PyEZ, obwohl die Versuchung bestand, dies mit paramiko und ssh.exec_command zu tun, Infolgedessen muss das Netzwerkverwaltungsprotokoll für netconf-Geräte auf den überwachten Geräten konfiguriert werden. Netconf arbeitet mit Geräten über einen Remote Procedure Call (RPC) und verwendet in diesem Beispiel XML, um die empfangenen Informationen bereitzustellen.

Die Installation der aktuellen Version von Junos PyEZ über PyPI wird mit dem folgenden Befehl ausgeführt:

$ pip install junos-eznc 

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

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

Und noch eine Option durch

 $ pip install -r requirements.txt 

Dieser Befehl installiert die Bibliotheken, die für die im System nicht vorhandenen Arbeiten erforderlich sind. In meiner Version von requirements.txt gibt es nur zwei davon, die letzten Versionen sind zum Zeitpunkt des Schreibens des Skripts angegeben:

 junos-eznc netaddr 

Das Standard-Skript verwendet den Namen des aktuellen Benutzers im System. Sie können sich mit dem Schlüssel show_route.py -u <Benutzername> unter dem Namen eines anderen Benutzers anmelden. Getpass.getpass akzeptiert das Kennwort von stdin, sodass das Kennwort nicht im System verbleibt. Um eine Verbindung zum Gerät herzustellen, müssen Sie auf Anfrage auch dessen Hostnamen oder IP-Adresse eingeben. Alle für die Autorisierung auf dem Gerät erforderlichen Daten wurden empfangen.

Junos PyEZ unterstützt die Verbindung zu Geräten, auf denen Junos OS ausgeführt wird, über die Konsole, Telnet oder Netconf über ssh. Der Artikel betrachtet die letzte Option.

Für den Anschluss an das Gerät wird die Geräteklasse des Moduls jnpr.junos verwendet

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

Über alle Routen, die dem Router durch einen Remoteprozeduraufruf oder einen Aufruf von Remoteprozeduren bekannt sind, für die dies praktischer ist, wird eine Anfrage gestellt.

 data = dev.rpc.get_route_information() 

Ein ähnlicher Befehl unter Junos OS

 user@router> show route | display xml 

Wenn Sie rpc am Ende des Befehls hinzufügen, erhalten wir das Anforderungs-Tag und können es mit dem Namen der RPC-Methode abgleichen. Auf diese Weise können Sie andere interessante Namen herausfinden. Es ist erwähnenswert, dass sich die Syntax zum Schreiben eines Anforderungs-Tags vom Methodennamen unterscheidet, dh Bindestriche durch Unterstriche ersetzen.

 user@router> show route | display xml rpc <rpc-reply xmlns:junos="http://xml.juniper.net/junos/15.1R1/junos"> <rpc> <get-route-information> </get-route-information> </rpc> </rpc-reply> 

Ich habe die Routendaten im XML-Format erhalten, von denen ich nur diejenigen ausgewählt habe, die mich mit dem Tag <rt-destination> xxx.xxx.xxx.xxx/yy </ rt-destination> interessieren, und habe sie in eine Variable als Liste im Zeichenfolgenformat geschrieben, um eine Liste zu erhalten ausgelastete Subnetze.

 route_list = data.xpath("//rt-destination/text()") 

Ich habe den Rest in eine while-Schleife eingeschlossen, um die Anforderung an den Router nicht erneut auszuführen, wenn ich ein anderes Subnetz als dasjenige überprüfen muss, das der Router bereits kennt. Es ist erwähnenswert, dass der Router, auf dem ich angefordert habe, die Routen nur über OSPF kennt. Daher ist es für den Grenzrouter besser, die Anforderung ein wenig zu ändern, um die Skriptausführungszeit 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 nicht mehr als drei Oktetten aus dem Netzwerk desselben Subnetzes einzugeben. Dies ist erforderlich, um den Suchbereich festzulegen. Ich mag diese Implementierung des Einstellens der Kriterien und des Suchbereichs nicht wirklich, aber bisher habe ich keine bessere Lösung gefunden. Als nächstes wähle ich aus der erhaltenen Liste von route_list-Subnetzen unter Verwendung einer Variablen, die nicht mehr als drei Oktette enthält, die für mich interessanten Subnetze aus

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

Über IPNetwork, das netaddr-Modul, erhalte ich Subnetze als Liste von IPv4-Adressen

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

Unter Verwendung von IPNetwork aus dem vom Benutzer mit der Maske eingegebenen Netzwerk erhalte ich einen Adressbereich und bilde 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) 

Ich leite die erhaltene Liste der freien Adressen in Form von Subnetzen ab

 print(netaddr.IPSet(freeip)) 

Unten finden Sie das vollständige Skript, das auf Switches getestet wurde, die als Router der Modelle ex4550 und ex4600 verwendet werden

 #!/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'^%s\S*' % 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: https://habr.com/ru/post/de481648/


All Articles