Einführung
Der Redakteur von Field Notes hat zwei Fotostationen mit unterschiedlichen Auswahlen zu bearbeiten. Ein Kontaktbogen mit passender Dateiliste macht die Fotos für die Auswahl nutzbar. Ein gestarteter Hintergrundjob oder eine alte gleichnamige Datei ist jedoch noch keine fertige Lieferung. Erstelle ein kleines Beispiel und nutze dann Ansible, um auf die tatsächlichen aktuellen Ergebnisse jeder Station zu warten und sie abzuholen.
Du brauchst grundlegende Terminal-Navigation und Übung mit einem kleinen Ansible-Inventory, Variablen sowie command/file-Aufgaben. SSH-Zugang, lizenzierte Fotos und das Bildwerkzeug sind vorbereitet. Dieses Lab erklärt Argumentlisten, Schleifen, hostbezogene Job-IDs, Abschlussprüfungen und fetch-Ziele vor ihrer Verwendung. Die Dauer ist eine Schätzung des Autors einschließlich Lesen und gewöhnlicher Korrekturen, keine gemessene Bearbeitungszeit echter Einsteiger.
Einen kleinen Kontaktbogen erstellen
In diesem Schritt führst du mit Ansible einen kleinen Fotojob aus, holst sein echtes Bild und seine Dateiliste ab und verwendest das Ergebnis als Vorbild für den größeren Job.
Öffne den Tab Photo Desk. Klicke unter A previous walk auf Open contact sheet. Ein Kontaktbogen zeigt verkleinerte Versionen mehrerer Fotos auf einer Seite, damit eine Redaktion Motive vergleichen kann, ohne alle Originale zu öffnen. Dieses historische Beispiel trägt die Kennzeichnung previous-walk: Es ist eine Referenz, keine fertige Arbeit für heute. Scrolle auf einem schmalen Bildschirm innerhalb des Bildrahmens, um die Dateinamen zu lesen. Mit Back to photo desk kehrst du im selben Tab zur Seite zurück.
Geschichte und Stationszuweisungen sind fiktiv. Die Landschaftsfotos sind eine lizenzierte Lehrsammlung; Photo credits nennt die tatsächlichen Fotografen und Quellen. Das vorbereitete Werkzeug liest echte JPEG-Dateien und erzeugt einen PNG-Kontaktbogen sowie eine CSV-Dateiliste. Du automatisierst dieses Werkzeug, ohne Bildverarbeitungscode zu schreiben.
Wechsle zum Tab Controller. Er beginnt in /home/labex/project. Der Controller führt Ansible aus. Seine beiden SSH-Ziele sind Container, die den Kernel dieser Trainings-VM teilen, keine zwei eigenständigen VMs. Jedes Ziel hat eigene Dateien, auch wenn die Pfadnamen gleich sind.
pwd zeigt das aktuelle Verzeichnis und cat eine Datei an. Lies das vorbereitete Inventory und die Variablen:
pwd
cat inventory.yml
cat group_vars/all.yml
cat host_vars/camera-north.yml
cat host_vars/camera-south.yml
Die Inventory-Gruppe cameras enthält camera-north und camera-south mit ihren tatsächlichen SSH-Einstellungen. Die Projektdatei ansible.cfg wählt dieses inventory.yml und die vorbereitete Host-Vertrauenskonfiguration. Das ursprüngliche inventory.ini des Images ist nicht das Kurs-Inventory. Behalte Konfiguration, Inventory und Variablendateien unverändert bei.
Die Klammern im JSON-Stil dieser Dateien sind gültiges YAML. group_vars/all.yml liefert gemeinsame Variablen: input_root ist /srv/photo-sheets/batches, output_root ist /srv/photo-sheets/rendered und collection_root bezeichnet das Controller-Verzeichnis collected neben dem Playbook. Eine Datei in host_vars gilt für den gleichnamigen Host. Hier wählt photo_batch auf der Nordstation morning-walk und auf der Südstation afternoon-walk. Die heutigen Auswahlen unterscheiden sich in Inhalt und Umfang.
Nutze zuerst die vorbereitete Eingabe sample mit zwei Fotos auf der Nordstation. Ansibles Modul command führt das vorbereitete Programm auf diesem SSH-Ziel aus. Seine Liste argv übergibt ein Argument je Listeneintrag, ohne eine Kommandozeichenfolge durch eine Shell interpretieren zu lassen. Die Option --input wählt das Quellverzeichnis, --output das Ergebnisverzeichnis und --station beschriftet das Ergebnis mit der Station. Kein Quellfoto wird bearbeitet.
{{ variable }} setzt einen Ansible-Wert ein. inventory_hostname ist der Inventory-Name des aktuellen Hosts; playbook_dir ist das Verzeichnis des Playbooks auf dem Controller. gather_facts: false überspringt Maschineninformationen, die dieser Fotojob nicht benötigt.
Das Modul fetch überträgt eine Datei vom SSH-Ziel zum Controller, also in der Gegenrichtung von copy. Eine loop wiederholt dies für die beiden genannten Dateinamen; {{ item }} ist der aktuelle Name. Standardmäßig bewahrt fetch einen Verzeichnisbaum mit Host und Quellpfad. Hier entfernt flat: true den Quellpfad, deshalb enthält das Ziel ausdrücklich inventory_hostname. So bleiben gleichnamige Dateien unterschiedlicher Stationen getrennt. fetch erstellt benötigte Zielverzeichnisse.
Erstelle sample.yml. cat > filename schreibt eine Datei und ersetzt eine vorhandene gleichnamige Datei. <<'YAML' beginnt ein Here-Dokument: Füge den Text bis zum abschließenden YAML auf einer eigenen Zeile ein. Der zitierte Begrenzer erhält den eingefügten Text wörtlich; Ansible verarbeitet die Ausdrücke beim Ausführen des Playbooks. YAML-Einrückungen verwenden Leerzeichen:
cat > sample.yml <<'YAML'
- name: Build a small selection before scheduling both workstations
hosts: camera-north
gather_facts: false
tasks:
- name: Build the two-photo practice sheet
ansible.builtin.command:
argv:
- /usr/local/bin/photo-sheet
- --input
- "{{ input_root }}/sample"
- --output
- "{{ output_root }}/sample"
- --station
- "{{ inventory_hostname }}"
- name: Collect the practice image and file list
ansible.builtin.fetch:
src: "{{ output_root }}/sample/{{ item }}"
dest: "{{ playbook_dir }}/sample/{{ inventory_hostname }}/"
flat: true
loop:
- contact-sheet.png
- files.csv
YAML
Prüfe vor dem Start die Syntax. --syntax-check prüft die Playbook-Struktur, verarbeitet aber keine Fotos:
ansible-playbook sample.yml --syntax-check
Kopiere bei einem Schreib- oder Einrückungsfehler das ganze Playbook erneut und wiederhole die Syntaxprüfung. Führe es jetzt aus:
ansible-playbook sample.yml
Die Bildaufgabe ist standardmäßig synchron: Ansible wartet auf das Programmende, bevor es Dateien abholt. Die Zusammenfassung sollte failed=0 und unreachable=0 zeigen. Ein Fotojob verarbeitet Daten und kann changed melden; bei einem erneuten Bildverarbeitungslauf können wieder Änderungen entstehen.
Lies die abgeholte Dateiliste:
cat sample/camera-north/files.csv
Der Kopf lautet station,batch,position,filename,sha256,width,height. Es sollten zwei Datenzeilen für camera-north und sample vorhanden sein, in derselben Reihenfolge von links nach rechts wie die Bilder. Die Dateien heißen frame-01.jpg und frame-02.jpg. SHA256 ist ein Fingerabdruck des Inhalts jeder Quelldatei; du musst die langen Werte nicht auswendig lernen. Die Maße beschreiben das Originalfoto, nicht dessen kleine Vorschau.
Wechsle zu Photo Desk und lade neu. Verwende unter Small practice sheet den Link Open contact sheet, um dein echtes Ergebnis aus zwei Fotos anzusehen. Gehe mit Back to photo desk zurück und nutze anschließend Download contact sheet (PNG) und Download file list (CSV) in dieser Karte. Öffne das heruntergeladene Bild und die CSV: Beide Fotos, Dateinamen und Zeilenreihenfolge müssen zusammenpassen. Bei wiederholten Downloads kann der Browser eine Nummer zum Dateinamen hinzufügen.
Die folgende Übungskarte zeigt das tatsächliche Bild mit zwei Fotos und beide Downloadlinks. Prüfe vor der Verwendung der Dateien die Station und die Kennzeichnung sample.

