SSD Nodes Learn Hosting plans →
Anleitungen Matt ConnorVon Matt Connor

Ansible Check-Modus und --diff richtig nutzen

Erfahren Sie, was --check und --diff tatsächlich prüfen, welche Module nichts melden und warum der Probelauf vor dem echten Lauf falsch liegen kann.

Was der Ansible-Check-Modus macht

Der Ansible-Check-Modus ist ein Probelauf: ansible-playbook --check verbindet sich mit jedem Host im Play, fragt jedes Modul, ob der aktuelle Zustand bereits dem angeforderten Zustand entspricht, und meldet, was sich ändern würde, ohne etwas zu schreiben. Mit --diff wird zusätzlich der Inhalt der Dateien vor und nach der Änderung ausgegeben, die das Modul bearbeiten würde. Zusammen beantworten diese Optionen die Frage, die Sie sich vor jedem echten Lauf stellen sollten: Was wird auf diesen Servern gleich geändert?

Der Check-Modus simuliert Ihr Playbook nicht. Es gibt kein Modell des Servers. Jedes Modul wird lediglich angewiesen, zu prüfen statt zu schreiben. Ein Modul, das eine schreibgeschützte Prüfung unterstützt, meldet changed und fährt fort. Ein Modul, das diese Prüfung nicht unterstützt, führt nichts aus und meldet nichts. Die Ansible-Dokumentation fasst es in einem Satz zusammen: „Module, die den Check-Modus nicht unterstützen, melden nichts und führen nichts aus.“ Genau daraus entsteht die Lücke, durch die ein Probelauf eine falsche Antwort liefern kann. Deshalb behandelt der größte Teil dieses Leitfadens diese Lücke.

Testlauf ausführen: --check und --diff

ansible-playbook -i inventory.ini site.yml --check --diff --limit web1

-C und -D sind die Kurzformen der beiden Flags. Das --limit ist beabsichtigt. Der Diff eines Hosts ist lesbar. Bei zwanzig Hosts scrollen Sie daran vorbei.

Vier Ergebniswörter tragen den gesamten Bericht.

  • ok: [web1] bedeutet, dass die Aufgabe ausgeführt wurde und keine Änderung gemeldet hat. Bei einem Modul, das einen Zustand verwaltet, etwa apt oder template, bedeutet das, dass der Zustand bereits übereinstimmt. Bei debug oder set_fact bedeutet es nur, dass die Aufgabe ausgeführt wurde.
  • changed: [web1] bedeutet, dass das Modul vorhersagt, etwas geschrieben zu hätten. Mit --diff zeigen die darüberstehenden Zeilen, was das wäre. Die meisten Module treffen diese Vorhersage korrekt. Einige Module mit unvollständiger Unterstützung für den Check-Modus weisen jedoch in ihrer eigenen Dokumentation darauf hin: get_url sendet im Check-Modus nur eine HEAD-Anfrage und weist darauf hin, dass der Status von changed möglicherweise falsch gemeldet wird.
  • skipping: [web1] bedeutet, dass die Aufgabe nicht ausgeführt wurde. Entweder wurde ihr when ausgewertet und war false, oder das Modul kann nicht im Check-Modus ausgeführt werden.
  • fatal: [web1] bedeutet, dass die Aufgabe während der Prüfung fehlgeschlagen ist. Lesen Sie die Meldung, bevor Sie annehmen, dass das Playbook fehlerhaft ist.

--diff gibt für Dateimodule einen Unified Diff aus. Entfernte Zeilen sind mit - markiert, hinzugefügte Zeilen mit +. Unter einer Kopfzeile beginnen die Zeilen mit --- before und +++ after und nennen den Zielpfad. Module, die keine Dateien schreiben, geben ihre eigene Darstellung von vorher und nachher aus. ansible.builtin.user zeigt daher die Attribute, die geändert würden, und nicht den Dateiinhalt.

Aktivieren Sie den Diff dauerhaft in ansible.cfg, damit Sie das Flag nicht vergessen:

[diff]
always = true
context = 5

