Aggiunta ad elenchi o aggiunta di chiavi ai dizionari in Ansible


34

(Relativo a callback o hook e serie riutilizzabili di attività, in ruoli Ansible ):

Esiste un modo migliore per aggiungere a un elenco o aggiungere una chiave a un dizionario in Ansible rispetto a (ab) usando un'espressione template jina2?

So che puoi fare qualcosa del tipo:

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

ma non esiste davvero alcun tipo di meta task o aiuto per farlo?

Sembra fragile, sembra non documentato e si basa su molte ipotesi su come funzionano le variabili in Ansible.

Il mio caso d'uso è costituito da più ruoli (estensioni del server di database), ciascuno dei quali deve fornire una configurazione a un ruolo di base (il server di database). Non è semplice come aggiungere una riga al file di configurazione del server db; ogni modifica si applica alla stessa linea , ad esempio le estensioni bdre pg_stat_statementsdevono apparire entrambe su una linea target:

shared_preload_libaries = 'bdr, pg_stat_statements'

Il modo Ansible è fare questo per elaborare il file di configurazione più volte (una volta per estensione) con una regexp che estrae il valore corrente, lo analizza e quindi lo riscrive? Se è così, come lo fai idempotente su più corse?

Che cosa succede se la configurazione è più difficile da analizzare e non è così semplice come aggiungere un altro valore separato da virgola? Pensa ai file di configurazione XML.


Sai una cosa? Mi piace il taglio del tuo braccio
pieno

Risposte:


13

È possibile unire due elenchi in una variabile con +. Supponi di avere un group_varsfile con questo contenuto:

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

Ed è utilizzato in un modello pgsql.conf.j2come:

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

È quindi possibile aggiungere estensioni ai server del database di test in questo modo:

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

Quando il ruolo viene eseguito in uno dei server di test, verranno aggiunte le estensioni adizionali.

Non sono sicuro che funzioni anche per i dizionari, e fai anche attenzione agli spazi e lascia una virgola penzolante alla fine della riga.


Puoi, ma devi fare tutto group_vars, i ruoli non possono prendersi cura dei dettagli della configurazione delle estensioni stesse. Sta aggiungendo vari ruoli che sto particolarmente cercando, quindi un ruolo può essere aggiunto a un var esposto da un altro ruolo.
Craig Ringer,

Il tuo ruolo di base conosce ogni ruolo di estensione? Ho avuto un caso simile in cui sono stato in grado di lasciare la concatenazione fino a una with_itemspena.
GnP,

no, e questo è davvero il problema. In una distribuzione il ruolo di base potrebbe essere al
Craig Ringer il

4
Sembra che se provi a fare questo per concatenare due elenchi, pensa che sia un modello infinitamente ricorsivo perché anche il lato sinistro è sul lato destro. Sto fraintendendo come usare questo?
Ibrahim,

2
@spectras Almeno da Ansible 2.7 questo NON funziona. Come suggerito da Ibrahim, ciò causa un errore: "loop ricorsivo rilevato nella stringa del modello".
rluba,

35

Da Ansible v2.x è possibile eseguire queste operazioni:

# 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' }

tutto quanto sopra è documentato in: http://docs.ansible.com/ansible/playbooks_filters.html


