An Listen anhängen oder Schlüssel zu Wörterbüchern in Ansible hinzufügen

34

(Bezogen auf Rückrufe oder Hooks und wiederverwendbare Aufgabenserien in Ansible-Rollen ):

Gibt es eine bessere Möglichkeit, an eine Liste anzuhängen oder einem Wörterbuch in Ansible einen Schlüssel hinzuzufügen, als (ab) einen jina2-Vorlagenausdruck zu verwenden?

Ich weiß, dass Sie so etwas tun können:

- name: this is a hack
  shell: echo "{% originalvar.append('x') %}New value of originalvar is {{originalvar}}"

Aber gibt es wirklich keine Meta-Aufgabe oder einen Helfer dafür?

Es fühlt sich zerbrechlich an, scheint undokumentiert zu sein und basiert auf vielen Annahmen darüber, wie Variablen in Ansible funktionieren.

Mein Anwendungsfall sind mehrere Rollen (Datenbankservererweiterungen), die jeweils eine Konfiguration für eine Basisrolle (den Datenbankserver) benötigen. Es ist nicht so einfach, eine Zeile an die Konfigurationsdatei des Datenbankservers anzuhängen. Jede Änderung gilt für dieselbe Zeile , z. B. die Erweiterungen, bdrund pg_stat_statementsmuss in einer Zielzeile erscheinen:

shared_preload_libaries = 'bdr, pg_stat_statements'

Ist dies die Ansible-Methode, um die Konfigurationsdatei nur mehrere Male (einmal pro Erweiterung) mit einem regulären Ausdruck zu verarbeiten, der den aktuellen Wert extrahiert, analysiert und dann neu schreibt? Wenn ja, wie macht man das über mehrere Läufe hinweg idempotent?

Was ist, wenn die Konfiguration schwerer zu analysieren ist und es nicht so einfach ist, einen anderen durch Kommas getrennten Wert anzufügen? Denken Sie an XML-Konfigurationsdateien.

Craig Ringer
quelle
Weißt du was? Ich mag den Schnitt von Ihrem Nebeneffekt-Fock ☺
DomQ

Antworten:

13

Sie können mit zwei Listen in einer Variablen zusammenführen +. Angenommen, Sie haben eine group_varsDatei mit folgendem Inhalt:

---
# group_vars/all
pgsql_extensions:
  - ext1
  - ext2
  - ext3

Und es wird in einer Vorlage verwendet pgsql.conf.j2wie:

# {{ ansible_managed }}
pgsql_extensions={% for item in pgsql_extensions %}{{ item }}, {% endfor %}

Sie können dann wie folgt Erweiterungen an die Testdatenbankserver anhängen:

---
# group_vars/testing_db
append_exts:
  - ext4
  - ext5
pgsql_extensions: "{{ pgsql_extensions + append_exts }}"

Wenn die Rolle auf einem der Testserver ausgeführt wird, werden die zusätzlichen Erweiterungen hinzugefügt.

Ich bin mir nicht sicher, ob dies auch für Wörterbücher funktioniert, und achte auch auf Leerzeichen und ein baumelndes Komma am Ende der Zeile.

GnP
quelle
Sie können, aber Sie müssen alles tun group_vars, die Rollen können sich nicht um die Details des Einrichtens der Erweiterungen selbst kümmern. Das Anhängen von Variablen von Rollen , nach denen ich besonders suche, damit eine Rolle an eine Variable angehängt werden kann, die von einer anderen Rolle verfügbar gemacht wird.
Craig Ringer
Kennt Ihre Basisrolle jede Nebenstellenrolle? Ich hatte einen ähnlichen Fall, in dem ich die Verkettung zu einem with_itemsSatz auflösen konnte.
GnP
nein, und das ist wirklich das Problem. In einem Einsatz könnte die Basisrolle al
Craig Ringer
4
Wenn Sie versuchen, dies zu tun, um zwei Listen zu verketten, scheint dies eine unendlich rekursive Vorlage zu sein, da sich die linke Seite auch auf der rechten Seite befindet. Verstehe ich das falsch?
Ibrahim
2
@spectras Zumindest ab Ansible 2.7 funktioniert dies NICHT. Wie Ibrahim vorschlug, verursacht dies einen Fehler: "Rekursive Schleife in Template-Zeichenfolge erkannt".
Rluba
35

Seit Ansible v2.x können Sie Folgendes tun:

# use case I: appending to LIST variable:

      - name: my appender
        set_fact:
          my_list_var: '{{my_list_myvar + new_items_list}}'

