Pull Requests.
Dans l’environnement des outils de gestion de configuration, on retrouve . 2 niveaux d’abstractions de base : Ressource et Module, ce dernier peut être affiné en deux sous parties : le module expert, le module métier.
La ressource est le niveau d’abstraction le plus bas, c’est celle qui est le plus proche de l’action réellement effectuée sur le serveur cible. On peut la comparer aux fonctions de base d’un langage.
Le pattern Ressource nous permet de passer d’une logique d’action à une logique d’état désiré. C’est l’application de ce pattern qui nous permet d’assurer l’idempotence de notre code assez facilement.
Par exemple, nous souhaitons rajouter une entrée dans le fichier /etc/hosts de notre serveur.
En Shell, pour ajouter une entrée nous pouvons faire :
echo "127.0.0.1 localhost" >> /etc/hosts
Si nous voulons rendre cette action idempotente, on peut essayer :
if (!grep -q 127.0.0.1 /etc/hosts); then echo "127.0.0.1 localhost" >> /etc/hosts; fi
Et en puppet :
host { 'localhost': ip => '127.0.0.1', }
Quel type de code souhaitez vous maintenir?
Lorsque l’on fait du Shell il est nécessaire de regarder le delta par rapport à la cible et en fonction de cela, nous effectuons la transition. La commande Shell présentée, semble gérer le delta correctement, mais on peut trouver des cas où l’état préalable n’est pas géré (127.0.0.1 est présent mais n'est pas associé à localhost). Les gérer vaut-il la peine de complexifier le code ?
Dans le cas de Puppet, le pattern Ressource nous permet de spécifier directement l’état cible et c’est l’outil qui nous masque la transition.
L’usage du pattern Ressource présente l'intérêt qu’il s’intéresse à l’état désiré en masquant la constellation d’états de départ potentiellement infini.
L’écriture de ce module nécessite une connaissance intime de la brique manipulée. Mais elle nécessite également une bonne connaissance de l’outil de gestion de configuration afin de l’utiliser au mieux et de ne pas enchaîner des commandes Shell bas niveau.
Celui-ci connaît et gère par exemple : la syntaxe et l’emplacement des fichiers de configuration, le processus de déploiement, la validité des versions, les différents comportements entre versions et OS, le chemin vers les binaires...
De plus, il expose une interface d’entrée simplifiée : on peut notamment y retrouver des flags de feature flipping.
Il assure la corrélation entre le besoins besoins spécifiques au projet/contexte métier et l’appel aux modules experts. Nous allons donc retrouver des appels à de multiples modules experts, mais aussi la définition de variables métiers ou connexes à l’organisation.
Il faut faire attention à ce que l’on mets derrière le mot "métier" : on ne parle pas ici de transposer des règles métier liée à l’entreprise dans le code d’infrastructure. On parle de toutes les pratiques internes liées à l’usage de l’infrastructure : un module métier peut être un module qui exploite un module expert tomcat et un module expert logstash pour en faire un tomcat configuré dans le contexte de production avec la tuyauterie de collecte de log. Par nature, ce type de module est spécifique au contexte de l'entreprise.
Ces modules métier ne connaissent ni l’emplacement des fichiers de configuration, ni aucun composant technique précis. Cela lui est abstrait par le module expert.
Si nous voulons installer un MySQL avec Puppet, nous utiliserons un module expert (ici, issu de la communauté) puis dans le module métier nous le référencerons :
class { '::mysql::server': root_password => 'strongpassword', remove_default_accounts => true, }
Nous indiquons au module expert un nouveau mot de passe root et la suppression des comptes par défaut. À lui de savoir installer MySQL.
Il est écrit par un développeur connaissant les spécificités métiers (organisation, utilisation du produit, manière d’exploiter...). Il n’a pas besoin d’être expert sur le produit installé mais doit comprendre l’interface offerte par le module expert.
Ces trois niveaux peuvent se transposer dans les différents outils de management de configuration mais aussi avec la Programmation Orientée Objet.
Programmation Objet | Shell | Puppet | Ansible | |
Ressource | Fonction de base d’un langage | Fonction complexe | Ressource | Module |
Module expert | Interface | Fonction qui appelle des fonctions “Ressource” | Module (principalement issu de la communauté) | Role (principalement issu de la communauté) |
Module métier | Consommation de l’interface | Script | Profile (privé) | Role/Playbook (privé) |
L’approche ne doit pas être confondue avec la simple automatisation de l’existant. La construction de ces abstractions sera plus complexe avec certains outils graphiques, langages propriétaires simplistes et autres outils orientés “automatisation de l’existant”.
Ces outils limités ne permettent pas de construire des abstractions, de réaliser des diffs, de faire du dry-run, ou de travailler de manière collaborative. Ils ne sont pas dans la mouvance Infra As Code mais dans une logique d’automatisation de processus ad-hoc.
Les outils dans cette mouvance d’Infra As Code nécessitent de refaire tout ce qui à été développé dans le passé et de revoir les processus d’automatisation souvent obsolètes et pauvres. Cela prend du temps et demande un investissement initial mais c’est nécessaire !
Avec cette approche nous serons en mesure de reprendre bien d’autres patterns éprouvés issus du monde logiciel : refactoring, clean code, usines de développements, tests automatisés, pratiques organisationnelles liées à l’agile et au software craftsmanship … Ils permettent de garantir la maintenabilité et la qualité du code. L’infra As Code va bien au-delà d’un “yum install” dans un script !