Meldet ein Befehl „No such file or directory“, zeigt ls das aktuelle Verzeichnis zur Kontrolle der Schreibweise. Kehre mit cd /home/labex/project zum Arbeitsverzeichnis zurück und wiederhole den passenden Befehl. Bewahre alle Quellfotos, historischen Referenzen, Redaktionsnotizen und vorbereiteten Verbindungen. Die größeren aktuellen Auswahlen wurden noch nicht erstellt.
Vor dem Abholen auf jeden Job warten
In diesem Schritt startest du die aktuellen Auswahlen auf beiden Stationen, wartest auf den jeweils eigenen erfolgreichen Host-Job und holst die passenden Dateien ohne Namenskollisionen ab.
Bleibe in Controller, in /home/labex/project. Die Gruppe cameras wählt beide Ziele; das jeweilige photo_batch wählt weiterhin deren vorbereitete Eingabe. Nutze diese Variablen, damit derselbe Ablauf andere Mitglieder, Stapelnamen und Verzeichnisse verarbeiten kann, ohne die beiden Stationsnamen oder Eingabepfade fest einzutragen.
Eine synchrone Aufgabe wartet, bevor Ansible zur nächsten wechselt. Mit async: 120 gibt Ansible der entfernten Operation ein Laufzeitbudget von 120 Sekunden. poll: 0 startet sie, ohne in dieser Aufgabe auf ihren Abschluss zu warten. Ein erfolgreicher Start ist noch keine erfolgreiche Verarbeitung: Der entfernte Job kann weiterhin mit einem Fehler enden.
register: photo_job speichert das Startergebnis für jeden Inventory-Host getrennt. Seine ansible_job_id identifiziert diesen Job auf diesem Host. Die JID einer Station lässt sich nicht auf der anderen Station abfragen. Das Modul debug zeigt die gespeicherten Beobachtungen und damit die verschiedenen Zuordnungen.
async_status fragt denselben Host nach seiner JID und speichert jede Antwort in photo_result. until: photo_result is finished wiederholt die Abfrage, bis das native Abschlussflag wahr ist; retries: 60 begrenzt die Wiederholungen und delay: 1 wartet jeweils eine Sekunde. Wiederholt werden Statusabfragen, keine neuen Fotojobs. SSH und Verarbeitung verursachen zusätzliche Laufzeit. Ein kleiner echter Stapel kann schon vor der ersten Abfrage fertig sein; diese Übung fügt keine künstliche Verzögerung hinzu.
Der Abschluss allein belegt keinen Erfolg. Das rc des entfernten Programms ist sein Exit-Code: Null bedeutet Erfolg. async_status gibt ein Ergebnis ungleich null standardmäßig als Fehler weiter. Das zusätzliche assert macht die Anforderung Exit-Code null ausdrücklich; es wandelt keinen Fehler in Erfolg um. Die folgende Debug-Ausgabe zeigt vor dem Abholen die tatsächlichen Werte von finished und rc. Ein gleichwertiger Ablauf kann ohne diese Zusatzprüfung die native Fehlerweitergabe des Moduls verwenden.
Beide Hosts erzeugen auf ihren eigenen Dateisystemen dieselben Namen, contact-sheet.png und files.csv. Hole sie erst nach erfolgreichem Abschluss ab und bewahre jedes Paar unter seinem Inventory-Host-Verzeichnis auf dem Controller auf. Photo Desk kann diese ausdrücklich flache Ablage oder die standardmäßige Host-/Quellpfad-Hierarchie innerhalb des Stationsordners lesen. Fehlende Sammlungen werden niemals aus Referenzdateien ergänzt.
Schreibe process-photos.yml mit demselben zitierten Here-Dokument wie im vorherigen Schritt:
cat > process-photos.yml <<'YAML'
- name: Build and collect each workstation's current photo selection
hosts: cameras
gather_facts: false
tasks:
- name: Start this workstation's contact sheet
ansible.builtin.command:
argv:
- /usr/local/bin/photo-sheet
- --input
- "{{ input_root }}/{{ photo_batch }}"
- --output
- "{{ output_root }}"
- --station
- "{{ inventory_hostname }}"
async: 120
poll: 0
register: photo_job
- name: Show the job assigned to this workstation
ansible.builtin.debug:
msg:
workstation: "{{ inventory_hostname }}"
job: "{{ photo_job.ansible_job_id }}"
- name: Wait for this workstation's own job
ansible.builtin.async_status:
jid: "{{ photo_job.ansible_job_id }}"
register: photo_result
until: photo_result is finished
retries: 60
delay: 1
- name: Require successful processing before collecting
ansible.builtin.assert:
that: photo_result.rc == 0
- name: Read the actual completion result
ansible.builtin.debug:
msg:
workstation: "{{ inventory_hostname }}"
finished: "{{ photo_result.finished }}"
rc: "{{ photo_result.rc }}"
- name: Collect the image and its file list by workstation
ansible.builtin.fetch:
src: "{{ output_root }}/{{ item }}"
dest: "{{ collection_root }}/{{ inventory_hostname }}/"
flat: true
loop:
- contact-sheet.png
- files.csv
YAML
Prüfe die Syntax:
ansible-playbook process-photos.yml --syntax-check
Starte dann die tatsächliche Verarbeitung:
ansible-playbook process-photos.yml
Jede Station sollte ihre eigene Job-ID und anschließend finished: true und rc: 0 in der Abschlussnachricht anzeigen. Die abschließende Zusammenfassung sollte für beide Hosts failed=0 und unreachable=0 melden. Die Nordauswahl enthält drei Fotos, die Südauswahl sechs. Die tatsächlichen Jobs können zu unterschiedlichen Zeiten enden. Dieser Lauf zeigt echte asynchrone Ausführung, keine Leistungsgarantie für größere Arbeitslasten.
Lies beide abgeholten Listen:
cat collected/camera-north/files.csv
cat collected/camera-south/files.csv
Die Felder station und batch müssen zur Zuweisung des jeweiligen Hosts passen. Gleiche Dateinamen bedeuten keine gleichen Quellfotos. Position, Name, Fingerabdruck und Maße jeder Zeile beschreiben ein tatsächliches Eingabebild; der Kontaktbogen verwendet dieselbe Reihenfolge.
Wechsle zu Photo Desk und lade neu. Öffne unter Current collections für jede Station Open contact sheet. Prüfe die Kontaktbögen mit drei beziehungsweise sechs Fotos in voller Größe und verwende dazwischen Back to photo desk. Lade PNG und CSV jeder Station herunter, öffne beide Dateien und prüfe Bilder sowie vollständige Datenzeilen. Referenz und kleine Übungssammlung müssen verfügbar bleiben.
Vergleiche die Host- und Stapelkennzeichnungen der beiden Karten. Der Nordbogen hat eine Reihe mit drei Bildern; der Südbogen hat zwei Reihen mit je drei Bildern aus einer anderen Auswahl.

