Wenn man von typischen Szenarien der Netzwerkautomatisierung spricht, kann man nicht auf eine Reihe von Befehlsmodulen verzichten. Dank dieser Module können Sie mit Ansible Befehle auf Netzwerkgeräten ausführen, als würden Sie sie direkt über die Konsole eingeben. Gleichzeitig rutscht die Ausgabe von Befehlen nicht nur in das Terminalfenster, um in Vergessenheit zu geraten, sondern kann gespeichert und in Zukunft verwendet werden. Es kann in Variablen geschrieben, zur Verwendung in nachfolgenden Aufgaben analysiert oder für die Zukunft in Hostvariablen gespeichert werden.

Das Ziel dieses Beitrags ist es zu zeigen, dass sich wiederholende Netzwerkverwaltungsaufgaben automatisiert werden können und dass Ansible nicht nur das Verwalten von Konfigurationen ermöglicht, sondern auch dazu beiträgt, Routine loszuwerden und Zeit zu sparen.
Lassen Sie uns die grundlegenden Möglichkeiten zur Verwendung der Netzwerkbefehlsmodule analysieren, einschließlich des Speicherns der Ausgabe von Befehlen mithilfe des Registerparameters. Wir betrachten auch die Skalierung auf mehrere Netzwerkgeräte mithilfe von Hostvars und die Organisation der bedingten Ausführung mithilfe des Parameters wait_for und dreier anderer verwandter Parameter: Intervall, Wiederholungsversuche und Übereinstimmung.
Verschiedene Netzwerkplattformen verfügen über eigene Befehlsmodule, die alle auf der Erweiterungsstufe Red Hat Ansible Engine Networking Add-on unterstützt werden:
Grundlagen des Befehlsmoduls
Stellen Sie sich ein Playbook vor, in dem der Befehl show version einfach mit dem Modul eos_command ausgeführt wird:
--- - name: COMMAND MODULE PLAYBOOK hosts: eos connection: network_cli tasks: - name: EXECUTE ARISTA EOS COMMAND eos_command: commands: show version register: output - name: PRINT OUT THE OUTPUT VARIABLE debug: var: output
Hier haben wir zwei Aufgaben und die erste verwendet das Modul eos_command mit einem einzelnen Befehlsparameter. Da wir nur einen Befehl ausführen - show version - kann dieser in derselben Zeile wie der Befehlsparameter selbst angegeben werden. Wenn es zwei oder mehr Teams gibt, muss jedes von ihnen nach den Befehlen in einer separaten Zeile platziert werden :. In diesem Beispiel verwenden wir das
Schlüsselwort register , um die Ausgabe des Befehls show version zu speichern. Der Registerparameter (kann in jeder Ansible-Aufgabe verwendet werden) legt die Variable fest, in der die Ausgabe unserer Aufgabe gespeichert wird, damit sie später verwendet werden kann. In unserem Beispiel wird diese Variable als Ausgabe bezeichnet.
Die zweite Aufgabe in unserem Beispiel verwendet das
Debug-Modul , um den Inhalt der neu erstellten Ausgabevariablen anzuzeigen. Das heißt, dies sind die gleichen Daten, die Sie auf der Befehlszeilenschnittstelle des EOS-Geräts sehen würden, wenn Sie dort "show version" eingeben würden. Der Unterschied besteht darin, dass unser Playbook sie in dem Terminalfenster anzeigt, in dem Sie es starten. Wie Sie sehen können, erleichtert das Debug-Modul das Überprüfen von Ansible-Variablen.
Hier ist die Ausgabe unseres Spielbuchs:
PLAY [eos] ************************************************************************* TASK [execute Arista eos command] ************************************************** ok: [eos] TASK [print out the output variable] *********************************************** ok: [eos] => { "output": { "changed": false, "failed": false, "stdout": [ "Arista vEOS\nHardware version: \nSerial number: \nSystem MAC address: 0800.27ec.005e\n\nSoftware image version: 4.20.1F\nArchitecture: i386\nInternal build version: 4.20.1F-6820520.4201F\nInternal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91\n\nUptime: 1 day, 3 hours and 23 minutes\nTotal memory: 2017324 kB\nFree memory: 1111848 kB" ], "stdout_lines": [ [ "Arista vEOS", "Hardware version: ", "Serial number: ", "System MAC address: 0800.27ec.005e", "", "Software image version: 4.20.1F", "Architecture: i386", "Internal build version: 4.20.1F-6820520.4201F", "Internal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91", "", "Uptime: 1 day, 3 hours and 23 minutes", "Total memory: 2017324 kB", "Free memory: 1111848 kB" ] ] } } PLAY RECAP ************************************************************************* eos : ok=2 changed=0 unreachable=0 failed=0
Wie aus dem Screenshot hervorgeht, haben unsere beiden Aufgaben erfolgreich geklappt. Da die erste Aufgabe die Standarddetailstufe von Nachrichten verwendet, heißt es lediglich, dass der eos-Host die Aufgabe mit dem Ergebnis ok abgeschlossen hat, wodurch der Erfolg der Ausführung grün hervorgehoben wird. Die zweite Aufgabe mit dem Debug-Modul gibt die Ausgabe des ausgeführten Befehls zurück und zeigt dieselben Informationen in zwei Formaten an:
Der Abschnitt stdout zeigt dasselbe, was Sie in der Befehlszeilenschnittstelle des Geräts sehen würden, jedoch in Form einer langen Zeile. Der Abschnitt stdout_lines unterteilt diese Ausgabe in Zeilen, damit sie bequem gelesen werden kann. Jedes Element in dieser Liste ist eine separate Zeile in der Ausgabe des Befehls.
Vergleichen Sie die Ausgabe des Befehls auf dem Gerät und in Ansible:
Teamleistung in Arista EOS | stdout_lines in Ansible |
eos> show vers Arista vEOS Hardwareversion: Seriennummer: System-MAC-Adresse: 0800.27ec.005e
Software-Image-Version: 4.20.1F Architektur: i386 Interne Build-Version: 4.20.1F-6820520.4201F Interne Build-ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91
Betriebszeit: 1 Tag, 3 Stunden und 56 Minuten Gesamtspeicher: 2017324 kB Freier Speicher: 1116624 kB | "Stdout_lines": [ [ "Arista vEOS", "Hardwareversion:", "Seriennummer:", "System-MAC-Adresse: 0800.27ec.005e", "", "Software-Image-Version: 4.20.1F", "Architektur: i386", "Interne Build-Version: 4.20.1F-6820520.4201F ", "Interne Build-ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91 ", "", "Betriebszeit: 1 Tag, 3 Stunden und 23 Minuten", "Gesamtspeicher: 2017324 kB", Freier Speicher: 1111848 kB ]] |
Wenn Sie mit JSON und YAML vertraut sind, haben Sie wahrscheinlich bereits auf eine Kuriosität geachtet: stdout_lines beginnt mit zwei öffnenden Klammern:
"stdout_lines": [ [
Zwei öffnende Klammern geben an, dass stdout_lines tatsächlich eine Liste von Zeilenlisten zurückgibt. Wenn Sie unsere Debug-Aufgabe geringfügig ändern, können Sie mit diesem Chip die Ergebnisse des Befehls selektiv anzeigen. Da unsere Liste nur eine Liste von Zeilen enthält, wird diese Liste als Null bezeichnet (tatsächlich ist es die erste, aber die Anzahl geht von Grund auf neu). Lassen Sie uns nun sehen, wie Sie eine separate Zeile daraus extrahieren, z. B. die System-MAC-Adresse. In der Ausgabe des Befehls ist diese Zeile die vierte in Folge, aber da wir von Grund auf neu zählen, benötigen wir letztendlich Zeile 3 aus Liste 0, mit anderen Worten: output.stdout_lines [0] [3].
- name: print out a single line of the output variable debug: var: output.stdout_lines[0][3] debug- : TASK [print out a single line of the output variable] ****************************** ok: [eos] => { "output.stdout_lines[0][3]": "System MAC address: 0800.27ec.005e" }
Was ist der Sinn der Listennummerierung und warum wird sie überhaupt benötigt? Tatsache ist, dass Sie innerhalb derselben Aufgabe beispielsweise mehrere Teams leiten können (hier haben wir drei Teams):
--- - hosts: eos connection: network_cli tasks: - name: execute Arista eos command eos_command: commands: - show version - show ip int br - show int status register: output - name: print out command debug: var: output.stdout_lines
So sieht die Ausgabe aus:
"output.stdout_lines": [ [ "Arista vEOS", "Hardware version: ", "Serial number: ", "System MAC address: 0800.27ec.005e", "", "Software image version: 4.20.1F", "Architecture: i386", "Internal build version: 4.20.1F-6820520.4201F", "Internal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91", "", "Uptime: 1 day, 4 hours and 20 minutes", "Total memory: 2017324 kB", "Free memory: 1111104 kB" ], [ "Interface IP Address Status Protocol MTU", "Ethernet1 172.16.1.1/24 up up 1500", "Management1 192.168.2.10/24 up up 1500" ], [ "Port Name Status Vlan Duplex Speed Type Flags", "Et1 connected routed full unconf EbraTestPhyPort ", "Et2 connected 1 full unconf EbraTestPhyPort ", "Et3 connected 1 full unconf EbraTestPhyPort ", "Ma1 connected routed a-full a-1G 10/100/1000" ] ]
Hier ist Listennummer Null die Ausgabe des Befehls show version, Listennummer eins ist die Ausgabe von show ip int br, Listennummer zwei ist die Ausgabe von show int status. Das heißt, die Listennummer wird durch die Reihenfolge bestimmt, in der die Befehle ausgeführt werden.
Arista EOS Teams | Übereinstimmende Ausgabelisten |
Version anzeigen | output.stdout_lines [0] |
show ip int br | output.stdout_lines [1] |
int-Status anzeigen | output.stdout_lines [2] |
Skalierung des Befehlsmoduls: Hostvariablen
Und was passiert, wenn Sie das Playbook auf mehreren Geräten gleichzeitig ausführen?
Um eindeutig zu sein, wird die Ausgabevariable als
Hostvariable für jeden Host im Inventar gespeichert. Wenn wir drei Schalter haben und unser Playbook darauf ausführen, erhalten wir die Ausgabevariable für jeden einzelnen Host. Angenommen, wir benötigen die IP-Adresse aus dem Befehl show ip int br für den Ethernet1-Port auf switch03. Da show ip int br der zweite Befehl ist, der als Teil der Task ausgeführt wird, und die Ethernet1-Daten in der zweiten Zeile ihrer Ausgabe enthalten sind, müssen wir stdout_lines [1] [1] schreiben. Um auf die Variablen eines bestimmten Hosts zuzugreifen, verwenden wir das Schlüsselwort hostvars und suchen nach dem Host, den wir benötigen, anhand des Namens.
So geht's:
- name: debug hostvar debug: var: hostvars["switch03"].output.stdout_lines[1][1]
Daher enthält die Ausgabe genau das, was wir brauchen:
TASK [debug hostvar] *************************************************************** ok: [switch03] => { "hostvars[\"switch03\"].output.stdout_lines[1][1]": "Ethernet1 172.16.1.3/24 up up 1500" }
Standardmäßig verwendet die Aufgabe die Variablen des aktuellen Hosts. Mit hostvars können Sie jedoch direkt auf die Variablen eines anderen Hosts zugreifen.
Bedingungen in Aufgaben mit Befehlsmodulen: Parameter wait_for
Mit dem Parameter wait_for können Sie unmittelbar nach Ausführung des Befehls eine Bedingungsprüfung durchführen. Damit die Aufgabe beispielsweise nur dann als erfolgreich abgeschlossen gilt, wenn die Ausgabe des Statusprüfbefehls bestimmten Text enthält. Standardmäßig wird der Parameter wait_for nicht verwendet, sodass die Aufgabe wie in den obigen Beispielen nur einmal ausgeführt wird. Wenn Sie es jedoch explizit festlegen, wird die Aufgabe neu gestartet, bis die Bedingung erfüllt ist oder die Anzahl der Versuche überschritten wird (standardmäßig sind es 10). Wenn Sie die Befehlsprotokollierung aktivieren, können Sie im folgenden Playbook sehen (das speziell geschrieben wurde, damit die Bedingung niemals erfüllt wird), dass alles einfach so abläuft.
--- - hosts: eos connection: network_cli tasks: - name: execute Arista eos command eos_command: commands: - show int status wait_for: - result[0] contains DURHAM
In diesem Playbook wird der Befehl show int status zehnmal ausgeführt, da seine Ausgabe niemals eine DURHAM-Zeile enthält.
Sie können dies mit dem Befehl show logging überprüfen:
Mar 24 20:33:52 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=17 start_time=1521923632.5 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:53 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=18 start_time=1521923633.71 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:54 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=19 start_time=1521923634.81 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:55 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=20 start_time=1521923635.92 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:56 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=21 start_time=1521923636.99 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:58 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=22 start_time=1521923638.07 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:59 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=23 start_time=1521923639.22 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:34:00 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=24 start_time=1521923640.32 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:34:01 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=25 start_time=1521923641.4 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:34:02 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=26 start_time=1521923642.47 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status
Schauen wir uns nun ein Beispiel für ein echtes Playbook an, in dem alles so konfiguriert ist, dass eine OSPF-Nachbarschaft (Nachbarschaft) mit einem anderen Gerät als dem Befehl ip ospf area erstellt wird. Wir wenden diesen Befehl an und überprüfen dann mit dem Parameter wait_for, ob das Wort FULL in der Ausgabe vorhanden ist: Wenn es vorhanden ist, wurde die Nachbarschaft erfolgreich eingerichtet. Wenn in 10 Versuchen nicht FULL angezeigt wird, schlägt die Aufgabe fehl.
--- - hosts: eos connection: network_cli tasks: - name: turn on OSPF for interface Ethernet1 eos_config: lines: - ip ospf area 0.0.0.0 parents: interface Ethernet1 - name: execute Arista eos command eos_command: commands: - show ip ospf neigh wait_for: - result[0] contains FULL
Führen Sie dieses Playbook mit dem Befehl ansible-playbook aus:
➜ ansible-playbook ospf.yml PLAY [eos] ********************************************************************************************* TASK [turn on OSPF for interface Ethernet1] ******************************************************* changed: [eos] TASK [execute Arista eos command] **************************************************************** ok: [eos] PLAY RECAP ****************************************************************************************** eos : ok=2 changed=1 unreachable=0 failed=0
Wir schauen auf die Kommandozeile und sehen, dass das Playbook erfolgreich war:
eos#show ip ospf neigh Neighbor ID VRF Pri State Dead Time Address Interface 2.2.2.2 default 1 FULL/DR 00:00:33 172.16.1.2 Ethernet1
Zusätzlich zu enthält können Sie die folgenden Vergleichsoperatoren verwenden:
- Gleichung: - ist gleich
- neq: - ungleich
- gt: - mehr
- ge: - größer oder gleich
- lt: - weniger
- le: - kleiner oder gleich
Zusätzlich können Sie zusammen mit wait_for drei zusätzliche Parameter verwenden (ausführlich in der Dokumentation zu den Modulen beschrieben):
Parameter | Beschreibung |
Intervall | Zeit zwischen Wiederholungen eines Teams. |
Wiederholungen | Max Die Anzahl der Wiederholungen, bevor die Aufgabe mit einem Fehler abgeschlossen wird oder die Bedingung erfüllt ist. |
Spiel | Das Zusammentreffen aller Bedingungen oder mindestens einer. |
Lassen Sie uns näher auf den Übereinstimmungsparameter eingehen:
- name: execute Arista eos command eos_command: commands: - show ip ospf neigh match: any wait_for: - result[0] contains FULL - result[0] contains 172.16.1.2
Wenn match: any angegeben ist, wird die Aufgabe als erfolgreich angesehen, wenn das Ergebnis FULL oder 172.16.1.2 enthält. Wenn match: all angegeben ist, muss das Ergebnis sowohl FULL als auch 172.16.1.2 enthalten. Standardmäßig wird match: all verwendet. Wenn Sie mehrere Bedingungen vorschreiben, möchten Sie höchstwahrscheinlich, dass alle und nicht mindestens eine ausgeführt werden.
Wann kann passen: welche nützlich sein? Angenommen, Sie müssen überprüfen, ob das Rechenzentrum über eine bidirektionale Verbindung zum Internet verfügt. Das Rechenzentrum ist mit fünf verschiedenen Internetanbietern verbunden, von denen jeder über eine eigene BGP-Verbindung verfügt. Ein Playbook kann alle diese fünf Verbindungen überprüfen. Wenn mindestens eine davon funktioniert und nicht alle fünf, melden Sie, dass alles in Ordnung ist. Denken Sie daran, dass jedes ein logisches ODER ist und alles ein logisches UND ist.
Parameter | Beschreibung |
Übereinstimmung: beliebig | Logisches "ODER" Es ist mindestens eine Bedingung erforderlich |
Spiel: alle | Logisches "Und" Alle Bedingungen erforderlich |
Negative Bedingungen: Aufbau der inversen Logik
Manchmal ist es nicht wichtig, was in der Schlussfolgerung steht, sondern was nicht. Hier ist es natürlich immer verlockend, den neq-Vergleichsoperator zu verwenden, aber für einige Szenarien mit negativen Bedingungen gibt es bessere Optionen. Wenn Sie beispielsweise die include-Anweisung invertieren müssen (vom Typ "Die Ausgabe des Befehls sollte solche und solche nicht enthalten"), können Sie das Schlüsselwort register verwenden, um die Ausgabe zu speichern und sie dann in der nächsten Aufgabe mit dem
Ausdruck when zu verarbeiten . Wenn Sie beispielsweise das Playbook stoppen müssen, wenn die Bedingungen nicht erfüllt sind, verwenden Sie einfach die
Fail- oder
Assert- Module, um den Fehler spezifisch zu beenden. Der Vergleichsoperator neq ist nur dann nützlich, wenn Sie den genauen Wert aus der Ausgabe extrahieren können (z. B. aus einem Schlüssel-Wert-Paar oder aus JSON) und nicht nur aus einer Zeichenfolge oder einer Liste von Zeichenfolgen. Andernfalls wird ein zeichenweiser Vergleich der Zeichenfolgen durchgeführt.
Was weiter
Lesen Sie die
Dokumentation zum Arbeiten mit der Ausgabe von Befehlen in Netzwerkmodulen. Es enthält nützliche Beispiele für die Verwendung von ge, le und anderen Bedingungen bei der Arbeit mit der Ausgabe im JSON-Format auf bestimmten Netzwerkplattformen.