# use case II: appending to LIST variable one by one:

      - name: my appender
        set_fact:
          my_list_var: '{{my_list_var + [item]}}'
        with_items: '{{my_new_items|list}}'

# use case III: appending more keys DICT variable in a "batch":

      - name: my appender
        set_fact:
          my_dict_var: '{{my_dict_var|combine(my_new_keys_in_a_dict)}}'

# use case IV: appending keys DICT variable one by one from tuples
      - name: setup list of tuples (for 2.4.x and up
        set_fact:
          lot: >
            [('key1', 'value1',), ('key2', 'value2',), ..., ('keyN', 'valueN',)],
      - name: my appender
        set_fact:
          my_dict_var: '{{my_dict_var|combine({item[0]: item[1]})}}'
        with_items: '{{lot}}'
# use case V: appending keys DICT variable one by one from list of dicts (thanks to @ssc)

  - name: add new key / value pairs to dict
    set_fact:
      my_dict_var: "{{ my_dict_var | combine({item.key: item.value}) }}"
    with_items:
    - { key: 'key01', value: 'value 01' }
    - { key: 'key02', value: 'value 03' }
    - { key: 'key03', value: 'value 04' }

Alles oben Genannte ist dokumentiert in: http://docs.ansible.com/ansible/playbooks_filters.html

Max Kovgan
quelle
1
Anwendungsfall IV hängt einfach anu'(': u\"'\"}"
ssc
1
danke, @ssc. Mir ist aufgefallen, dass es mit Ansible nicht funktioniert 2.4.x(FIXED)
Max Kovgan
nach # 4 bis usecase, habe ich den Standardwert hinzugefügt , um die Handhabung undefinierten Fehler in meinem Szenario: set_fact: my_dict_var: '{{my_dict_var|default({})|combine({item[0]: item[1]})}}'. Der undefinierte Fehler tritt auf, wenn ein Teil der Filterung verwendet wird oder keine Ergebnisse registriert werden.
SK Venkat
Herr SK Venkat, der Beispielcode hier zeigt nur eine sehr spezifische Sache (Hinzufügen von Wörterbuchelementen aus Tupeln). Wenn Sie etwas anderes tun müssen, ist dieser Code nicht Ihr Kopieren-Einfügen.
Max Kovgan
3

Sie müssen die Schleife in 2 teilen

--- 
- Gastgeber: localhost
  Aufgaben: 
    - include_vars: Stapel
    - set_facts: role = {{stacks.Roles | Teilt(' ')}}
    - Include: addhost.yml
      with_items: "{{role}}"

und addhost.yml

- set_facts: groupname = {{item}}
- set_facts: ips = {{stacks [item] | split ('')}}
- local_action: add_host hostname = {{item}} groupname = {{groupname}}
  with_items: {{ips}}
Arthur Tsang
quelle
1

Sie sind sich nicht sicher, wann sie dies hinzugefügt haben, aber zumindest für Wörterbücher / Hashes (NICHT Listen / Arrays) können Sie die Variable hash_behaviour folgendermaßen festlegen : hash_behaviour = mergein Ihrem ansible.cfg.

Ich habe einige Stunden gebraucht, um versehentlich über diese Einstellung zu stolpern: S

Nüsse
quelle
Dies ist sehr praktisch, aber achten Sie darauf, es auf der vorhandenen Codebasis zu aktivieren. kann einige Eier zerbrechen.
Max Kovgan
0

Fast alle Antworten hier erfordern Änderungen in den Aufgaben, aber ich musste Wörterbücher in der VAR-Definition dynamisch zusammenführen, nicht während der Ausführung.

ZB möchte ich einige gemeinsam genutzte Variablen definieren all group_varsund sie dann in eine andere groupoder eine andere erweitern host_vars. Sehr nützlich bei der Arbeit für Rollen.

Wenn Sie versuchen, den Filter combineoder zu verwenden, der uniondie ursprüngliche Variable in var-Dateien überschreibt, werden Sie während des Vorlagenvorgangs in einer Endlosschleife enden. Daher habe ich diese Problemumgehung erstellt (dies ist keine Lösung).

Sie können mehrere Variablen basierend auf einem Namensmuster definieren und diese dann automatisch in die Rolle laden.

group_vars/all.yml

dictionary_of_bla:
  - name: blabla
    value1 : blabla
    value2 : blabla

group_vars/group1.yml

dictionary_of_bla_group1:
  - name: blabla2
    value1 : blabla2
    value2 : blabla2

Rollencode-Snippet

tasks:
  - name: Run for all dictionary_of_bla.* variations
    include_tasks: do_some_stuff.yml
    with_items: "{{ lookup('varnames','dictionary_of_bla.*').split(',') }}"
    loop_control:
      loop_var: _dictionary_of_bla

do_some_stuff.yml

- name: do magic
  magic:
    trick_name: item.name
    trick_value1: item.value1
    trick_value2: item.value2
  with_items: "{{ vars[_dictionary_of_bla] }}"

Es ist nur ein Ausschnitt, aber Sie sollten wissen, wie es funktioniert. hinweis: lookup ('varnames', '') ist seit ansible 2.8 verfügbar

Ich denke, es wäre auch möglich, alle Variablen dictionary_of_bla.*zur Laufzeit mit derselben Suche in einem Wörterbuch zusammenzuführen.

Der Vorteil dieses Ansatzes besteht darin, dass Sie keine exakten Listen mit Variablennamen festlegen müssen, sondern dass nur das Muster und der Benutzer es dynamisch festlegen können.

VeselaHouba
quelle
-4

Ansibleist ein Automatisierungssystem und unterscheidet sich in Bezug auf die Verwaltung von Konfigurationsdateien nicht wesentlich von apt. Der Grund, warum immer mehr Software die Funktion zum Lesen von Konfigurationsausschnitten aus einem conf.dVerzeichnis anbietet, besteht darin, dass solche Automatisierungssysteme unterschiedliche Pakete / Rollen zur Konfiguration der Software hinzufügen können. Ich glaube, dass es nicht die Philosophie ist, das Ansiblezu tun, was Sie vorhaben, sondern den conf.dTrick anzuwenden . Wenn die zu konfigurierende Software diese Funktionalität nicht bietet, sind Sie möglicherweise in Schwierigkeiten.

Da Sie XML-Konfigurationsdateien erwähnen, nutze ich die Gelegenheit, um ein bisschen zu jammern. Es gibt einen Grund für die Unix-Tradition, Konfigurationsdateien im Klartext zu verwenden. Binäre Konfigurationsdateien eignen sich nicht gut für die Systemautomatisierung, sodass Sie bei jeder Art von Binärformat Probleme haben und wahrscheinlich ein Programm für die Konfiguration erstellen müssen. (Wenn jemand der Meinung ist, dass XML ein reines Textformat ist, sollte er sein Gehirn untersuchen lassen.)

Nun zu Ihrem spezifischen PostgreSQLProblem. PostgreSQLunterstützt den conf.dTrick. Zunächst würde ich prüfen, ob shared_preload_librariesmehrmals angegeben werden kann. Ich habe keinen Hinweis in der Dokumentation gefunden, dass es geht, aber ich würde es trotzdem versuchen. Wenn es nicht mehrmals angegeben werden kann, würde ich den PostgreSQLJungs mein Problem erklären, falls sie Ideen haben; Dies ist ein PostgreSQLProblem und kein AnsibleProblem. Wenn es keine Lösung gibt und ich die verschiedenen Rollen wirklich nicht zu einer zusammenführen könnte, würde ich ein System implementieren, um die Konfiguration auf dem verwalteten Host zu kompilieren. In diesem Fall würde ich wahrscheinlich ein Skript /usr/local/sbin/update_postgresql_configerstellen, /etc/postgresql/postgresql.conf.jinjain das kompiliert wird /etc/postgresql/9.x/main/postgresql.conf. Das Skript würde die gemeinsam genutzten Preload-Bibliotheken von /etc/postgresql/shared_preload_libraries.txteiner Bibliothek pro Zeile lesen und sie Jinja zur Verfügung stellen.

Dies ist für Automatisierungssysteme nicht ungewöhnlich. Ein Beispiel ist das Debian- exim4Paket.

Antonis Christofides
quelle
PostgreSQL unterstützt einen conf.dInclude-Mechanismus und verwendet dankenswerterweise Klartextdateien. Es gibt jedoch einige Konfigurationsoptionen, bei denen mehrere Erweiterungen Meinungen dazu haben können - z. B. "Erhöhen Sie max_wal_senders um 10 gegenüber dem vorherigen Wert".
Craig Ringer
4
Anscheinend sagen Sie, dass die Anwendung geändert werden sollte, um Einschränkungen im Konfigurationsverwaltungssystem zu umgehen, oder ich sollte auf wiederverwendbare Rollen verzichten.
Craig Ringer