1
il caso d'uso IV si limita ad aggiungereu'(': u\"'\"}"
ssc il

1
grazie @ssc. Ho notato che non funziona con ansible 2.4.x(RISOLTO)
Max Kovgan,

secondo il caso d'uso 4 #, ho aggiunto il valore di default per gestire l' errore non definito nel mio scenario: set_fact: my_dict_var: '{{my_dict_var|default({})|combine({item[0]: item[1]})}}'. L'errore indefinito arriva quando viene utilizzato un filtro o non viene registrato alcun risultato.
SK Venkat,

Signor SK Venkat, il codice di esempio qui mostra solo cose molto specifiche (aggiunta di voci di dizionario dalle tuple). Se devi fare qualcos'altro, questo codice non è il tuo copia-incolla.
Max Kovgan,

3

devi dividere il loop in 2

--- 
- host: localhost
  compiti: 
    - include_vars: stack
    - set_facts: ruoli = {{stacks.Roles | Diviso(' ')}}
    - include: addhost.yml
      with_items: "{{ruoli}}"

e addhost.yml

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

1

Non sono sicuro quando hanno aggiunto questo, ma almeno per dizionari / hash (NON elenchi / array), puoi impostare la variabile hash_behaviour , in questo modo: hash_behaviour = mergenel tuo ansible.cfg.

Mi ci sono volute alcune ore per inciampare accidentalmente in questa impostazione: S


questo è molto utile, ma attenzione per abilitarlo e2e sulla base di codice esistente. potrebbe rompere alcune uova.
Max Kovgan,

0

Quasi tutte le risposte qui richiedono cambiamenti nelle attività, ma avevo bisogno di unire dinamicamente i dizionari nella definizione di Vars, non durante l'esecuzione.

Ad esempio, voglio definire alcuni var condivisi in all group_varse poi voglio estenderli in qualche altro groupo host_vars. Molto utile quando si lavora per ruoli.

Se provi a usare i filtri combineo unionsovrascrivendo la variabile originale in file var, finirai con un ciclo infinito durante il modello, quindi ho creato questa soluzione alternativa (non è una soluzione).

È possibile definire più variabili in base a un modello di nome e quindi caricarle automaticamente nel ruolo.

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

snippet di codice ruolo

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] }}"

È solo uno snippet, ma dovresti avere l'idea di come funziona. nota: lookup ('varnames', '') è disponibile da Ansible 2.8

Immagino che sarebbe anche possibile unire tutte le variabili dictionary_of_bla.*in un dizionario durante il runtime usando la stessa ricerca.

Il vantaggio di questo approccio è che non è necessario impostare elenchi esatti di nomi di variabili, ma solo il modello e l'utente possono impostarlo in modo dinamico.


-4

Ansibleè un sistema di automazione e, per quanto riguarda la gestione dei file di configurazione, non è molto diverso da apt. Il motivo per cui un numero sempre maggiore di software offre la funzione di leggere frammenti di configurazione da una conf.ddirectory è di consentire a tali sistemi di automazione di avere pacchetti / ruoli diversi che aggiungono configurazione al software. Credo che non sia la filosofia di Ansiblefare ciò che hai in mente, ma invece di usare il conf.dtrucco. Se il software in fase di configurazione non offre questa funzionalità, potresti avere dei problemi.

Dato che menzioni i file di configurazione XML, ne approfitto per lamentarmi. C'è un motivo per la tradizione Unix di usare file di configurazione in testo semplice. I file di configurazione binari non si prestano bene all'automazione del sistema, quindi qualsiasi tipo di formato binario ti darà problemi e probabilmente ti richiederà di creare un programma per gestire la configurazione. (Se qualcuno pensa che XML sia un formato di testo semplice, dovrebbe andare a far esaminare il proprio cervello.)

Ora, sul tuo PostgreSQLproblema specifico . PostgreSQLsupporta il conf.dtrucco. Innanzitutto, vorrei verificare se è shared_preload_librariespossibile specificare più volte. Non ho trovato alcun suggerimento nella documentazione che può, ma lo proverei comunque. Se non può essere specificato più volte, spiegherei il mio problema ai PostgreSQLragazzi nel caso avessero delle idee; questo è un PostgreSQLproblema e non un Ansibleproblema. Se non esiste una soluzione e non potrei davvero unire i diversi ruoli in uno, implementerei un sistema per compilare la configurazione sull'host gestito. In questo caso, probabilmente sarei creare uno script /usr/local/sbin/update_postgresql_configche avrebbe compilato /etc/postgresql/postgresql.conf.jinjain /etc/postgresql/9.x/main/postgresql.conf. Lo script legge le librerie di precarico condivise da /etc/postgresql/shared_preload_libraries.txtuna libreria per riga e le fornisce a jinja.

Non è raro che i sistemi di automazione facciano questo. Un esempio è il exim4pacchetto Debian .


PostgreSQL supporta un conf.dmeccanismo di inclusione e per fortuna utilizza file di testo normale. Tuttavia, ci sono alcune opzioni di configurazione in cui più estensioni possono avere opinioni al riguardo - ad esempio "aumentare max_wal_senders di 10 da qualunque cosa fosse prima".
Craig Ringer,

4
Sembra che tu stia dicendo che l'applicazione dovrebbe essere modificata per aggirare le limitazioni nel sistema di gestione della configurazione, o dovrei rinunciare ad avere ruoli riutilizzabili.
Craig Ringer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.