Zwei schnellere Prüfungen sollten vor dem Check-Modus ausgeführt werden. ansible-playbook site.yml --syntax-check analysiert das YAML und die Play-Struktur, ohne einen einzigen Host zu kontaktieren. ansible-playbook site.yml --list-tasks gibt die Aufgaben aus, die ausgeführt würden. So erkennen Sie, dass eine Rolle, die Sie für getaggt hielten, tatsächlich nicht getaggt ist. Keine der beiden Prüfungen stellt eine Verbindung her. Beide sind daher sofort abgeschlossen.

Der Check-Modus selbst stellt eine Verbindung her. Er öffnet eine SSH-Verbindung zu jedem Host im Muster und sammelt Fakten. Ein nicht erreichbarer Host lässt den Testlauf daher fehlschlagen. Das ist bereits ein nützliches Signal. Genau deshalb ist es wichtig, festzulegen, wie ein Playbook mit nicht erreichbaren Hosts umgehen soll, bevor Sie einen Testlauf in CI integrieren.

Warum der Check-Modus auf einem neuen Server fehlschlägt

Dieses Play ist korrekt. Wenn Sie es mit --check auf einem Server ausführen, auf dem nginx noch nicht installiert ist, schlägt ein großer Teil davon fehl.

- name: Install nginx
  ansible.builtin.apt:
    name: nginx
    state: present

- name: Write the site config
  ansible.builtin.template:
    src: site.conf.j2
    dest: /etc/nginx/conf.d/site.conf

- name: Start and enable nginx
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: true

Die Aufgabe apt meldet changed. Das ist korrekt: Das Paket fehlt, daher würde ein regulärer Lauf es installieren. Der Check-Modus hat es nicht installiert. Die Aufgabe template schlägt anschließend fehl, weil /etc/nginx/conf.d/ auf diesem Host nicht vorhanden ist und zuvor nichts erstellt wurde. Auch die Aufgabe service schlägt fehl, weil keine nginx-Unit vorhanden ist, die abgefragt werden könnte. Keine dieser Fehler ist ein Fehler im Playbook. Beim Probelauf fehlte der benötigte Zustand. Genau das ist mit dem Hinweis in der Dokumentation gemeint, dass der Check-Modus für eine Aufgabe keine verwertbare Ausgabe liefern kann, wenn deren Eingabe von der Änderung einer vorherigen Aufgabe abhängt.

Die ehrliche Fassung der Regel lautet daher: Der Check-Modus ist gegenüber einem Host am aussagekräftigsten, auf dem das Playbook bereits den gewünschten Zustand hergestellt hat, und gegenüber einem neuen Host entsprechend unübersichtlich. Ein --check-Lauf, bei dem jede Aufgabe ok meldet, ist eine verlässliche Aussage über einen Host im gewünschten Zustand. Das bedeutet, dass sich nichts ändern würde. Dabei gelten auf jedem Host zwei Einschränkungen: Eine übersprungene command-Aufgabe ist keine Antwort, sondern eine nicht ausgefüllte Stelle. Außerdem kann ein Modul mit nur teilweiser Unterstützung des Check-Modus, beispielsweise get_url, weiterhin einen falschen Änderungsstatus melden. Auf einem vollständig neuen Host bedeutet --check daher meist nur, dass der Host neu ist. Wenn Sie Ihr erstes Ansible-Playbook für einen VPS schreiben, müssen Sie beim ersten Probelauf mit einer langen Liste roter Meldungen rechnen. Bewerten Sie das Playbook anhand des zweiten Laufs.

Warum Command- und Shell-Aufgaben im Check-Modus übersprungen werden

ansible.builtin.command und ansible.builtin.shell wissen nicht, was Ihr Command ausführt. Es gibt keine schreibgeschützte Möglichkeit, eine beliebige Binärdatei auszuführen. Deshalb verweigert das Modul die Ausführung im Check-Modus. Das Aufgabenergebnis enthält skipped: true und die Meldung Command would have run if not in check mode. In der Ausgabe sehen Sie skipping: [web1].

Die Moduldokumentation bezeichnet die Unterstützung des Check-Modus als „partiell“. Als Workaround nennt sie creates und removes. Geben Sie der Aufgabe einen creates-Pfad. Dann kann der Check-Modus zumindest den Dateitest auswerten:

- name: Extract the release bundle
  ansible.builtin.command: /usr/bin/tar xf /tmp/app.tar.gz -C /opt/app
  args:
    creates: /opt/app/bin/app

