Das Problem: Statische Listen in Ansible Tower Surveys
Stehen Sie auch vor der Herausforderung, Auswahllisten (Surveys) in Ansible Tower oder dem Automation Controller manuell pflegen zu müssen? Veraltete Einträge führen zu Fehlern und hohem Aufwand. In dieser Anleitung zeigen wir Ihnen Schritt für Schritt, wie Sie Ihre Surveys mithilfe eines Playbooks dynamisch aktualisieren und so Ihren Self-Service-Katalog automatisieren.
Ansible automatisiert Konfiguration und Orchestrierung agentlos über SSH. Für größere Umgebungen bietet Ansible Tower bzw. der heutige Automation Controller eine Web-UI, RBAC, Inventories, Credentials, Scheduling, API und Workflows. Surveys dienen als Frontend für Self-Service-Workflows. Standardmäßig sind sie statisch. Über die REST-API lassen sich die Choices jedoch dynamisch aktualisieren – etwa wenn Services, DNS-Zonen oder Cluster-Namen aus externen Systemen kommen.
Es wird von Redhat unterstützt, hat aber eine starke Open-Source-Community, die alle Arten von Playbooks und Rollen schreibt, die „Rezepte“ sind, die einfach installiert und gegen die Ziele verwendet werden können. Ansible eignet sich hervorragend für die Verwendung über die CLI, aber wenn eine komplexe Landschaft zu verwalten ist, kommt Ansible Tower (AWX in seiner Open-Source-Version) zum Einsatz. Mit Ansible Tower können die Administratoren Workflows schreiben, d. h. Gruppen von Playbooks, die eine Survey als Frontend haben können, so dass die Benutzer sich einfach selbst bedienen und auswählen können, welche Art von Ressourcen sie konfigurieren/löschen möchten.
Die Surveys sind derzeit „statisch“, aber da Ansible Tower auch eine API zur Verfügung hat, bedeutet dies, dass wir sie manipulieren können, um sie dynamisch zu ändern, indem wir das Community-uri-Modul und den Ansible Tower selbst als Ziel verwenden.
Das Hauptziel ist es, die Auswahlliste in einer Umfrage dynamisch zu aktualisieren. Die Informationen zu den Listenelementen stammen dabei aus einer anderen Quelle oder demselben Tower-Host.
In unserem Beispiel verwenden wir einen Workflow, um einen Dienst zu entfernen, dessen Liste dann automatisch aktualisiert wird.
Schritt-für-Schritt: Das Playbook zur dynamischen Aktualisierung
Du kannst den Subtask in meinem Github Repo verwenden, indem du die Ziel-Workflow-ID und die aktualisierte Liste übergibst und den match_key und match_value festlegst, die ersetzt werden sollen.
So sieht der Survey des Workflows in der GUI aus:
Und so sieht die Survey in der API-Perspektive aus:
Unser Ziel ist es, den Wert „choices“ im ersten Element der „spec„-Liste (die eigentlich ein Dictionary ist) zu aktualisieren, ohne die anderen Elemente in der Survey zu verändern.
Nehmen wir an, die Service-Liste existiert bereits an anderer Stelle (z. B. in einer Firewall) und es kommt ein neuer Dienst hinzu, der in der Survey aktualisiert werden muss.
Für unser Beispiel habe ich die neue Liste der Einfachheit halber manuell erstellt, aber diese sollte von einer anderen API kommen.
- name: services_list build
set_fact:
services_list: “service1\nservice2\nservice3\nservice4\nservice5\n"
- name: services_list debug
debug:
msg: "{{ services_list }}"
Sobald ich die neue Auswahlliste habe, brauche ich die target_template_id, die in der API URL zu sehen ist.
Dann können wir die Subtasks wie folgt verwenden:
- name: Update surveys for workflow job templates
include: survey_update.yml template_id={{ target_template }} new_services_list={{ new_services_list }}
Anschließend springen wir zur Teilaufgabe survey_update.yml, in der die aktuelle Survey abgerufen wird:
- name: "Get current survey from {{ template_id }} survey"
uri:
url: "{{ tower_endpoint }}workflow_job_templates/{{ template_id }}/survey_spec/"
method: GET
user: "{{ tower_user }}"
password: "{{ tower_pass }}"
validate_certs: False
force_basic_auth: yes
status_code: 200
body_format: json
register: current_survey
Im nächsten Schritt erstellen wir zwei Listen. Eine mit der Zielspezifikation (target_spec_list), die wir ändern wollen, und eine weitere Liste mit allen anderen Elementen (trimmed_spec_list), die wir später hier verwenden:
- name: "Remove the list element which contains {{ match_value }} variable"
set_fact:
trimmed_spec_list: "{{ current_survey.json.spec|rejectattr( match_key , 'match', match_value)|list }}"
- name: "Select target survey which contains {{ match_value }} variable"
set_fact:
target_spec_list: "{{ current_survey.json.spec|selectattr( match_key , 'match', match_value)|list }}"
Um festzulegen, welche Umfrage ausgewählt werden soll, verwende ich zwei generische Variablen, die in vars/main.yml enthalten sind:
tower_endpoint: "https://tower.organization.org/api/v2/"
target_template: 89
match_key: "variable"
match_value: "service" # the value to match in the survey list element
Das bedeutet, dass der Key als “variable” fungiert und der Wert in unserem Fall als “service”. Der Einfachheit halber habe ich hier als Key “variable” rausgesucht, ohne dass es ein zwangsläufiges Erfordernis ist.
Jetzt extrahieren wir das erste Dict-Element und ersetzen den Wert „choices„, der als Variable an die Unteraufgabe übergeben wurde:
- name: "extract the survey dict that matches {{ match_value }} variable"
set_fact:
new_survey_dict: "{{ target_spec_list[0] }}"
- name: replace the choices element in the dict
set_fact:
new_survey_dict: "{{ new_survey_dict | combine(new_item, recursive=true) }}"
vars:
new_item: { 'choices': "{{ new_services_list }}" }
with_dict: "{{ new_survey_dict }}"
Jetzt können wir die aktualisierte_spec_list nutzen. Diese fügst du einfach zur trimmed_spec_list hinzu, die wir am Anfang genommen haben, um die final_spec_list zu erstellen:
- name: Create the new services list element with updated choices
set_fact:
updated_spec_list: "{{ updated_spec_list | default([]) + [ new_survey_dict] }}"
- name: Generate the new spec list
set_fact:
final_spec_list: "{{ updated_spec_list + trimmed_spec_list }}"
Zum Schluss erstellen wir den erforderlichen json-Payload mit der aktualisierten Survey und stellen ihn zurück in den Tower:
- name: Create and add items to new_survey dictionary
set_fact:
new_survey: "{{ new_survey | default({}) | combine ({ item.key : item.value }) }}"
with_items:
- { 'key': 'description' , 'value': ''}
- { 'key': 'name' , 'value': ''}
- { 'key': 'spec' , 'value': "{{ final_spec_list }}" }
- name: "put the survey back on {{ template_id }} survey playbook"
uri:
url: "{{ tower_endpoint }}workflow_job_templates/{{ template_id }}/survey_spec/"
method: POST
user: "{{ tower_user }}"
password: "{{ tower_pass }}"
validate_certs: False
force_basic_auth: yes
status_code: 200
body:
"{{ new_survey }}"
body_format: json
Nachdem das Ansible Playbook gelaufen ist, aktualisieren wir die Survey mit der neuen Dienstliste:
Hinweise aus der Praxis
– RBAC: Der Service-Account braucht Rechte auf das Workflow Job Template und Survey.
– Idempotenz: Die Choices als deterministische Liste generieren (z. B. sortiert), damit Git-Diffs und Runs stabil bleiben.
– Security: Token-Auth bevorzugen, Credentials im Vault halten.
– Scheduling: Per Controller-Schedule regelmäßig aktualisieren oder via Webhook triggern (GitOps, Jenkins, GitLab CI).
– Logging/Monitoring: API-Antworten loggen, Fehlerfälle behandeln, Activity Stream prüfen.
Ergebnis
Die Survey-Choices werden automatisiert aktualisiert. Nutzer wählen in der Web-UI stets gültige Optionen, Workflows bleiben robust und es sind keine manuellen Anpassungen nötig – egal ob die Daten aus Inventory, CMDB, Firewall-API oder Git kommen.
Fazit