Auch ein beendeter Job kann fehlgeschlagen sein
Wechsle zurück zu Controller. Wähle nun absichtlich nur auf der Nordstation eine nicht vorhandene Eingabe. --limit camera-north begrenzt den Aufruf auf diesen Inventory-Host. --extra-vars photo_batch=missing überschreibt die Stapelvariable nur für diesen Aufruf und bearbeitet keine vorbereitete Variablendatei. Der Job startet und meldet danach eine abgeschlossene, aber fehlgeschlagene Verarbeitung. Die vorhandenen guten Dateien sind kein neuer Erfolgsnachweis.
Dieser Befehl soll fehlschlagen:
ansible-playbook process-photos.yml --limit camera-north --extra-vars photo_batch=missing
Zeige unmittelbar den Status des vorherigen Befehls an. $? enthält den Exit-Code des letzten Befehls; echo gibt ihn aus. Ein anderer vorher ausgeführter Befehl würde den Wert ersetzen:
echo $?
Erwarte einen Ansible-CLI-Code ungleich null, normalerweise 2. In der Fehlermeldung ist das entfernte Ergebnis beendet, das Programm hat rc gleich 2 und der Fehler nennt /srv/photo-sheets/batches/missing. CLI-Code und entfernter Programmcode sind unterschiedliche Werte; hier sind beide zufällig 2. Ein beendeter fehlerhafter Job ist kein erfolgreiches Abholen. Die fetch-Aufgabe darf für diesen fehlgeschlagenen Versuch nicht laufen. Die Südstation liegt außerhalb dieses Aufrufs.
Korrigiere die Auswahl mit dem vorbereiteten Standardwert und wiederhole nur die Nordstation:
ansible-playbook process-photos.yml --limit camera-north
Der Lauf muss erfolgreich sein und das echte Ergebnis von morning-walk abholen. Die Südsammlung bleibt von ihrem erfolgreichen Job verfügbar. Kehre zu Photo Desk zurück, lade neu und lade PNG und CSV des Nordens erneut herunter, um die richtige Auswahl mit drei Fotos zu bestätigen. Halte process-photos.yml wiederverwendbar, bewahre alle Originalfotos und historischen Ergebnisse und halte die Redaktionsnotizen privat.
Nutze bei gewöhnlichen YAML- oder Namensfehlern das zuvor erklärte ls, die Verzeichnisrückkehr und die Korrektur des ganzen Blocks; prüfe dann erneut die Syntax. Setze die VM nicht zurück und verändere kein Quellfoto, um einen Eingabefehler zu verdecken. Ein wiederholter erfolgreicher Fotojob verarbeitet erneut; eine unveränderte fetch-Prüfsumme bedeutet nicht, dass keine Verarbeitung stattfand.
Ansible behält nach poll: 0 einen Statuscache. Nach dem Prüfen eines beendeten Jobs kann async_status mit mode: cleanup und der jid dieses Hosts den Cacheeintrag entfernen. Diese Wartung ist hier optional. Das Bereinigen beendet keinen laufenden Job und löscht keinen Kontaktbogen.
Zusammenfassung
Du hast einen echten kleinen Kontaktbogen erstellt und anschließend mit Ansible zwei hostbezogene asynchrone Jobs gestartet und abgewartet. Du hast das vollständige Bild/CSV-Paar je Station abgeholt, einen abgeschlossenen Fehler von einem Erfolg unterschieden und eine fehlende Eingabe durch erneutes Ausführen nur des betroffenen Hosts korrigiert.



