Ansible : Utiliser ses API avec Python

Depuis quelques temps j’ai enfin trouvĂ© des idĂ©es de petits outils Ă  dĂ©velopper avec Python pour pouvoir apprendre Ă  manipuler ce langage.

Utilisant beaucoup Ansible de maniĂšre professionnelle (je vous invite Ă  lire la serie de billets Ă©crite Ă  ce sujet si ce n’est dĂ©jĂ  fait), et celui-ci Ă©tant dĂ©veloppĂ© en Python, je m’appuie dans notre contexte sur nos inventaires pour fournir diverses informations Ă  d’autres systĂšmes ou encore Ă  des utilisateurs.

Attention : Les API dont je vais parler sont utilisées par Ansible pour ses propres besoins et sont susceptibles de casser en cas de modification. Il faut donc rester parcimonieux sur leur utilisation et ne pas trop en dépendre !

L’un des premiers outils que j’ai bricolĂ© avec Python est un gĂ©nĂ©rateur de fiche environnement pour une application, ceci dans le but de mettre fin aux 50 fichiers Excel Ă©parpillĂ©s Ă  droite et Ă  gauche et jamais maintenus. Si j’ai pu facilement lire les fichiers group_vars de l’inventaire Ansible avec le module pyyaml de Python, le fichier hosts au format ini Ă©tait un peu plus corsĂ© et mal reconnu car il n’y avait pas forcĂ©ment de clĂ© / valeur pour un serveur.

Exemple :

[webservers]
host1
host2

[databases]
hostdb1
hostdb2

Le module ConfigParser de Python avait du mal sur le coup.

Python 3.8.6 (default, Sep 25 2020, 00:00:00) 
[GCC 10.2.1 20200723 (Red Hat 10.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.read('hosts')
['hosts']
>>> print(config['webservers'])
<Section: webservers>
>>> 

… et Ă  partir de lĂ  je ne voyais plus comment lui faire afficher les hosts du groupe webservers.

AprĂšs quelques recherches j’ai donc vu cette possibilitĂ© d’importer directement les API d’Ansible.

Python 3.8.6 (default, Sep 25 2020, 00:00:00) 
[GCC 10.2.1 20200723 (Red Hat 10.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from ansible.inventory.manager import InventoryManager
>>> from ansible.parsing.dataloader import DataLoader
>>> loader = DataLoader() # cette méthode se charge d'aller trouver et lire les fichiers .yaml, .ini, .json
>>> inventory = InventoryManager(loader=loader, sources='hosts') # on charge le fichier hosts de l'inventaire
>>> print(inventory.groups) # liste les groupes de l'inventaire
{'all': all, 'ungrouped': ungrouped, 'webservers': webservers, 'databases': databases}
>>> print(inventory.get_hosts('webservers')) # affiche les hosts d'un groupe
[host1, host2]

Et voilĂ , c’est aussi simple. A noter que les variables retournĂ©es font partie de la Classe d’Ansible, donc elles ne sont pas forcĂ©ment exploitables directement dans du code externe. J’ai du passer par des intermĂ©diaires pour retransformer les valeurs en str afin de pouvoir les exploiter. Par exemple j’avais besoin de rĂ©soudre l’entrĂ©e DNS du nom du serveur pour obtenir l’IP afin de l’afficher dans le rĂ©fĂ©rentiel, la valeur retournĂ©e par la commande get_hosts Ă©tait nativement inexploitable pour socket.gethostbyname.

D’autres mĂ©thodes sont aussi disponibles pour gĂ©nĂ©rer des inventaires dynamiques afin de lancer dans la foulĂ©e des Playbook Ansible via Python. Dans le ca de l’API Manager, le nĂ©cessaire est disponible dans les sources d’Ansible pour comprendre ce qu’elle permet de faire.