Conventions de nommage pour Ansible
Écrit par Emmanuel BENOÎT - Créé le 2022-11-20
Je voulais écrire un petit quelque chose sur la façon dont je nomme les différents éléments lorsque j'utilise Ansible ; cependant, comme cela dépend en partie de la façon dont j'organise mes inventaires et mes playbooks, j'ai fini par devoir expliquer une partie de cela aussi.
Inventaire
Noms d'hôtes
J'ai tendance à ignorer la best practice communément admise, qui consiste à utiliser des noms courts pour les hôtes, et à utiliser plutôt des FQDNs. À mon avis, cela présente de nombreux avantages.
- Cela rend impossible la collision entre les noms d'hôtes et les noms de groupes.
- L'utilisation d'une variable supplémentaire pour porter le FQDN que l'hôte est supposé avoir n'est plus nécessaire.
- L'hôte sur lequel s'est produit une erreur est immédiatement évident.
Noms des groupes
J'organise mon inventaire en hiérarchies relativement peu profondes qui
correspondent à différents aspects. Tous les noms de groupes dans une telle
hiérarchie, à l'exception du groupe de niveau supérieur, sont précédés d'un
préfixe indiquant la hiérarchie à laquelle ils appartiennent.
Par exemple, si je dois regrouper les hôtes par emplacement, je vais utiliser
un groupe nommé by_location
contenant des sous-groupes utilisant le préfixe
loc_
.
Tous les noms de groupe sont en snake case.
Rôles et tags
J'utilise la kebab-case pour les noms de rôles. En outre, je m'assure généralement que chaque rôle peut être contrôlé à l'aide d'un seul tag, qui est identique au nom du rôle.
J'organise la plupart des tâches de mes rôles en un ensemble de 5 phases.
- Les préparations, qui valideront les variables de configuration en tenant compte des facts, mettront en cache certaines données...
- L'installation, qui installera des paquets, créera des répertoires, copiera des fichiers depuis les dépôts... for repositories...
- La configuration, qui créera ou mettra à jour les fichiers nécessaires pour ce qui est installé par le rôle.
- Le runtime, qui configurera un service déjà en cours d'exécution à travers une interface qu'il fournit ; cela inclut par exemple la création d'utilisateurs de base de données ou l'exécution d'appels API vers l'application qui vient d'être installée.
- La post-installation, qui effectuera tout nettoyage requis.
Ces phases ne sont pas toujours toutes présentes dans un rôle donné. Si elles
le sont, les phases d'installation, de configuration et d'exécution porteront
respectivement les tags install
, config
et runtime
, tandis que les
préparations et la post-installation ne portent aucune étiquette. Cela permet
aux phases d'un rôle d'être exécutées sélectivement de manière relativement
prévisible.
Variables
Préfixe
Toutes les variables doivent être préfixées, soit par un nom de rôle, soit par
un nom de groupe. Alors que la pratique communément admise consiste à utiliser
un seul _
pour séparer le préfixe et le nom réel de la variable, je préfère en
utiliser deux, par exemple :
my_role__variable_name: value
Le raisonnement est que, lorsqu'on en utilise un seul, un nom tel que a_b_c
est ambigu : il pourrait s'agir de la variable b_c
du groupe/rôle a
,
mais aussi de la variable c
du groupe/rôle a_b
. Bien que je n'aie jamais eu
de collisions lorsque j'utilisais encore un seul séparateur, j'ai vu des cas
d'ambiguïté à quelques reprises.
Lorsque la variable est liée à un rôle, le nom du rôle converti en snake case
sera utilisé comme préfixe, comme on le voit ci-dessus avec un rôle appelé
my-role
.
Pour les variables fournies par des groupes, j'utiliserai le nom du groupe comme
préfixe de la variable. Par exemple, si je voulais définir une variable
vlan_tag
qui dépende du réseau sur lequel se trouve un hôte, j'aurais le type
de structure suivant :
all:
children:
by_network:
children:
net_dmz:
vars:
by_network__vlan_tag: 32
net_app1:
vars:
by_network__vlan_tag: 33
net_dev:
vars:
by_network__vlan_tag: 34
Je n'utilise que très rarement de variables liées à des hôtes. Quand c'est le cas, il s'agit d'exceptions à des éléments habituellement portés par des groupes, les noms de variables étant donc déterminés par ces derniers.
Variables privées
Quand une variable doit être considérée comme "privée" pour un rôle ou un
groupe, je préfixe son nom entier avec un _
supplémentaire. Ce sera le cas
pour presque toutes les variables dans le fichier vars/main.yml
d'un rôle, car
la plupart d'entre elles ne sont pas destinées à être utilisées en dehors du
rôle qui les définit. J'utilise également cette convention pour les variables
utilisées avec la clause register
d'une tâche, et pour les itérateurs de
boucles si item
est insuffisant (par exemple pour les boucles qui incluent
d'autres tâches ou rôles).
Découplage
Un rôle ne devrait à mon avis jamais utiliser une variable qui ne lui est pas explicitement destinée en dehors des host facts, car cela introduit un couplage fort entre ce rôle et la structure actuelle de l'inventaire.
Pour cette raison, j'utilise des variables de groupe pour transporter des
informations communes et j'affecter leur contenu aux variables de rôle. Par
exemple, si j'avais une variable db_name
dans les rôles role-a
et role-b
qui devaient se voir attribuer la même valeur, j'obtiendrais quelque chose comme
ceci dans mes variables de groupe :
srv_service__db_name: thing
role_a__db_name: "{{ srv_service__db_name }}"
role_b__db_name: "{{ srv_service__db_name }}"
Handlers
J'utilise toujours la directive listen
pour mes handlers, avec un nom qui
suit la même convention que les noms de variables ci-dessus. Par exemple, un
handler qui redémarre le service pour un rôle nommé apache
sera appelé
apache__restart
. Cependant, j'ajoute toujours, en plus de cet identifiant,
un nom lisible par l'homme qui apparaîtra dans les journaux.
- listen: ntp__restart
name: Restart NTP
ansible.builtin.service:
name: ntp
state: restarted