Ansible utilise Jinja2 pour le filtre des variables.
Souhaitez-vous parfois fusionner en profondeur des variables, y compris des dictionnaires? Aujourd'hui, je vais vous présenter deux façons de réaliser une fusion profonde de variables avec Ansible. Ce qui est différent, c'est que la méthode est différente pour Ansible 2.0 et supérieur et inférieur.
Un nouveau ** filtre de combinaison ** a été implémenté depuis Ansible 2.0. http://docs.ansible.com/ansible/playbooks_filters.html#combining-hashes-dictionaries
test.yml
- hosts: localhost
gather_facts: no
vars:
dict:
foo:
bar: 1
dict2:
foo:
baz: 2
qux: 2
# combining hashes/dictionaries (new in version 2.0)
dict_combine: "{{ dict | combine(dict2, recursive=True) }}"
tasks:
- debug:
var: dict_combine
Si vous faites ce qui précède, vous obtiendrez les résultats suivants.
$ ansible-playbook -i localhost, test.yml
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"dict_combine": {
"foo": {
"bar": 1,
"baz": 2
},
"qux": 2
}
}
C'est très pratique. Le contenu de dict-> foo est correctement fusionné. À propos, omettre «récursif» n'est qu'une fusion de mise à jour.
recursive=false
$ ansible-playbook -i localhost, test.yml
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"dict_combine": {
"foo": {
"baz": 2
},
"qux": 2
}
}
À propos, la fonction équivalente à combiner qui omet récursive pourrait être réalisée comme suit en utilisant update () même dans la version antérieure à Ansible 2.0.
test.yml
- hosts: localhost
gather_facts: no
vars:
dict:
foo:
bar: 1
dict2:
foo:
baz: 2
qux: 2
# **[Note]**
# jinja2 'do' tag need expression-statement extension
# please set below to [default] section in ansible.cfg
# jinja2_extensions=jinja2.ext.do
dict_update: |
{% do dict.update(dict2) %}
{{ dict }}
tasks:
- debug:
var: dict_update
Si vous devez utiliser Ansible 1.X pour diverses raisons, c'est un peu gênant car vous ne pouvez pas utiliser combiner. Bien sûr, vous pouvez importer la partie source de la moissonneuse-batteuse implémentée en 2.0, mais comme c'est un gros problème, j'aimerais créer mon propre plugin Filter. http://docs.ansible.com/ansible/developing_plugins.html#filter-plugins
Pour utiliser le plugin, mettez le chemin (filter_plugins =) dans ansible.cfg ou placez le fichier personnalisé directement dans le répertoire plugin d'ansible lui-même et il sera lu lors de l'exécution de ansible.
/path-to/ansible/filter_plugins/dict_merge.py
from copy import deepcopy
def dict_merge(a, b):
if not isinstance(b, dict):
return b
result = deepcopy(a)
for k, v in b.iteritems():
if k in result and isinstance(result[k], dict):
result[k] = dict_merge(result[k], v)
else:
result[k] = deepcopy(v)
return result
class FilterModule(object):
def filters(self):
return {'dict_merge': dict_merge}
Ceci termine la création du plug-in. C'est plus facile que vous ne le pensez. Testons-le.
test.yml
- hosts: localhost
gather_facts: no
vars:
dict:
foo:
bar: 1
dict2:
foo:
baz: 2
qux: 2
# custom filter plugin
dict_merged: "{{ dict | dict_merge(dict2) }}"
tasks:
- debug:
var: dict_merged
Le résultat de l'exécution est le suivant.
$ ansible-playbook -i localhost, test.yml
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"dict_merged": {
"foo": {
"bar": 1,
"baz": 2
},
"qux": 2
}
}
J'ai pu obtenir le même résultat que combiner. Bien sûr, il fusionne également des dicts plus profonds.
En plus du plug-in Filter, Ansible propose plusieurs plug-ins que vous pouvez créer vous-même. http://docs.ansible.com/ansible/developing_plugins.html
Les plug-ins de recherche et de rappel sont relativement informatifs et contiennent des informations sur les personnes qui font diverses choses.
Let's enjoy your Ansible life!