Wenn /opt/app/bin/app bereits vorhanden ist, meldet der Check-Modus Would not run command since '/opt/app/bin/app' exists. Das ist ein gültiges Ergebnis. Fehlt der Pfad, erhalten Sie Command would have run if not in check mode. Auch das ist ein gültiges Ergebnis. Ohne creates bleibt diese Aufgabe in Ihrem Probelauf ohne Aussage.

Die Folgewirkung ist problematischer als die fehlende Ausgabe. Eine übersprungene command-Aufgabe registriert weiterhin ein Ergebnis. Dieses Ergebnis enthält zwar stdout, aber der Wert ist eine leere Zeichenfolge, weil nichts ausgeführt wurde. Die Bedingung der nächsten Aufgabe wird anhand dieser leeren Zeichenfolge ausgewertet und nimmt stillschweigend den falschen Zweig: Eine Versionsprüfung findet keine Version, und ein Test wie 'active' in svc.stdout ergibt false. Ihr Playbook liefert bei einer echten Ausführung ein anderes Ergebnis als im Probelauf. Es gibt keinen Fehler, auf den Sie verweisen können. Das ist der verwirrendste Fehler in diesem gesamten Feature. Der Fehler 'dict object' has no attribute 'stdout' gehört zu einer anderen Art des Überspringens: Eine Aufgabe wurde übersprungen, weil when den Wert false hatte. Ihr Ergebnis enthält dann überhaupt keinen Schlüssel stdout.

check_mode: false und die eine Stelle, an die es gehört

check_mode: false bei einer Task bedeutet: „Diese Task tatsächlich ausführen, auch unter --check.“ Das behebt das Problem übersprungener Befehle und ist nur bei einer Task sicher, die ausschließlich liest.

- name: Read the installed app version
  ansible.builtin.command: /usr/local/bin/app --version
  register: app_version
  check_mode: false
  changed_when: false

Diese Task verhält sich in beiden Modi korrekt. Sie liest eine Version und schreibt nie. changed_when: false verhindert, dass sie eine Änderung meldet, die sie nicht vorgenommen hat. check_mode: false sorgt dafür, dass app_version.stdout während eines Probelaufs die tatsächliche Version statt einer leeren Zeichenfolge enthält. Dadurch werden die darauf basierenden Bedingungen weiterhin korrekt ausgewertet.

Lesen Sie das Schlüsselwort wörtlich, bevor Sie es an einer anderen Stelle einsetzen. Eine Task mit check_mode: false schreibt während ansible-playbook --check auf Ihre Server. Setzen Sie es bei einer apt-Task oder einer template-Task ein, damit ein Probelauf übersichtlicher aussieht, ist es kein Probelauf mehr. Wenn eine schreibende Task nicht sicher ausgeführt werden kann, versehen Sie sie stattdessen mit einer Bedingung:

- name: Apply the database migration
  ansible.builtin.command: /usr/local/bin/app migrate --apply
  when: not ansible_check_mode

ansible_check_mode ist eine spezielle Variable, die Ansible während eines Prüflaufs auf true setzt. Das Gegenstück zu diesem Schlüsselwort gibt es ebenfalls. check_mode: true bindet eine Task immer an den Prüfmodus, auch während einer normalen Ausführung. Dadurch wird sie zu einer Abfrage auf Abweichungen: Registrieren Sie das Ergebnis. Ein Bericht mit changed bedeutet, dass der Host nicht mehr dem von der Task geforderten Zustand entspricht.

Warum eine Task bei jedem Lauf eine Änderung meldet

