Aller au contenu principal

Ecrire des plugins de filtres Ansible

· 4 minutes de lecture
Stéphane ROBERT

logo ansible

Parfois manipuler des données directement dans les playbooks Ansible peut être fastidieux ! C'est là qu'interviennent les filtres Ansible. Mais parfois pas de solutions simples.

C'est là qu'il faut utiliser les plugins de filtres. Les plugins de filtres vous vous permettre de gérer vos données directement avec du code Python. Une fois que vous saurez comment le faire, vous ne pourrez plus vous en passer. Mais attention à chaque nouvelle release d'Ansible de nouveaux filtres apparaissent.

Je vous ai écris plusieurs billets sur le sujet : 1, 2 et 3

Passons au code pour transformer une string SnakeCaze à une CamelCaze

Nous voulons transformer une string formatée en snake_case à une autre en CamelCaze. Écrivons une simple boucle qui va itérer sur chaque élément d'un split avec le caractère '_', les passer en majuscule et concaténer le tout.

def snake_to_camel(text):
import re
return ''.join(x.title() or '_' for x in text.split('_'))

Écriture du plugin de filtre Ansible

Il suffit d'ajouter à la fin de votre programme python la définition de la classe FilterModule.

class FilterModule(object):

def filters(self):
return {
'snaketocamel': snake_to_camel
}

Ensuite enregistrer vos programmes dans le répertoire filter_plugins. Si vous voulez utiliser un autre répertoire il faudra l'indiquer dans votre fichier ansible.cfg

[default]
filter_plugins = /path/to/filter/plugins

Utilisation de votre filtre dans un playbook

Rien de plus simple. Écrivez ceci dans un fichier que vous nommerez test.yml

---
- hosts: localhost
gather_facts: false
vars:
text1: "une_variable"
text2: "une_autre_variable"
tasks:
- name: Snake To camel
debug:
msg: "{{ item | snaketocamel }}"
with_items:
- "{{text1}}"
- "{{text2}}"

Vous pouvez le lancer avec la commande:

ansible-playbook -i localhost test.yml

Ce qui vous donnera :

ok: [localhost] => (item=une_variable) => {
"msg": "UneVariable"
}
ok: [localhost] => (item=une_autre_variable) => {
"msg": "UneAutreVariable"
}

Passer plusieurs variables à un filtre personnalisé

Nous allons ajouter un suffix à notre filtre. La fonction devient:

def snake_to_camel(text,suffix=''):
import re
return suffix + ''.join(x.title() or '_' for x in text.split('_'))

Et le playbook :

---
- hosts: localhost
gather_facts: false
vars:
text1: "une_variable"
text2: "une_autre_variable"
tasks:
- name: Snake to Camel
debug:
msg: "{{ item | snaketocamel('string') }}"
with_items:
- "{{text1}}"
- "{{text2}}"

Ce qui donne comme résultat :

ok: [localhost] => (item=une_variable) => {
"msg": "stringUneVariable"
}
ok: [localhost] => (item=une_autre_variable) => {
"msg": "stringUneAutreVariable"
}

Lever une exception Ansible dans votre filtre

En général, les erreurs rencontrées lors de l'exécution doivent être renvoyées en levant une AnsibleError() ou une classe similaire contenant un message décrivant l'erreur. Lorsque vous encapsulez d'autres exceptions dans des messages d'erreur, vous devez toujours utiliser la fonction Ansible to_text pour garantir la compatibilité des chaînes entre les différentes versions de Python.

Un exemple : Tester qu'une librairie est bien installé: ici la lib six.

# -*- coding: utf-8 -*-

from ansible.errors import AnsibleError
import re

try:
import six
HAS_LIB = True
except ImportError:
HAS_LIB = False

def snake_to_camel(text, suffix=''):
if not HAS_LIB:
raise AnsibleError('You need to install "six" prior to running '
'snaketocamel filter')
import re
return suffix + ''.join(x.title() or '_' for x in text.split('_'))

class FilterModule(object):

def filters(self):
return {
'snaketocamel': snake_to_camel
}

On desinstalle six`et on lance le playbook :

pip3 uninstall six -y
ansible-playbook -i localhost test.yml

Ce qui donne :

TASK [Snake to Camel] ***
fatal: [localhost]: FAILED! => {"msg": "You need to install \"six\" prior to running snaketocamel filter"}

Voila je vous laisse pour que vous puissiez développer vos propres filtres et l'intégrer dans vos playbooks.

Pour tester vos développements sur différentes versions d'Ansible et Python, je vous propose de lire ce billet.