Tierney - stock.adobe.com
Netzwerkautomatisierung mit Paramiko, Netmiko und NAPALM
Python lässt sich mit Automatisierungs-Frameworks wie Paramiko, Netmiko und NAPALM perfekt zur Netzwerkautomation nutzen. Unser Vergleich zeigt deren Stärken und Schwächen.
Python ist die am häufigsten genutzte Programmiersprache für Netzwerkautomatisierung, eignet sich aber nicht ohne Weiteres für alle Aufgaben. Zum Glück haben einige motivierte Anwender Bibliotheken erstellt, die sich um viele Details der Netzwerkautomatisierung mit Python kümmern. Diese Automatisierungsbibliotheken erleichtern es Nutzern, Automationssysteme zu erstellen.
Benutzer, die erste Schritte im Bereich Automatisierung unternehmen, sollten zunächst Grundkenntnisse der Skriptsprache Python und der Datenstrukturen wie Listen, Tuples, Wörterbücher und Sets erwerben. Zudem empfiehlt sich ein grundlegendes Verständnis der Templating-Sprache Jinja2 und von YAML (YAML Ain't Markup Language). Nutzern steht ein leistungsstarkes Automatisierungs-Framework zur Verfügung, wenn sie Python für Scripting, Jinja2 für Templating, YAML zur Datendarstellung und die nachfolgenden Automatisierungsbibliotheken miteinander kombinieren.
Automatisierungsbibliotheken
Netzwerkautomation mithilfe von Python und Automatisierungsbibliotheken kann eine einfache Kommunikation mit Netzwerkgeräten ermöglichen. In diesem Artikel werfen wir einen Blick auf drei Bibliotheken für die Netzwerkautomatisierung: Paramiko, Netmiko und NAPALM (Network Automation Programmability Abstraction Layer with Multivendor support). Jede Bibliothek baut auf ihrem Vorgänger auf, um bessere Abstraktionsschichten bereitzustellen, mit denen Nutzer effizientere Automationssysteme erstellen können.
Paramiko
Paramiko ist eine Low-Level-Client-Bibliothek für Secure Shell (SSH). Wir können sie nutzen, um programmgesteuert den Aufbau einer Verbindung mit der Befehlszeile (Command-line Interface, CLI) eines Netzwerkgeräts über eine sichere SSH-Verbindung zu kontrollieren. Mit der Bibliothek senden Nutzer Befehle, die jemand normalerweise eingeben würde, und parsen die Ergebnisse jeder Befehlsausführung, was auch als Screen Scraping bezeichnet wird.
Das folgende Python-Skript verwendet die Paramiko-Bibliothek, um die ARP-Tabelle (Address Resolution Protocol) von einem Cisco-Router des Typs Catalyst 3560 abzufragen. Es ist der erste Schritt eines Skripts, um den Switch Port zu identifizieren, mit dem ein Gerät verbunden ist.
01) #!/usr/bin/env python3
02) import sys
03) from time import sleep
04) import paramiko
05) router="192.168.1.108"
06)
07) # Create an ssh connection and set terminal length 0
08) conn = paramiko.SSHClient()
09) conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
10) conn.connect(router, username="tester", password="foobar")
11) router_conn = conn.invoke_shell()
12) print('Successfully connected to %s' % router)
13) router_conn.send('terminal length 0\n')
14) sleep(1) # Wait for the cmd to be sent and processed
15)
16) # Send the command and wait for it to execute
17) router_conn.send("show arp\n")
18) sleep(2)
19)
20) # Read the output, decode into UTF-8 (ASCII) text, and print
21) print(router_conn.recv(5000).decode("utf-8"))
Die Zeilen eins bis fünf importieren die zusätzlichen Bibliotheken, die wir benötigen, und legen die IP-Adresse des Routers fest, den wir abfragen wollen. Die Zeilen sieben bis 14 bauen eine SSH-Verbindung zum Router auf und melden sich mit dem Namen tester und dem Passwort foobar an. Dann wird ein Kommando gesendet, um die Ausgabepaginierung zu deaktivieren. Die Zeilen 16 bis 18 senden den Befehl show arp, während Zeile 21 das Befehlsergebnis liest und ausgibt. Die Verbindung wird geschlossen, wenn das Skript endet.
So sieht das Resultat aus:
01) $ ./paramiko-example.py
02) Successfully connected to 192.168.1.108
03)
04) test-sw>terminal length 0
05) test-sw>show arp
06) Protocol Address Age (min) Hardware Addr Type Interface
07) Internet 192.168.1.1 1 0025.9c1a.4c89 ARPA Vlan1
08) Internet 192.168.1.3 0 0c84.dcc4.8569 ARPA Vlan1
09) Internet 192.168.1.108 - bcc4.933e.49c0 ARPA Vlan1
10) Internet 192.168.1.141 0 4c32.7596.b70b ARPA Vlan1
11) test-sw>
Paramiko bietet eine Low-Level-SSH-Schnittstelle für Netzwerkgeräte. Viele Parameter, die abhängig vom Gerätemodell variieren, werden im Skript codiert, einschließlich Änderungen in der Befehlssyntax für verschiedene Betriebssysteme.
Außerdem müssten wir uns um alle Details der Datenerfassung, Durchführung von Konfigurationsänderungen und der Verifizierung dieser Änderungen selbst kümmern. Um eine Konfigurationsänderung vorzunehmen, müssten wir jeden einzelnen Schritt des Vorgangs managen – Zugriff aktivieren, Konfigurationsmodus aufrufen, Änderungen übermitteln und Änderungen speichern. Zum Glück übernehmen andere Frameworks, wie Netmiko, den Großteil dieser Arbeit für uns.
Netmiko
Die Netmiko-Bibliothek hilft Nutzern, viele Details der gängigen Funktionen für die Gerätekommunikation zu verbergen. Die Library verwendet Paramiko zur Low-Level-SSH-Konnektivität, bietet aber eine größere Abstraktion der Kommunikation mit einer Vielzahl unterschiedlicher Netzwerkgeräte. Netmiko unterstützt eine breite Palette von Geräten, und das Netmiko-Skript ist um einiges kürzer als das Paramiko-Pendant, wie folgend zu sehen ist.
01) #!/usr/bin/env python3
02) import sys
03) from time import sleep
04) from netmiko import ConnectHandler
05) dev={
06) 'device_type': 'cisco_ios',
07) 'host': '192.168.1.108',
08) 'username': 'tester',
09) 'password': 'foobar',
10) } # Use a dictionary to pass the login parameters
11)
12) # Connect to the device
13) router_conn = ConnectHandler(**dev)
14)
15) # Send the command and print the result
16) print(router_conn.send_command("show arp\n"))
Die Zeilen eins bis vier importieren zunächst die notwendigen Module. Dann wird mit den Zeilen fünf bis 10 ein Python-Wörterbuch erstellt, das die Verbindungsparameter für dieses Gerät enthält. Anwender, die mit vielen Geräten arbeiten, benötigen zusätzlichen Code, den sie über die Geräte iterieren. Das lässt sich einfach mit einer Liste von Wörterbüchern erreichen. Die Geräteverbindung erfolgt in einer anschließenden Zeile, während die letzte Zeile den Befehl abschickt und das Ergebnis ausgibt.
Nach Entfernen der Geräte-Prompts ist die Ausgabe von Netmiko ebenfalls kürzer:
01) $ ./netmiko-example.py
02) Protocol Address Age (min) Hardware Addr Type Interface
03) Internet 192.168.1.1 1 0025.9c1a.4c89 ARPA Vlan1
04) Internet 192.168.1.3 0 0c84.dcc4.8569 ARPA Vlan1
05) Internet 192.168.1.108 - bcc4.933e.49c0 ARPA Vlan1
06) Internet 168.1.141 0 4c32.7596.b70b ARPA Vlan1
Netmiko hat die device_type-Definition verwendet, um die Kommunikation mit dem Gerät richtig zu managen, so dass wir nichts mit den gerätespezifischen Aufgaben zu tun haben. Zwar ermöglicht es Netmiko den Nutzern, Gerätekommandos zu senden und die Antworten zu erhalten, automatisiert allerdings nicht die Konfigurationsverwaltung. An dieser Stelle kommt NAPALM ins Spiel.
NAPALM
NAPALM baut auf Netmiko auf und bietet einen Mechanismus für die Interaktion mit Gerätekonfigurationen. Die Bibliothek unterstützt weniger Geräte als Netmiko: Arista, Juniper und Cisco (IOS, IOS XR, NX-OS und NX-OS SSH). Sie unterstützt aber auch eine Reihe von getter-Funktionen, die grundlegende Gerätedaten abfragen. Das folgende Skript nutzt die get_arp_table()-Funktion:
01) #!/usr/bin/env python3
02) import sys
03) import time
04) import napalm
05) import os
06) import json
07) dev_type = 'ios'
08) dev_creds={
09) 'hostname': '192.168.1.108',
10) 'username': 'tester',
11) 'password': 'foobar',
12) 'optional_args': {'secret': 'foobar'}
13) } # Use a dictionary for the login parameters
14)
15) driver = napalm.get_network_driver(dev_type)
16) conn = driver(**dev_creds)
17) conn.open()
18) output = conn.get_arp_table()
19) print(json.dumps(output, indent=2))
20) close()
Das Setup mit NAPALM ist länger als mit Netmiko, weil es mehr Bibliotheken benötigt. Zudem müssen die Login-Parameter anders angegeben werden, wie in den Zeilen zwei bis 13 zu sehen. Die Verbindung wird in den Zeilen 15 bis 17 hergestellt. Zum Schluss wird die ARP-Tabelle abgerufen.
NAPALM liefert sie im Wörterbuchformat von Python zurück. Daher verwenden wir eine Bibliotheksfunktion für das Prettyprinting:
01) $ ./napalm-example.py
02) [
03) {
04) "interface": "Vlan1",
05) "mac": "00:25:9C:1A:4C:89",
06) "ip": "192.168.1.1",
07) "age": 0.0
08) },
09) {
10) "interface": "Vlan1",
11) "mac": "0C:84:DC:C4:85:69",
12) "ip": "192.168.1.3",
13) "age": 0.0
14) },
15) {
16) "interface": "Vlan1",
17) "mac": "BC:C4:93:3E:49:C0",
18) "ip": "192.168.1.108",
19) "age": 0.0
20) },
21) {
22) "interface": "Vlan1",
23) "mac": "4C:32:75:96:B7:0B",
24) "ip": "192.168.1.141",
25) "age": 2.0
26) }
27) ]
Die Wörterbuchausgabe lässt sich direkt innerhalb von Python nutzen. Die anderen Wörterbücher liefern die CLI-Textausgabe, die in eine Python-Datenstruktur konvertiert werden müsste, um für andere Zwecke eingesetzt werden zu können.
Die wahre Stärke von NAPALM liegt in dessen Fähigkeit, mit Konfigurationen zu arbeiten. Dazu gehören:
- Austausch von Konfigurationen
- Zusammenführen von Konfigurationen
- Vergleich von Konfigurationen
- Übergabe einer bereitgestellten Konfiguration
- Verwerfen einer potenziellen Konfiguration
- Rollback zu einer früheren Konfiguration
Erste Schritte mit Netzwerkautomatisierung und Python
Eine Reihe von Online-Kursen und -Videos behandeln die Netzwerkautomation mit Python und Automatisierungs-Frameworks. Eine gute Ausgangsbasis sind hierbei die Trainings von Nick Russo. Ivan Pepelnjak untersucht in seinen Kursen für Fortgeschrittene Building Network Automations Solutions und Ansible for Networking Engineers (zusammen mit David Barroso) auch andere Technologien.