Les variables
Objectif de cet atelier pratique
- Intégrer par la pratique le fonctionnement des variables
Ansible offre la possibilité d'utiliser des variables dans les tasks, à condition que celles-ci aient été définies quelque part auparavant. Sachez qu'il existe une bonne vingtaine de méthodes différentes pour faire ceci. Non, ne partez pas en courant. Nous allons prendre notre temps et découvrir tout cela en mettant un pied devant l'autre.
Démarrer le labo
Placez-vous dans le répertoire du treizième atelier pratique :
Voici les quatre machines virtuelles de cet atelier :
| Machine virtuelle | Adresse IP |
|---|---|
ansible |
192.168.56.10 |
rocky |
192.168.56.20 |
debian |
192.168.56.30 |
suse |
192.168.56.40 |
Démarrez les VM :
Connectez-vous au Control Host :
L'environnement de cet atelier est préconfiguré et prêt à l'emploi :
-
Ansible est installé sur le Control Host.
-
Le fichier
/etc/hostsdu Control Host est correctement renseigné. -
L'authentification par clé SSH est établie sur les trois Target Hosts.
-
Le répertoire du projet existe et contient une configuration de base et un inventaire.
-
Direnv est installé et activé pour le projet.
-
Le validateur de syntaxe
yamllintest également disponible.
Rendez-vous dans le répertoire des playbooks :
$ cd ansible/projets/ema/playbooks/
direnv: loading ~/ansible/projets/ema/.envrc
direnv: export +ANSIBLE_CONFIG
Les play vars
Une des nombreuses possibilités pour définir des variables consiste à inclure
une section vars dans le play. Dans l'exemple ci-dessous, deux variables
sont d'abord définies dans la section vars. Dans un deuxième temps, elles
sont affichées grâce au module debug :
--- # vars1.yml
- hosts: localhost
gather_facts: false
vars:
color: blue
number: 42
tasks:
- debug:
msg: "Color: {{color}}, Number: {{number}}"
...
Jusqu'ici, rien de particulier à signaler :
$ ansible-playbook vars1.yml
PLAY [localhost] **************************************************************
TASK [debug] ******************************************************************
ok: [localhost] => {
"msg": "Color: blue, Number: 42"
}
PLAY RECAP ********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ...
Syntaxe
Notez la syntaxe avec les doubles accolades {{...}} qui nous permet
d'accéder au contenu des variables.
Les extra vars
Une autre possibilité pour définir des variables consiste à les fournir en
argument en ligne de commande avec l'option -e (ou --extra-vars) :
$ ansible-playbook vars1.yml -e color=red
TASK [debug] ******************************************************************
ok: [localhost] => {
"msg": "Color: red, Number: 42"
}
L'option -e pourra d'ailleurs être réitérée autant de fois que vous
voulez :
$ ansible-playbook vars1.yml -e color=red -e number=99
TASK [debug] ******************************************************************
ok: [localhost] => {
"msg": "Color: red, Number: 99"
}
Précédences des variables
Cette première manipulation des variables nous permet de tirer une conclusion : lorsqu'on définit une seule et même variable à plusieurs endroits, une de ces définitions va l'emporter sur les autres. Concrètement, nous savons déjà qu'une variable extra vars est plus forte qu'une variable play vars.
Vous vous doutez bien que ces règles de précédence sont clairement définies. Jetez un œil dans la documentation officielle à la section Using Variables. Vous y trouverez le classement officiel :
Non, je ne vous demande pas d'apprendre ce classement par cœur. En revanche, rien ne vous empêche de comprendre son fonctionnement :
-
Il comporte en tout et pour tout 22 types de variables.
-
Repérez les play vars en position 12.
-
Repérez les extra vars en position 22.
-
Le classement va manifestement du plus faible au plus fort.
-
Il en résulte qu'une variable extra vars l'emportera toujours sur toutes les autres.
Les variables set_fact
Dans certains cas de figure, il devient nécessaire de définir des variables au
cours de l'exécution d'un play. Dans ce cas, set_fact vous permet d'ajouter
des variables à un play ou même de redéfinir des variables existantes :
--- # set_fact.yml
- hosts: localhost
gather_facts: false
tasks:
- name: Define variables
set_fact:
color: yellow
number: 13
- debug:
msg: "Color: {{color}}, Number: {{number}}"
...
Rien de bien surprenant ici non plus :
$ ansible-playbook set_fact.yml
TASK [Define variables] *******************************************************
ok: [localhost]
TASK [debug] ******************************************************************
ok: [localhost] => {
"msg": "Color: yellow, Number: 13"
}
-
Dans la liste des précédences, les variables set_fact occupent la position 19. On va dire qu'elles sont plutôt fortes.
-
Un fact est une variable spécifique à l'hôte. À partir du moment où elle a été définie, elle ne sera visible que pour l'hôte qui vient d'exécuter la tâche correspondante.
Ne vous tracassez pas trop sur cette distinction pour l'instant. Nous aborderons les facts Ansible en temps et en heure, et les choses vont s'éclaircir.
Les group_vars
Pour gérer les différences entre les systèmes, il nous faut une méthode qui
permet d'attribuer une valeur à une variable en fonction de la cible. Un
exemple pratique va vous permettre de comprendre ce fonctionnement. Dans
l'exemple suivant, on inclut tous les Target Hosts, mais les variables
mycolor et mynumber ne sont pas définies :
--- # vars2.yml
- hosts: all
gather_facts: false
tasks:
- debug:
msg: "Color: {{mycolor}}, Number: {{mynumber}}"
...
Comme il faut s'y attendre, l'accès au contenu d'une variable non définie résulte en une erreur d'exécution conséquente, pour ne pas dire fatale :
$ ansible-playbook vars2.yml
PLAY [all] ****************************************************************
TASK [debug] **************************************************************
fatal: [rocky]: FAILED! => {"msg": "The task includes an option with an
undefined variable.
fatal: [debian]: FAILED! => {"msg": "The task includes an option with an
undefined variable.
fatal: [suse]: FAILED! => {"msg": "The task includes an option with an
undefined variable.
PLAY RECAP ****************************************************************
debian : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0
rocky : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0
suse : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0
En dehors des extra vars, est-ce qu'il existe une méthode pour définir des
variables à l'extérieur d'un playbook ? La réponse est oui. En effet,
Ansible va chercher ce genre d'information dans un répertoire
group_vars :
$ mkdir -v ~/ansible/projets/ema/group_vars
mkdir: created directory '/home/vagrant/ansible/projets/ema/group_vars'
Le groupe all contient la liste complète de tous nos Target Hosts. On va
donc créer un fichier all.yml correspondant à l'intérieur du répertoire
group_vars, avec des valeurs par défaut pour tous les systèmes cible :
À partir de là, notre playbook s'exécute correctement :
$ ansible-playbook vars2.yml
PLAY [all] ****************************************************************
TASK [debug] **************************************************************
ok: [rocky] => {
"msg": "Color: white, Number: 97"
}
ok: [debian] => {
"msg": "Color: white, Number: 97"
}
ok: [suse] => {
"msg": "Color: white, Number: 97"
}
PLAY RECAP ****************************************************************
debian : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0
rocky : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0
suse : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0
C'est déjà pas mal, mais nous n'avons toujours pas de paramétrage individuel.
Qu'à cela ne tienne, jetez un œil dans l'inventaire de cet atelier, qui définit
un groupe [redhat_hosts] avec l'hôte rocky comme seul et unique
membre :
Admettons qu'on souhaite colorier en rouge tous nos systèmes Red Hat. Dans ce
cas, on pourrait très bien créer un fichier group_vars/redhat_hosts.yml en
partant du principe qu'Ansible s'en servira pour la définition des variables du
groupe correspondant :
Résultat des courses :
TASK [debug] ****************************************************************
ok: [rocky] => {
"msg": "Color: red, Number: 97"
}
ok: [debian] => {
"msg": "Color: white, Number: 97"
}
ok: [suse] => {
"msg": "Color: white, Number: 97"
}
Là aussi, jetez un œil à la précédence des variables :
-
group_vars/all.ymloccupe la quatrième place (pas terrible) -
group_vars/*.ymloccupe la sixième place (un chouïa plus fort)
Les host_vars
Ansible vous offre également la possibilité de paramétrer des cibles
individuelles. Le fonctionnement est analogue aux group vars, au détail près
qu'Ansible va chercher ses informations dans un répertoire host_vars
correspondant :
$ mkdir -v ~/ansible/projets/ema/host_vars
mkdir: created directory '/home/vagrant/ansible/projets/ema/host_vars'
Admettons qu'on souhaite colorier en vert notre système SUSE. Dans ce cas, il
suffit de créer un fichier host_vars/suse.yml en partant du principe
qu'Ansible s'en servira pour la définition des variables de l'hôte
correspondant :
Et voici le résultat :
TASK [debug] ****************************************************************
ok: [rocky] => {
"msg": "Color: red, Number: 97"
}
ok: [debian] => {
"msg": "Color: white, Number: 97"
}
ok: [suse] => {
"msg": "Color: green, Number: 97"
}
Vous vous doutez bien que les paramètres d'un hôte individuel doivent
l'emporter sur les paramètres de groupe. Là aussi, jetez un œil à la précédence
des variables : host_vars/*.yml se trouve en neuvième position.
En mode interactif
Une option moins courante consiste à définir vos variables au début de
l'exécution d'un play à l'aide d'une section vars_prompt comme ceci :
--- # prompting.yml
- hosts: localhost
gather_facts: false
vars_prompt:
- name: var1
prompt: Please select a value for var1
default: 42
private: false
- name: var2
prompt: And now for var2 (secret)
private: true
tasks:
- debug:
msg: "var1 is {{var1}}, var2 is {{var2}}"
...
Voilà ce que ça donne :
$ ansible-playbook prompting.yml
Please select a value for var1 [42]: 99
And now for var2 (secret): ***********
PLAY [localhost] *************************************************************
TASK [debug] *****************************************************************
ok: [localhost] => {
"msg": "var1 is 99, var2 is yatahongaga"
}
Si vous lancez le playbook avec des extra vars, la saisie interactive ne s'affiche plus en raison de la précédence :
$ ansible-playbook prompting.yml -e var1=38 -e var2=zamooche
PLAY [localhost] *************************************************************
TASK [debug] *****************************************************************
ok: [localhost] => {
"msg": "var1 is 38, var2 is zamooche"
}
Les structures complexes
Avec Ansible, les variables peuvent très bien contenir des structures complexes, comme on peut le voir dans l'exemple ci-dessous :
--- # vars-complex.yml
- hosts: suse
gather_facts: false
vars:
motd:
hello: Bonjour cher visiteur !
quote:
- Chat échaudé craint la charrue avant la peau de l'ours.
- Chassez le naturiste, il revient au bungalow.
lotto: [2, 8, 17, 33, 34, 42]
tasks:
- name: Upload /etc/motd
copy:
dest: /etc/motd
content: |
{{ motd.hello }}
Citation du jour: {{ motd.quote[1] }}
Les numéros du loto: {{ motd.lotto | join(', ') }}
...
Le fichier /etc/motd
Le fichier /etc/motd contient le message du jour (Message Of The Day)
censé s'afficher juste après la connexion au shell sur les systèmes
Unix/Linux.
Exécutez le playbook et connectez-vous à l'hôte suse :
$ ssh suse
Last login: Sun Sep 22 07:58:19 2024 from 192.168.56.10
Bonjour cher visiteur !
Citation du jour: Chassez le naturiste, il revient au bungalow.
Les numéros du loto: 2, 8, 17, 33, 34, 42
Tout le monde est là ?
Dans certains cas de figure, ce n'est pas une mauvaise idée de vérifier
d'emblée si toutes les variables nécessaires à l'exécution d'un playbook sont
correctement définies. Le module assert va nous assister dans cette
démarche :
--- # assert.yml
- hosts: debian
gather_facts: false
tasks:
- assert:
that:
- hostname is defined and hostname != ''
fail_msg: The hostname variable is undefined or empty.
- name: Set hostname
hostname:
name: "{{ hostname }}"
- debug:
msg: Let's check if we see this.
...
La condition en-dessous de that doit être remplie, faute de quoi le play
s'interrompt :
$ ansible-playbook assert.yml
PLAY [debian] *************************************************************
TASK [assert] *************************************************************
fatal: [debian]: FAILED! => {
"assertion": "hostname is defined and hostname != ''",
"changed": false,
"evaluated_to": false,
"msg": "The hostname variable is undefined or empty."
}
PLAY RECAP ****************************************************************
debian : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0
Le même play avec une variable hostname définie :
$ ansible-playbook assert.yml -e hostname=sandbox
PLAY [debian] *************************************************************
TASK [assert] *************************************************************
ok: [debian] => {
"changed": false,
"msg": "All assertions passed"
}
TASK [Set hostname] *******************************************************
changed: [debian]
TASK [debug] **************************************************************
ok: [debian] => {
"msg": "Let's check if we see this."
}
PLAY RECAP ****************************************************************
debian : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0
Un peu de ménage
Quittez le Control Host :
Supprimez toutes les VM :
À vous de jouer !
Placez-vous dans le répertoire du quatorzième atelier pratique :
Voici les quatre machines virtuelles de cet atelier :
| Machine virtuelle | Adresse IP |
|---|---|
control |
192.168.56.10 |
target01 |
192.168.56.20 |
target02 |
192.168.56.30 |
target03 |
192.168.56.40 |
Les VM tournent toutes sous Rocky Linux. Démarrez-les :
Connectez-vous au Control Host :
L'environnement de cet atelier est préconfiguré et prêt à l'emploi :
-
Ansible est installé sur le Control Host.
-
Le fichier
/etc/hostsdu Control Host est correctement renseigné. -
L'authentification par clé SSH est établie sur les trois Target Hosts.
-
Le répertoire du projet existe et contient une configuration de base et un inventaire.
-
Direnv est installé et activé pour le projet.
-
Le validateur de syntaxe
yamllintest également disponible.
Rendez-vous dans le répertoire du projet :
$ cd ansible/projets/ema/
direnv: loading ~/ansible/projets/ema/.envrc
direnv: export +ANSIBLE_CONFIG
$ ls -l
total 8
-rw-r--r--. 1 vagrant vagrant 65 Sep 19 14:26 ansible.cfg
-rw-r--r--. 1 vagrant vagrant 128 Sep 19 14:26 inventory
drwxr-xr-x. 2 vagrant vagrant 6 Sep 19 14:26 playbooks
-
Écrivez un playbook
myvars1.ymlqui affiche respectivement votre voiture et votre moto préférée en utilisant le moduledebuget deux variablesmycaretmybikedéfinies en tant que play vars. -
En utilisant les extra vars, remplacez successivement l'une et l'autre marque - puis les deux à la fois - avant d'exécuter le play.
-
Écrivez un playbook
myvars2.ymlqui fait essentiellement la même chose quemyvars1.yml, mais en utilisant une tâche avecset_factpour définir les deux variables. -
Là aussi, essayez de remplacer les deux variables en utilisant des extra vars avant l'exécution du play.
-
Écrivez un playbook
myvars3.ymlqui affiche le contenu des deux variablesmycaretmybikemais sans les définir. Avant d'exécuter le playbook, définissez VW et BMW comme valeurs par défaut pourmycaretmybikepour tous les hôtes, en utilisant l'endroit approprié. -
Effectuez le nécessaire pour remplacer VW et BMW par Mercedes et Honda sur l'hôte
target02. -
Écrivez un playbook
display_user.ymlqui affiche un utilisateur et son mot de passe correspondant à l'aide des variablesuseretpassword. Ces deux variables devront être saisies de manière interactive pendant l'exécution du playbook. Les valeurs par défaut serontmicrolinuxpouruseretyatahongagapourpassword. Le mot de passe ne devra pas s'afficher pendant la saisie.
Quittez le Control Host :
Supprimez toutes les VM :
La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce site ? Offrez un café au rédacteur en cliquant sur la tasse.