Führen Sie das Playbook zweimal direkt hintereinander aus. Dazwischen darf nichts passieren. Jede Task sollte beim zweiten Lauf ok melden. Jede Task, die weiterhin changed meldet, weist auf eine von zwei Ursachen hin: Das Modul kann den von ihm verwalteten Zustand nicht erkennen, oder die Eingabe ist nicht stabil. Beides lässt sich beheben. Beides ist kein Grund, die Meldung zu unterdrücken.

  • command und shell ohne creates, removes oder changed_when melden jedes Mal changed, weil das Modul nicht feststellen kann, ob etwas passiert ist. Fügen Sie creates hinzu oder setzen Sie changed_when für eine Zeichenfolge in der Ausgabe.
  • ansible.builtin.file mit state: touch meldet absichtlich bei jedem Lauf changed, weil das Berühren einer Datei deren Zeitstempel aktualisiert. Verwenden Sie state: file, wenn Sie nur den Eigentümer oder die Berechtigungen setzen wollten.
  • Ein template, dessen gerenderte Ausgabe sich ändert, schreibt die Datei bei jedem Lauf neu. Ein Zeitstempel aus ansible_date_time, ein Aufruf von now() oder ein bei jedem Lauf neu erzeugtes Passwort erzeugen jeweils andere Bytes. Das Modul meldet daher korrekt eine Änderung. Entfernen Sie den veränderlichen Wert aus dem Template.
  • ansible.builtin.user mit password: "{{ pw | password_hash('sha512') }}" ändert sich bei jedem Lauf, weil password_hash bei jedem Aufruf einen zufälligen Salt erzeugt. Dadurch stimmt der resultierende Hash nie mit dem bereits in /etc/shadow vorhandenen Hash überein. Übergeben Sie einen expliziten Salt, der aus einem stabilen Wert abgeleitet ist.
  • state: latest für ein Paketmodul meldet changed, sobald ein Upgrade verfügbar ist. Diese Meldung ist korrekt. Deshalb liefert state: latest ein Playbook, dessen Ergebnis Sie nicht vorhersagen können. Verwenden Sie state: present und führen Sie Upgrades gezielt aus.
  • ansible.builtin.unarchive mit einer URL ohne creates lädt das Archiv bei jedem Lauf erneut herunter. Bei Archivtypen kann es außerdem keinen Vergleich mit dem Ziel durchführen, in das es das Archiv erneut entpackt. Geben Sie einen creates-Pfad an.

--diff ist die schnellste Möglichkeit, diese Fälle zu unterscheiden. Wenn eine Task changed meldet und der Diff unterschiedliche Bytes zeigt, ist Ihre Eingabe instabil. Wenn sie changed meldet und der Diff überhaupt keine Unterschiede zeigt, kann das Modul die von ihm vorgenommene Änderung nicht ausdrücken. Das bedeutet meist, dass es sich um eine command-Task oder um einen reinen Metadaten-Schreibvorgang wie das Setzen eines Zeitstempels handelt.

Verwenden Sie nicht changed_when: false, um eine laute Task zum Schweigen zu bringen. Dadurch wird die Meldung unterdrückt, sodass notify nie ausgelöst wird und der Handler zum Neustart des Dienstes nie ausgeführt wird. Beheben Sie stattdessen die Task.

Angriffsfolgen begrenzen: --limit, --tags und --step

Der Prüfmodus zeigt, was geändert würde. Mit diesen Optionen legen Sie fest, auf wie vielen Rechnern die Änderungen gleichzeitig ausgeführt werden.

--limit beschränkt den Play auf eine Teilmenge des Inventars. Die Option verwendet dieselben Muster wie hosts:. Daher funktionieren sowohl --limit web1 als auch --limit 'webservers:!web3'. Setzen Sie das Muster in Anführungszeichen. Ein nicht in Anführungszeichen gesetztes ! löst in einer interaktiven bash-Sitzung eine History-Erweiterung am Ausrufezeichen aus. Ihre Shell ändert den Befehl, bevor Ansible ihn überhaupt erhält.

Prüfen Sie das Muster, bevor Sie ihm vertrauen. ansible-playbook site.yml --limit 'webservers:!web3' --list-hosts gibt die passenden Hosts aus und beendet sich, ohne eine Verbindung zu einem von ihnen herzustellen. Ein Muster ohne Treffer ist sicher, weil Ansible nicht auf das gesamte Inventar zurückfällt. Ansible gibt eine Warnung aus, dass das Hostmuster keinem Host entspricht, und beendet sich anschließend mit einem Fehler. Die Inventar-, Hostmuster- und --limit-Angaben ergeben keine Zielhosts. Wenn Sie wissen, wie die Inventardatei diese Gruppen definiert, sind Muster von Anfang an vorhersehbar.

--tags deploy führt nur Aufgaben mit den angegebenen Tags aus. --skip-tags packages führt alle übrigen Aufgaben aus. --list-tags gibt die verfügbaren Tags aus. Tags sind besonders nützlich, sobald ein Play so groß wird, dass Sie nicht mehr alles ausführen möchten. Das ist auch einer der Gründe, ein langes Playbook in Rollen aufzuteilen.

