So verwenden Sie die Requests Library für Python auf Geräten, auf denen Junos OS ausgeführt wird
Die Anfragenbibliothek für Python ist auf bestimmten Geräten verfügbar, auf denen Junos OS ausgeführt wird und das Python-Erweiterungspaket unterstützt. Sie können das requests
Modul in Python-Skripten verwenden, um HTTP/1.1-Anforderungen zu senden. Auf Geräten, auf denen Junos OS mit erweiterter Automatisierung ausgeführt wird, können Sie das requests
Modul auch im interaktiven Python-Modus verwenden. Die Requests-Bibliothek bietet zusätzliche Methoden für die Unterstützung anfänglicher Bereitstellungen sowie für die Durchführung routinemäßiger Überwachung und Konfigurationsänderungen auf Geräten, auf denen Junos OS ausgeführt wird. Informationen zu dem requests
Modul und seinen Funktionen finden Sie in der Anforderungsdokumentation unter http://docs.python-requests.org/.
Anfragen stellen
Sie können das requests
Modul in Onbox-Python-Skripten verwenden, um HTTP/1.1-Anfragen zu senden. Um eine Anfrage zu stellen, importieren Sie das Modul in Ihr Skript und rufen die Funktion auf, die der gewünschten Anforderung entspricht. Das Modul unterstützt HTTP GET
und POST
Anfragen sowie HEAD
, DELETE
und PUT
Anforderungen. Die Anforderung gibt ein Response-Objekt zurück, das die Antwort des Servers enthält. Standardmäßig werden Anforderungen über die Standard-Routing-Instanz gestellt.
Die Requests-Bibliothek kann verwendet werden, um RPCs auf Geräten mit Junos OS auszuführen, die den REST-API-Service unterstützen. Das Zielgerät muss mit den entsprechenden Anweisungen auf Hierarchieebene [edit system services rest]
konfiguriert werden, um Junos OS-Befehle über HTTP oder HTTPS mit REST zu aktivieren.
Das folgende Op-Skript führt beispielsweise eine GET-Anforderung aus, die den get-software-information
RPC auf einem Remotegerät mit Junos OS ausführt, auf dem der REST API-Service über HTTP am Standardport (3000) konfiguriert ist. Das Skript gibt den Antwortstatuscode aus, und wenn der Statuscode den Erfolg anzeigt, gibt es den Antwortinhalt aus.
from junos import Junos_Context import jcs import requests user = Junos_Context['user-context']['user'] password = jcs.get_secret('Enter user password: ') r = requests.get('http://198.51.100.1:3000/rpc/get-software-information', auth=(user, password)) print (r.status_code) if (r.status_code == requests.codes.ok): print (r.text)
user@host> op show-version.py Enter user password: 200 <software-information> <host-name>router1</host-name> <product-model>mx240</product-model> <product-name>mx240</product-name> <junos-version>18.3R1.8</junos-version> <package-information> <name>os-kernel</name> ...
Um nur die Header abzurufen, können Sie eine einfache HEAD
Anfrage senden.
r = requests.head('http://198.51.100.1:3000/rpc/get-software-information', auth=(user, password)) print (r.headers) print (r.headers['content-type'])
user@host> op request-headers.py Enter user password: {'Date': 'Tue, 02 Apr 2019 18:30:58 GMT', 'Connection': 'close', 'Content-Type': 'application/xml; charset=utf-8', 'Server': 'lighttpd/1.4.48'} application/xml; charset=utf-8
Wenn für eine GET-Anforderung zusätzliche Parameter erforderlich sind, können Sie entweder das params
Argument einschließen und ein Wörterbuch oder eine Liste von Tupeln oder Bytes angeben, die in der Abfragezeichenfolge gesendet werden sollen, oder Sie können Schlüssel-Wert-Paare als Teil der URL übergeben. Ebenso können Sie benutzerdefinierte Header bereitstellen, indem Sie das headers
Argument und ein Wörterbuch mit HTTP-Headern angeben.
Die folgende Anforderung führt den get-interface-information
RPC mit der terse-Option für die angegebene Schnittstelle aus und gibt die Antwort im Textformat zurück:
headers={'content-type': 'application/xml', 'Accept': 'text/plain'} params={'interface-name':'ge-2/0/1', 'terse':''} r = requests.get('http://198.51.100.1:3000/rpc/get-interface-information', auth=(user, password), headers=headers, params=params)
Im folgenden Beispiel werden die Argumente als Schlüssel-Wert-Paare in der URL geliefert:
headers={'content-type': 'application/xml', 'Accept': 'text/plain'} rpc = 'get-interface-information?interface-name=ge-2/0/1&terse=' r = requests.get('http://198.51.100.1:3000/rpc/' + rpc, auth=(user, password), headers=headers)
Um mehrere RPCs in derselben Anforderung auszuführen, initiieren Sie eine HTTP POST-Anfrage und legen den data
Parameter fest, um auf die rpCs zu verweisen, die ausgeführt werden sollen. In den Abschnitten Ausführen von betrieblichen RPCs und Verwalten der Konfiguration finden Sie Beispiele für die Ausführung mehrerer RPCs.
Ausführen von betrieblichen RPCs
Sie können das requests
Modul verwenden, um RPCs aus der Junos XML-API auf einem Remotegerät mit Junos OS auszuführen, auf dem der REST-API-Service aktiviert ist.
Das folgende Op-Skript verwendet das requests
Modul, um das RPC-Äquivalent des Befehls für den show interfaces ge-2/0/1 terse
Betriebsmodus auf dem Zielgerät auszuführen:
from junos import Junos_Context import jcs import requests user = Junos_Context['user-context']['user'] password = jcs.get_secret('Enter user password: ') r = requests.get('http://198.51.100.1:3000/rpc/get-interface-information', auth=(user, password), params={'interface-name':'ge-2/0/1','terse':''}) print(r.text)
Das folgende Op-Skript sendet eine POST-Anforderung, die mehrere RPCs auf dem Zielgerät ausführt. Der data
Parameter verweist auf die auszuführenden RPCs, die zur Lesbarkeit in einer mehrlineigen Zeichenfolge definiert sind.
from junos import Junos_Context import jcs import requests user = Junos_Context['user-context']['user'] password = jcs.get_secret('Enter user password: ') headers={'content-type': 'application/xml', 'Accept': 'text/plain'} payload=""" <get-software-information/> <get-interface-information> <interface-name>ge-2/0/1</interface-name> </get-interface-information>""" r = requests.post('http://198.51.100.1/rpc/', auth=(user, password), headers=headers, data=payload) if (r.status_code == requests.codes.ok): print (r.text)
Sie können auch ein generisches Op-Skript erstellen, für das der Benutzer die erforderlichen Variablen und die Skriptkonstrukte liefert und die Anforderung ausführt. Betrachten Sie die folgende Op-Skriptkonfiguration, die die host
Argumente , rpc
und rpc_args
Befehlszeilenargumente für das requests-rpc.py Op-Skript konfiguriert:
[edit system scripts] op { file requests-rpc.py { arguments { host { description "host:port to which to connect"; } rpc { description "base RPC to execute on target device"; } rpc_args { description "dictionary of RPC arguments to use"; } } } } language python;
Das folgende Beispielskript verbindet sich mit einem Remotegerät mit Junos OS, das mit den entsprechenden Anweisungen auf [edit system services rest]
Hierarchieebene konfiguriert wurde, um Junos OS-Befehle über HTTP mithilfe von REST zu aktivieren. Das Skript fordert das Verbindungskennwort ein und verbindet sich mit dem Host und Port, die über das host
Argument bereitgestellt werden. Das Skript verwendet requests
das Modul dann, um eine GET-Anforderung zu senden, die den RPC ausführt, der über die Befehlszeilenargumente bereitgestellt wurde.
Ab Junos OS Version 21.2R1 und Junos OS Evolved Release 21.2R1 setzt das Gerät, wenn Befehlszeilenargumente an ein Python-Op-Skript weiterleitet, einen einzelnen Bindestrich (-) zu einstelligen Argumentnamen vor und präfixiert zwei Bindestriche (-) zu mehrzeichenigen Argumentnamen. In früheren Versionen präfixieren die Geräte allen Argumentnamen einen einzelnen Bindestrich (-).
# Junos OS Release 21.1 and earlier from junos import Junos_Context from ast import literal_eval import jcs import argparse import requests ## Argument list as configured in [edit system scripts op] arguments = { 'host': 'host:port to which to connect', 'rpc' : 'base RPC to execute on target device', 'rpc_args' : 'dictionary of RPC arguments to use' } ## Retrieve script arguments (Junos OS Release 21.1 and earlier) parser = argparse.ArgumentParser(description='This is a demo script.') for key in arguments: if key == 'rpc_args': parser.add_argument(('-' + key), help=arguments[key]) else: parser.add_argument(('-' + key), required=True, help=arguments[key]) args = parser.parse_args() ## Convert rpc_args to a dictionary if args.rpc_args is not None: args.rpc_args = literal_eval(args.rpc_args) ## Retrieve username and prompt for password for connecting to target device user = Junos_Context['user-context']['user'] password = jcs.get_secret('Enter user password: ') ## Execute RPC if args.rpc_args is None: r = requests.get('http://' + args.host + '/rpc/' + args.rpc, auth=(user, password)) else: r = requests.get('http://' + args.host + '/rpc/' + args.rpc, auth=(user, password), params=args.rpc_args) ## Print RPC contents if HTTP status code indicates success if (r.status_code == requests.codes.ok): print (r.text) else: print (r.status_code)
Wenn Sie das Skript ausführen, führt es den RPC mit den angegebenen Optionen auf dem Remotegerät aus und gibt die Antwort auf die Standardausgabe aus.
user@host> op requests-rpc.py host 198.51.100.1:3000 rpc get-interface-information rpc_args {'interface-name':'ge-2/0/1','terse':''} Enter user password: <interface-information xmlns="http://xml.juniper.net/junos/18.3R1/junos-interface" xmlns:junos="http://xml.juniper.net/junos/*/junos" junos:style="terse"> <physical-interface> <name>ge-2/0/1</name> <admin-status>up</admin-status> <oper-status>up</oper-status> </physical-interface> </interface-information>
Verwaltung der Konfiguration
Sie können das requests
Modul verwenden, um die Konfiguration auf einem Gerät mit Junos OS, auf dem der REST-API-Dienst aktiviert ist, abzurufen oder zu ändern.
Das folgende Op-Skript ruft die [edit system]
Hierarchie aus der Kandidatenkonfiguration mithilfe einer POST-Anforderung ab:
from junos import Junos_Context import jcs import requests user = Junos_Context['user-context']['user'] password = jcs.get_secret('Enter user password: ') headers = { 'content-type' : 'application/xml' } payload = '<get-configuration><configuration><system/></configuration></get-configuration>' r = requests.post('http://198.51.100.1:3000/rpc/', auth=(user, password), data=payload, headers=headers) print (r.content)
MIT HTTP POST-Anforderungen können Sie auch mehrere RPCs in einer einzigen Anforderung ausführen, z. B. zum Sperren, Laden, Commit und Entsperren einer Konfiguration.
Das folgende Beispielskript verbindet sich mit dem Remotegerät und konfiguriert eine Adresse auf der angegebenen Schnittstelle. Die Lock-, Load-, Commit- und Entsperrvorgänge werden aus Gründen der Lesbarkeit separat definiert, die RPCs jedoch in der Anfrage verkettt.
from junos import Junos_Context import jcs import requests user = Junos_Context['user-context']['user'] password = jcs.get_secret('Enter user password: ') #### lock, load, commit, unlock configuration headers={'content-type': 'application/xml'} lock = '<lock><target><candidate/></target></lock>' load = """<edit-config> <target><candidate></candidate></target> <default-operation>merge</default-operation> <config> <configuration> <interfaces> <interface> <name>ge-2/0/1</name> <unit> <name>0</name> <family> <inet> <address> <name>192.0.2.1/24</name> </address> </inet> </family> </unit> </interface> </interfaces> </configuration> </config> <error-option>stop-on-error</error-option> </edit-config>""" commit = '<commit/>' unlock = '<unlock><target><candidate/></target></unlock>' payload = lock + load + commit + unlock r = requests.post('http://198.51.100.1:3000/rpc/', auth=(user, password), headers=headers, data=payload) print(r.content)
Wenn Sie das Op-Skript ausführen, gibt es die RPC-Ergebnisse für die Sperr-, Last-, Commit- und Entsperrvorgänge zurück. Bei einigen Geräten trennt die Antwortausgabe die einzelnen RPC-Antworten durch Randzeilen, die gefolgt von einer Begrenzungszeichenfolge und einem Content-Type
Header enthalten--
. Andere Geräte enthalten möglicherweise nur den Content-Type
Header.
user@host> op requests-set-interface.py Enter user password: --harqgehabymwiax Content-Type: application/xml; charset=utf-8 <ok/> --harqgehabymwiax Content-Type: application/xml; charset=utf-8 <load-success/> --harqgehabymwiax Content-Type: application/xml; charset=utf-8 <commit-results xmlns:junos="http://xml.juniper.net/junos/*/junos"> <routing-engine junos:style="normal"> <name>re0</name> <commit-success/> <commit-revision-information> <new-db-revision>re0-1555351754-53</new-db-revision> <old-db-revision>re0-1555033614-52</old-db-revision> </commit-revision-information> </routing-engine> </commit-results> --harqgehabymwiax Content-Type: application/xml; charset=utf-8 <ok/> --harqgehabymwiax--
Verwenden von Zertifikaten in HTTPS-Anforderungen
Der grundlegende HTTP-Authentifizierungsmechanismus sendet Benutzeranmeldeinformationen als Base64-kodierte Klartextzeichenfolge. Um die Authentifizierungsnachweise vor Abhören zu schützen, empfehlen wir, den RESTful API-Service über HTTPS zu aktivieren, der die Kommunikation mit Transport Layer Security (TLS) oder Secure Sockets Layer (SSL) verschlüsselt. Informationen zur Konfiguration dieses Service finden Sie im Leitfaden zu Junos OS REST API.
Standardmäßig überprüft die Anforderungsbibliothek SSL-Zertifikate für HTTPS-Anforderungen. Sie können die Argumente und cert
die verify
Argumente in die Anforderung zur Steuerung der SSL-Überprüfungsoptionen einbeziehen. Ausführliche Informationen zu diesen Optionen finden Sie in der Dokumentation zu Anforderungen.
Wenn Sie Python 2.7 verwenden, um ein Skript auszuführen, das das requests
Modul zur Ausführung von HTTPS-Anforderungen verwendet, generiert InsecurePlatformWarning
und SubjectAltNameWarning
warnt das Skript.
Das folgende Op-Skript sendet eine GET-Anforderung über HTTPS und legt das verify
Argument auf den Dateipfad eines CA-Pakets oder eines Verzeichnisses mit vertrauenswürdigen CA-Zertifikaten fest. Die angegebenen CA-Zertifikate werden verwendet, um das Zertifikat des Servers zu überprüfen.
from junos import Junos_Context import jcs import requests user = Junos_Context['user-context']['user'] password = jcs.get_secret('Enter user password: ') r = requests.get('https://198.51.100.1:3443/rpc/get-software-information', auth=(user, password), verify='path-to-ca-bundle') print (r.status_code) if (r.status_code == requests.codes.ok): print (r.text)
Um ein lokales clientseitiges Zertifikat anzugeben, legen Sie das Argument gleich dem cert
Pfad einer einzelnen Datei, die den privaten Schlüssel und das Zertifikat des Clients enthält, oder auf ein Tupel fest, das die Pfade des einzelnen Clientzertifikats und der Privaten Schlüsseldateien enthält.
r = requests.get('https://198.51.100.1:3443/rpc/get-software-information', auth=(user, password), verify='path-to-ca-bundle', cert=('path-to-client-cert','path-to-client-key')
Festlegen der Routing-Instanz
Standardmäßig werden Anfragen mit der Standard-Routing-Instanz ausgeführt. Sie können Anforderungen auch über die mgmt_junos
Verwaltungsinstanz oder eine andere nicht standardmäßige Routing-Instanz ausführen. Wenn Sie Skripte über die Junos OS-Infrastruktur ausführen, können Sie die Routing-Instanz angeben, indem Sie die set_routing_instance()
Funktion im Skript aufrufen. Bestimmte Geräte unterstützen auch das Festlegen der Routing-Instanz und die Ausführung eines Skripts in der Shell auf Unix-Ebene.
Auf Geräten mit Junos OS Evolved unterstützt die Funktion nur die set_routing_instance()
Verwendung der Management-Routing-Instanz.
Um eine Anforderung in einem Python-Skript mit einer nicht standardmäßigen Routinginstanz auszuführen, einschließlich der mgmt_junos
Instanz:
Das folgende Op-Skript verwendet die mgmt_junos
Verwaltungsinstanz, um eine Verbindung mit dem Zielgerät herzustellen und Anforderungen auszuführen.
from junos import Junos_Context import jcs import requests user = Junos_Context['user-context']['user'] password = jcs.get_secret('Enter user password: ') jcs.set_routing_instance('mgmt_junos') r = requests.get('http://198.51.100.1:3000/rpc/get-software-information', auth=(user, password)) print (r.text)
Informationen zur Verwendung der set_routing_instance()
Funktion in Python-Skripten finden Sie unter set_routing_instance().
Zusätzlich zur Angabe der Routing-Instanz im Skript unterstützen bestimmte Geräte die Festlegung der Routing-Instanz und die Ausführung eines Skripts aus der Shell auf Unix-Ebene. Auf Geräten, auf denen Junos OS mit erweiterter Automatisierung (FreeBSD-Version 7.1 oder höher) ausgeführt wird, können Sie mit dem setfib
Befehl Anfragen mit der jeweiligen Routing-Instanz ausführen, einschließlich der Verwaltungsinstanz und anderer nicht standardmäßiger Routing-Instanzen.
Das folgende Python-Skript führt den get-software-information
RPC einfach auf einem Remotegerät aus und gibt die Antwort aus:
#!/usr/bin/env python import requests from getpass import getpass user = raw_input ('Enter username: ') password = getpass('Enter password: ') r = requests.get('http://198.51.100.1:3000/rpc/get-software-information', auth=(user, password)) print (r.text)
So führen setfib
Sie das Skript mit einer nicht standardmäßigen Routing-Instanz auf einem Gerät aus, auf dem Junos OS mit erweiterter Automatisierung ausgeführt wird:
Suchen Sie den Softwareindex, der der Routingtabelle für diese Instanz zugeordnet ist.
Im folgenden Beispiel wird das Gerät so konfiguriert, dass es die nicht standardmäßig dedizierte Verwaltungsinstanz
mgmt_junos
verwendet. Der Routingtabellenindex wird in der Befehlsausgabe referenziert.user@host> show route forwarding-table extensive table mgmt_junos Routing table: mgmt_junos.inet [Index 36738] Internet: Enabled protocols: Bridging, Destination: default Route type: permanent Route reference: 0 Route interface-index: 0 Multicast RPF nh index: 0 P2mpidx: 0 Flags: none Next-hop type: reject Index: 340 Reference: 1
Um das Op-Skript mit der angegebenen Routing-Instanz auszuführen, verwenden Sie den
setfib
Befehl, um das Skript auszuführen und auf den Index zu verweisen. Zum Beispiel:user@host> start shell % setfib -F36738 python /var/db/scripts/op/request-software-info.py
Im folgenden Beispiel wird das Gerät mit einer nicht standardmäßigen Routing-Instanz vr1 konfiguriert, und der Routingtabellenindex vr1.inet ist 8:
user@host> show route forwarding-table extensive table vr1 Routing table: vr1.inet [Index 8] Internet: Enabled protocols: Bridging, All VLANs, Destination: default Route type: permanent Route reference: 0 Route interface-index: 0 Multicast RPF nh index: 0 P2mpidx: 0 Flags: sent to PFE Next-hop type: reject Index: 592 Reference: 1
Der folgende Befehl führt das Op-Skript mithilfe der Routing-Instanz vr1 aus:
% setfib -F8 python /var/db/scripts/op/request-software-info.py
Durchführung von ZTP-Vorgängen
Die vollständig automatisierte Bereitstellung (Zero Touch Provisioning, ZTP) ermöglicht ihnen die automatische Bereitstellung neuer Geräte von Juniper Networks in Ihrem Netzwerk mit minimalem manuellen Eingriff. Um ZTP zu verwenden, konfigurieren Sie einen Server so, dass er die erforderlichen Informationen bereitstellt, die ein Junos OS-Image und eine Konfigurationsdatei zum Laden oder ein Skript zur Ausführung enthalten können. Wenn Sie ein Gerät physisch mit dem Netzwerk verbinden und es mit einer werksseitigen Standardkonfiguration starten, ruft das Gerät die Informationen vom designierten Server ab, aktualisiert das Junos OS-Image je nach Bedarf und führt das Skript aus oder lädt die Konfigurationsdatei.
Wenn Sie eine Verbindung herstellen und ein neues Netzwerkgerät starten, wird die erste Zeile der Datei untersucht, wenn Junos OS eine Datei auf dem Server erkennt. Wenn Junos OS die Zeichen #! gefolgt von einem Interpreter-Pfad, behandelt die Datei als Skript und führt sie mit dem angegebenen Interpreter aus. Sie können die Anfragenbibliothek in ausgeführten Skripten verwenden, um den ZTP-Prozess zu optimieren.
Betrachten Sie beispielsweise das folgende Python-Beispielskript, das das neue Gerät während des ZTP-Prozesses herunterlädt und ausführt. Wenn das Skript ausgeführt wird, lädt es zuerst das CA-Zertifikat vom Speicherort auf dem angegebenen Server herunter ca_cert_remote
und speichert es lokal im ca_cert_local
Speicherort. Das Skript verbindet sich dann mit dem Konfigurationsserver auf Port 8000 und gibt eine GET-Anforderung aus, um die neue Gerätekonfiguration abzurufen. Die Anforderung enthält den Pfad zum CA-Zertifikat, das zur Überprüfung des Serverzertifikats während des Austauschs verwendet wird. Das Skript verwendet dann die Junos PyEZ-Bibliothek, um die Konfiguration auf das Gerät zu laden und zu bestätigen.
#!/usr/bin/python import os import paramiko import requests from jnpr.junos import Device from jnpr.junos.utils.config import Config # Define the servers storing the certificate and configuration host_cert = '198.51.100.1' host_config = '192.0.2.1' username = 'admin' password = 'secret123' # Define CA certificate file locations ca_cert_remote = '/u01/app/myCA/certs/rootCA.crt' ca_cert_local = '/var/tmp/rootCA.crt' # Retrieve the CA certificate from the server ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(hostname=host_cert, username=username, password=password) sftp = ssh.open_sftp() sftp.get(ca_cert_remote, ca_cert_local) sftp.close() ssh.close() # Retrieve the configuration from the server uri = 'https://' + host_config + ':8000/' config = requests.get(uri, auth=(username, password), verify=ca_cert_local) # Load and commit the configuration on the device with Device() as dev: cu = Config(dev) cu.load(config.text, format='text', overwrite=True) cu.commit()