Développer et utiliser les lookup Ansible
Les lookups Ansible permet de récupérer des données qui sont stockées sur le noeud ou est exécuté le playbook. Par exemple il est possible de lire le contenu d’un fichier, de générer un mot de passe aléatoire, etc.
Les lookup Ansible disponibles
Il existe beaucoup de lookup disponible via la communauté ansible.
Nous allons nous intéresser à quelques lookup dont ceux qui sont intégrés par défaut à Ansible et à ceux de la communauté Général. Vous pouvez retrouver la liste de tous les lookups installés sur votre noeud via la commande suivante :
ansible-doc -l -t lookup
ansible.utils.get_path Retrieve the value in a v...ansible.utils.index_of Find the indices of items...ansible.utils.to_paths Flatten a complex object ...ansible.utils.validate Validate data with provid......
Lire des variables d’environnement
On utilise ici le lookup env
:
---- name: Load env gather_facts: no hosts: all vars: my_env: "{{ lookup('env', 'HOME') }}" tasks: - name: show the env debug: msg: "{{ my_env }}"
Pour lancer ce playbook (et tous les autres exemples) il suffit de taper la commande suivante :
ansible-playbook -i localhost, -c local playbook.yml
On ne le lance que sur localhost via une connexion locale.
Ce qui donne :
ok: [localhost] => { "msg": "/home/stephane.r"}
Lire le retour d’une commande
Il est possible de récupérer la sortie d’une commande avec le lookup pipe :
---- name: Load stdout of a command gather_facts: no hosts: all vars: my_env: "{{ lookup('pipe', 'date') }}" tasks: - name: show date debug: msg: "{{ my_env }}"
Ce qui donne :
ok: [localhost] => { "msg": "jeu. 1 avr. 2021 11:01:45"}
Lire le contenu d’un fichier
Pour lire le contenu d’un fichier, vous devez utiliser le lookup file. Rappel le fichier est stocké sur le noeud où est lancé le playbook. Donc pour notre test créer un fichier test.txt ou se trouve votre playbook :
---- name: Read a file gather_facts: no hosts: all vars: my_file: "{{ lookup('file', 'test.txt') }}" tasks: - name: show test file content debug: msg: "{{ my_file }}"
Ce qui donne :
ok: [localhost] => { "msg": "coucou je suis un fichier :)"}
Générer un mot de passe
Cette fois , nousallons utiliser le lookup Ansible password.
---- name: Generate a password gather_facts: no hosts: all vars: my_password: "{{ lookup('password', 'password.secret') }}" tasks: - name: display password debug: msg: "{{ my_password }}"
Ce qui donne :
ok: [localhost] => { "msg": "wbf4C-byFvUB3fqci6lT"}
Vous devriez retrouver le fichier password.secret dans le répertoire ou vous
exécuter le playbook. Si vous ne voulez pas le stocker il suffit d’indiquer /dev/null
.
Il est possible de formater le mot de passe en utilisant les paramètres suivant accolés au nom de fichier :
- chars : vous pouvez indiquer les attributs du module string de python : ascii_letters, digits, hexdigits, punctuation ou votre propre liste de caractères.
- length: la taille de votre mot de passe
- encrypt: la méthode d’encryptage parmi :
passlib.hash; md5_crypt, bcrypt, sha256_crypt, sha512_crypt
. Par défaut, il s’agit du format plain_text sinon le fichier contiendra également le salt pour l’idem potence.
Exemple, on génère un mot de passe de 64 caractères intégrant des chiffres, des lettres et les caractères .-! :
---- name: Generate a password gather_facts: no hosts: all vars: my_password: "{{ lookup('password', '/dev/null length=64 chars=ascii_letters,digits,._-! encrypt=md5_crypt') }}" tasks: - name: display password debug: msg: "{{ my_password }}"
Ce qui donne :
ok: [localhost] => { "msg": "hWkD3GN1B9ZvgLWj1!NbYRR6MowYdO5mc5OlPMgHwEx5ezRphqVOcT6bXXul-!aV"}
Lire une entrée DNS
Nous allons utiliser ici le lookup dig qui est très complet, mais il faut installer le module python dnspython:
pip3 install dnspython --user
---- name: Generate a password gather_facts: no hosts: all tasks: - name: use in a loop debug: msg: "{{ lookup('dig', 'gmail.com./MX', wantlist=True) }}"
Ce qui donne :
ok: [localhost] => { "msg": [ "5 gmail-smtp-in.l.google.com.", "40 alt4.gmail-smtp-in.l.google.com.", "10 alt1.gmail-smtp-in.l.google.com.", "30 alt3.gmail-smtp-in.l.google.com.", "20 alt2.gmail-smtp-in.l.google.com." ]}
Ce lookup utilise deux paramètres :
- flat: 0 ou 1 qui indique si l’on souhaite un export plat ou un dictionnaire
- qtype: le type de requête Un exemple les utilisant :
---- name: Generate a password gather_facts: no hosts: all tasks: - name: use in a loop debug: msg: "{{ lookup('dig', '_xmpp-server._tcp.gmail.com./SRV', 'flat=0') }}"
Ce qui donne:
ok: [localhost] => { "msg": "10 alt1.gmail-smtp-in.l.google.com.,40 alt4.gmail-smtp-in.l.google.com.,20 alt2.gmail-smtp-in.l.google.com.,30 alt3.gmail-smtp-in.l.google.com.,5 gmail-smtp-in.l.google.com."}
Les autres filtres
Comme dis plus haut il existe un tas de lookup disponible dont voici la liste complète ↗.
Avant de vous lancer dans le développement de votre propre lookup vérifier qu’il n’existe pas.
Développer un lookup Ansible
Nous allons écrire notre propre plugin lookup qui retournera la version d’Ansible.
Dans le répertoire créer le fichier ansible_version.py avec ce contenu :
from __future__ import (absolute_import, division, print_function)__metaclass__ = type
from ansible.errors import AnsibleErrorfrom ansible.plugins.lookup import LookupBasefrom ansible.release import __version__ as ansible_version
class LookupModule(LookupBase): def run(self, terms, variables=None, **kwargs): return [ansible_version]
Maintenant appelons le depuis un playbook:
---- name: Get ansible version gather_facts: no hosts: all tasks: - name: display ansible version debug: msg: "{{ lookup('ansible_version') }}"
Ce qui donne :
ok: [localhost] => { "msg": "2.10.6 "}
Quelques explications
On retrouve une classe LookupModule qui hérite de la classe LookupBase. Cette classe doit implémenter la méthode run.
def run(self, terms, variables=None, **kwargs):
La variable contient les arguments passés au module lookup sous la forme d’un tableau.
Comme pour le plugin filter il est possible de lever des exceptions:
try: import dnspythonexcept ImportError: raise AnsibleError("the lookup diog cannot be run without dnspython installed")
Je suis sûr que vous avez déjà plein d’idées :)
Pour tester vos développements sur différentes versions d’Ansible et Python, je vous propose de lire ce billet.
Si vous voulez plus de tutorial Ansible je vous renvoie sur le billet de l’introduction à ansible