web-dev-qa-db-fra.com

Ajout aux listes ou ajout de clés aux dictionnaires dans Ansible

(Lié à rappels ou hooks et séries de tâches réutilisables, dans les rôles Ansible ):

Existe-t-il un meilleur moyen d'ajouter à une liste ou d'ajouter une clé à un dictionnaire dans Ansible que (ab) en utilisant une expression de modèle jina2?

Je sais que tu peux faire quelque chose comme:

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

mais n'y a-t-il vraiment aucune sorte de méta-tâche ou d'aide pour le faire?

Il semble fragile, semble ne pas être documenté et repose sur de nombreuses hypothèses sur le fonctionnement des variables dans Ansible.

Mon cas d'utilisation est constitué de plusieurs rôles (extensions de serveur de base de données) qui doivent chacun fournir une configuration à un rôle de base (le serveur de base de données). Ce n'est pas aussi simple que d'ajouter une ligne au fichier de configuration du serveur db; chaque modification s'applique à la même ligne , par ex. les extensions bdr et pg_stat_statements doit apparaître sur une ligne cible:

shared_preload_libaries = 'bdr, pg_stat_statements'

La façon Ansible de le faire est-elle de simplement traiter le fichier de configuration plusieurs fois (une fois par extension) avec une expression régulière qui extrait la valeur actuelle, l'analyse, puis la réécrit? Si tel est le cas, comment rendre cet idempotent sur plusieurs pistes?

Et si la configuration est plus difficile à analyser et que ce n'est pas aussi simple que d'ajouter une autre valeur séparée par des virgules? Pensez aux fichiers de configuration XML.

39
Craig Ringer

Vous pouvez fusionner deux listes dans une variable avec +. Disons que vous avez un group_vars fichier avec ce contenu:

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

Et il est utilisé dans un modèle pgsql.conf.j2 comme:

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

Vous pouvez ensuite ajouter des extensions aux serveurs de base de données de test comme ceci:

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

Lorsque le rôle est exécuté sur l'un des serveurs de test, les extensions supplémentaires sont ajoutées.

Je ne suis pas sûr que cela fonctionne également pour les dictionnaires, et soyez également prudent avec les espaces et en laissant une virgule pendant à la fin de la ligne.

16
GnP

Depuis Ansible v2.x, vous pouvez faire ceci:

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

tout ce qui précède est documenté dans: http://docs.ansible.com/ansible/playbooks_filters.html

42
Max Kovgan

vous devez diviser la boucle en 2

 --- 
 - hôtes: localhost 
 tâches: 
 - include_vars: piles 
 - set_facts: rôles = {{stacks.Roles | split ('')}} 
 - inclure: addhost.yml 
 avec_items: "{{rôles}}" 

et addhost.yml

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

Je ne sais pas quand ils ont ajouté cela, mais au moins pour les dictionnaires/hachages (PAS les listes/tableaux), vous pouvez définir la variable hash_behaviour , comme ceci: hash_behaviour = merge dans ton ansible.cfg.

Cela m'a pris quelques heures pour tomber accidentellement sur ce paramètre: S

1
nuts

Presque toutes les réponses ici nécessitent des changements dans les tâches, mais j'avais besoin de fusionner dynamiquement les dictionnaires dans la définition de vars, pas pendant l'exécution.

Par exemple. Je souhaite définir des variables partagées dans allgroup_vars puis je veux les étendre dans d'autres group ou Host_vars. Très utile lorsque vous travaillez pour des rôles.

Si vous essayez d'utiliser les filtres combine ou union en écrasant la variable d'origine dans les fichiers var, vous vous retrouverez en boucle infinie pendant les modèles, j'ai donc créé cette solution de contournement (ce n'est pas une solution).

Vous pouvez définir plusieurs variables en fonction d'un modèle de nom, puis les charger automatiquement dans le rôle.

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

extrait de code de rôle

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

C'est juste un extrait, mais vous devriez avoir une idée de comment cela fonctionne. note: lookup ('varnames', '') est disponible depuis ansible 2.8

Je suppose qu'il serait également possible de fusionner toutes les variables dictionary_of_bla.* dans un dictionnaire pendant l'exécution en utilisant la même recherche.

L'avantage de cette approche est que vous n'avez pas besoin de définir des listes exactes de noms de variables, mais seuls le modèle et l'utilisateur peuvent le définir dynamiquement.

0
VeselaHouba