--start-at-task "Write the site config" setzt einen fehlgeschlagenen Lauf ab einer benannten Aufgabe fort. Verwenden Sie die Option zur Wiederherstellung, und berücksichtigen Sie die Kosten: Alles vor dieser Aufgabe wird übersprungen. Dazu gehören auch Aufgaben, die Facts setzen oder Variablen registrieren, die spätere Aufgaben lesen.

--step fordert vor jeder Aufgabe eine Eingabe an und wartet auf Ihre Antwort: yes, no oder continue. Das ist langsam. Beim ersten Ausführen einer destruktiven Aktion ist es trotzdem das richtige Werkzeug, weil Sie zwischen zwei Aufgaben abbrechen können statt erst nach zwanzig.

Rollout mit serieller Ausführung

Standardmäßig führt Ansible eine Aufgabe auf jedem Host im Play aus, bevor es mit der nächsten Aufgabe beginnt. Das ist schnell. Es bedeutet aber auch, dass eine fehlerhafte Aufgabe die gesamte Flotte in derselben Sekunde erreicht. Wenn Sie den Fehler gelesen und Ctrl-C gedrückt haben, ist die Änderung bereits überall ausgerollt.

serial teilt das Play in Batches auf. Das gesamte Play wird zuerst auf den Hosts des ersten Batches ausgeführt, danach auf den Hosts des nächsten Batches.

- name: Roll out the web tier
  hosts: webservers
  serial: [1, 5, "30%"]
  max_fail_percentage: 0
  tasks:
    - name: Deploy the release
      ansible.builtin.include_role:
        name: webapp

Der erste Batch umfasst einen Host. Wenn dieser die Änderung erfolgreich verarbeitet, umfasst der zweite Batch fünf Hosts. Jeder weitere Batch umfasst 30 Prozent der Hosts des Plays. max_fail_percentage: 0 bricht den restlichen Ablauf des Plays ab, sobald ein Host in einem Batch fehlschlägt. Der Schwellenwert muss überschritten werden, und jeder Fehler überschreitet null. Die Garantie für einen einzelnen Test-Host ergibt sich aus dem ersten Batch, nicht aus dieser Einstellung: Eine Version, die überall fehlschlägt, scheitert am einzelnen Host im ersten Batch und wird dort angehalten. Ein Fehler, der erst im Batch mit fünf Hosts sichtbar wird, hat bereits die anderen Hosts dieses Batches erreicht. Ansible führt jede Aufgabe auf dem gesamten Batch aus, bevor es mit der nächsten Aufgabe beginnt. any_errors_fatal: true ist die strengere Variante. Sie beendet das Play für alle Hosts, sobald der erste Host fehlschlägt.

Die Änderung zunächst auf einem Host auszuführen, ist keine übertriebene Vorsicht. Der Grund ist konkret: Inventory-Gruppen verändern sich mit der Zeit. Ein Server, der sechs Monate nach den anderen hinzugefügt wurde, kann eine andere Distributionsversion verwenden, einen von jemandem manuell installierten Dienst enthalten oder eine andere Festplattenaufteilung haben. Das Playbook ist für die Gruppe korrekt, aber für diesen einzelnen Host falsch. Ein Probelauf auf einem bereits angeglichenen Host würde diesen Fehler nicht zeigen. Eine Flotte von Linux-Servern verwalten bedeutet zu einem großen Teil, den abweichenden Host zu finden, bevor die Änderung ihn erreicht.

Reihenfolge der Ausführung

  1. ansible-playbook site.yml --syntax-check erkennt YAML- und Strukturfehler vollständig ohne Netzwerkzugriff.
  2. ansible-playbook site.yml --limit web1 --list-hosts bestätigt, dass Ihr Muster wie erwartet übereinstimmt.
  3. ansible-playbook site.yml --limit web1 --check --diff ist der Probelauf. Lesen Sie den Diff.
  4. ansible-playbook site.yml --limit web1 --diff wendet die Änderung auf diesem einen Host an.
  5. Führen Sie Schritt 4 erneut aus. Alles sollte ok melden. Alles, was weiterhin changed ist, muss behoben werden, bevor es auf den restlichen Bestand angewendet wird.
  6. ansible-playbook site.yml --check --diff über das gesamte Inventar liefert nun eine aussagekräftige Antwort, weil die konvergierten Hosts keine Änderungen mehr melden und die verbleibende Abweichung der tatsächlichen Differenz entspricht.

