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,
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