(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.
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.
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
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}}
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
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 all
group_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.