Ein Hinweis zu Schritt 3: --diff gibt Dateiinhalte auf Ihrem Terminal und im Log Ihres CI-Jobs aus. Wenn ein Template ein Datenbankpasswort rendert, wird dieses Passwort daher in das Log geschrieben. Setzen Sie diff: false für diese Aufgabe, um die Ausgabe zu unterdrücken, oder verwenden Sie no_log: true, um das gesamte Ergebnis auszublenden. Speichern Sie den Wert selbst in einer verschlüsselten Ansible-Vault-Datei und nicht im Repository.

FAQ

Ändert ansible-playbook --check etwas auf dem Server?

Nein, mit einer Ausnahme, die Sie steuern. Im Check-Modus wird jedes Modul aufgefordert, seinen Zustand zu melden, statt Änderungen zu schreiben. Module, die das nicht unterstützen, melden nichts und führen nichts aus. Die Ausnahme ist das Aufgaben-Schlüsselwort check_mode: false. Es erzwingt, dass die einzelne Aufgabe auch während eines --check-Laufs tatsächlich ausgeführt wird. Suchen Sie in Ihren Playbooks und Rollen nach check_mode: false, bevor Sie einem Probelauf vertrauen. Prüfen Sie bei jedem Treffer, dass es sich um eine Aufgabe handelt, die ausschließlich den Zustand liest.

Was ist der Unterschied zwischen --check und --diff?

--check entscheidet, ob etwas tatsächlich ausgeführt wird. --diff entscheidet, wie viele Details Sie sehen. --check allein zeigt, dass sich eine Datei ändern würde. --diff allein wendet die Änderung an und zeigt die geänderten Zeilen. Verwenden Sie beide Optionen zusammen für einen lesbaren Probelauf. Lassen Sie --diff auch bei echten Läufen aktiviert, indem Sie always = true unter [diff] in ansible.cfg setzen.

Warum meldet meine Ansible-Aufgabe bei jedem Lauf changed?

Weil das Modul den von ihm verwalteten Zustand nicht erkennen kann oder weil der übergebene Wert bei jedem Lauf anders ist. command und shell melden immer changed, sofern Sie nicht creates oder changed_when hinzufügen. file mit state: touch ändert sich absichtlich. Eine Vorlage, die einen Zeitstempel oder ein neu generiertes Passwort rendert, erzeugt bei jedem Lauf andere Bytes. Die Datei wird daher tatsächlich neu geschrieben. Führen Sie das Playbook zweimal direkt hintereinander aus. Alles, was beim zweiten Durchlauf weiterhin changed ist, weist auf die zu korrigierende Aufgabe hin.

Warum werden meine command- und shell-Aufgaben während eines Probelaufs übersprungen?

Weil es keine schreibgeschützte Möglichkeit gibt, einen beliebigen Befehl auszuführen. Im Check-Modus setzt das Modul command skipped: true mit der Meldung Command would have run if not in check mode. Fügen Sie creates oder removes hinzu, damit der Check-Modus stattdessen den Dateitest auswerten kann. Setzen Sie bei einer Aufgabe, die nur den Zustand liest, check_mode: false zusammen mit changed_when: false. Dann enthält das registrierte Ergebnis während des Probelaufs die tatsächliche Ausgabe, und die darauf aufbauenden Bedingungen funktionieren weiterhin.

Warum schlägt der Check-Modus auf einem neuen Server fehl, funktioniert aber auf einem vorhandenen?

Weil der Check-Modus den Zustand nicht anlegt, von dem spätere Aufgaben abhängen. Ein Probelauf auf einem Host ohne nginx meldet die Installation als changed und schlägt anschließend bei der Aufgabe fehl, die in /etc/nginx/conf.d/ schreibt, weil dieses Verzeichnis nie angelegt wurde. Das ist erwartetes Verhalten. Der Check-Modus erkennt Abweichungen auf Hosts, die das Playbook bereits in den gewünschten Zustand gebracht hat. Einen ersten Lauf kann er nicht validieren. Wenden Sie das Playbook auf einem neuen Host zunächst an und lesen Sie anschließend den zweiten Lauf aus.

#ansible#check-mode#idempotency#automation#safety