Dans le didacticiel précédent sur la prise de décision dans Ansible, vous avez appris à effectuer de simples modifications de fichiers en utilisant le blockinfile ou en ligne Modules ansibles.
Dans ce tutoriel, vous apprendrez à utiliser Jinja2 moteur de templates pour effectuer des modifications de fichiers plus complexes et dynamiques.
Vous apprendrez à accéder aux variables et aux faits dans les modèles Jinja2. De plus, vous apprendrez à utiliser les instructions conditionnelles et les structures de boucle dans Jinja2.
Pour essayer les exemples de ce didacticiel, vous devez suivre l'intégralité de la série de didacticiels RHCE Ansible dans le bon ordre.
Accéder aux variables dans Jinja2
Ansible recherchera les fichiers de modèle jinja2 dans votre répertoire de projet ou dans un répertoire nommé templates sous votre répertoire de projet.
Créons un répertoire de modèles pour garder les choses plus propres et mieux organisées :
[[email protected] plays]$ mkdir templates
[[email protected] plays]$ cd templates/
Créez maintenant votre premier modèle Jinja2 avec le nom index.j2 :
[[email protected] templates]$ cat index.j2
A message from {{ inventory_hostname }}
{{ webserver_message }}
Notez que les noms de fichier de modèle Jinja2 doivent se terminer par l'extension .j2.
Le nom_hôte_inventaire est une autre variable intégrée Ansible (alias spéciale ou magique) qui fait référence à cet hôte "actuel" en cours d'itération dans le jeu. Le message_du_serveur_web est une variable que vous définirez dans votre playbook.
Maintenant, revenez une étape en arrière dans votre répertoire de projet et créez le fichier check-apache.yml suivant :
[[email protected] plays]$ cat check-apache.yml
---
- name: Check if Apache is Working
hosts: webservers
vars:
webserver_message: "I am running to the finish line."
tasks:
- name: Start httpd
service:
name: httpd
state: started
- name: Create index.html using Jinja2
template:
src: index.j2
dest: /var/www/html/index.html
Notez que le httpd package a déjà été installé dans un didacticiel précédent.
Dans ce playbook, vous vous assurez d'abord qu'Apache est en cours d'exécution dans la première tâche Start httpd
. Utilisez ensuite le modèle module dans la deuxième tâche Create index.html
en utilisant le processus Jinja2to et transférez le index.j2 Fichier de modèle Jinja2 que vous avez créé vers la destination /var/www/html/index.html .
Allez-y et lancez le playbook :
[[email protected] plays]$ ansible-playbook check-apache.yml
PLAY [Check if Apache is Working] **********************************************
TASK [Gathering Facts] *********************************************************
ok: [node3]
ok: [node2]
TASK [Start httpd] *************************************************************
ok: [node2]
ok: [node3]
TASK [Create index.html using Jinja2] ******************************************
changed: [node3]
changed: [node2]
PLAY RECAP *********************************************************************
node2 : ok=3 changed=1 unreachable=0 failed=0 skipped=0
node3 : ok=3 changed=1 unreachable=0 failed=0 skipped=0
Tout semble bon jusqu'ici; lançons une commande Ansible ad-hoc rapide pour vérifier le contenu de index.html sur les nœuds des serveurs Web :
[[email protected] plays]$ ansible webservers -m command -a "cat /var/www/html/index.html"
node3 | CHANGED | rc=0 >>
A message from node3
I am running to the finish line.
node2 | CHANGED | rc=0 >>
A message from node2
I am running to the finish line.
Étonnante! Remarquez comment Jinja2 a pu récupérer les valeurs de inventory_hostname variable intégrée et le webserver_message variable dans votre playbook.
Vous pouvez également utiliser la boucle commande pour voir si vous obtenez une réponse des deux serveurs Web :
[[email protected] plays]$ curl node2.linuxhandbook.local
A message from node2
I am running to the finish line.
[[email protected] plays]$ curl node3.linuxhandbook.local
A message from node3
I am running to the finish line.
Accéder aux faits dans Jinja2
Vous pouvez accéder aux faits dans les modèles Jinja2 de la même manière que vous accédez aux faits de votre playbook.
Pour démontrer, modifiez vos modèles répertoire et créez le info.j2 Fichier Jinja2 avec le contenu suivant :
[[email protected] templates]$ cat info.j2
Server Information Summary
--------------------------
hostname={{ ansible_facts['hostname'] }}
fqdn={{ ansible_facts['fqdn'] }}
ipaddr={{ ansible_facts['default_ipv4']['address'] }}
distro={{ ansible_facts['distribution'] }}
distro_version={{ ansible_facts['distribution_version'] }}
nameservers={{ ansible_facts['dns']['nameservers'] }}
totalmem={{ ansible_facts['memtotal_mb'] }}
freemem={{ ansible_facts['memfree_mb'] }}
Notez que info.j2 accède à huit faits différents. Revenez maintenant au répertoire de votre projet et créez le fichier server-info.yml suivant livre de jeu :
[[email protected] plays]$ cat server-info.yml
---
- name: Server Information Summary
hosts: all
tasks:
- name: Create server-info.txt using Jinja2
template:
src: info.j2
dest: /tmp/server-info.txt
Notez que vous créez /tmp/server-info.txt sur tous les hôtes basés sur info.j2 fichier modèle. Allez-y et lancez le playbook :
[[email protected] plays]$ ansible-playbook server-info.yml
PLAY [Server Information Summary] *******************************************
TASK [Gathering Facts] **********************************
ok: [node4]
ok: [node1]
ok: [node3]
ok: [node2]
TASK [Create server-info.txt using Jinja2] ********
changed: [node4]
changed: [node1]
changed: [node3]
changed: [node2]
PLAY RECAP *************************
node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node3 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node4 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
Tout a l'air bien ! Exécutons maintenant une commande ad-hoc rapide pour inspecter le contenu de /tmp/server-info.txt fichier sur l'un des nœuds :
[[email protected] plays]$ ansible node1 -m command -a "cat /tmp/server-info.txt"
node1 | CHANGED | rc=0 >>
Server Information Summary
--------------------------
hostname=node1
fqdn=node1.linuxhandbook.local
ipaddr=10.0.0.5
distro=CentOS
distro_version=8.2
nameservers=['168.63.129.16']
totalmem=1896
freemem=1087
Comme vous pouvez le voir, Jinja2 a pu accéder à tous les faits et les traiter.
Instructions conditionnelles en Jinja2
Vous pouvez utiliser le si instruction conditionnelle dans Jinja2 pour tester diverses conditions et comparer des variables. Cela vous permet de déterminer le flux d'exécution de votre modèle de fichier en fonction de vos conditions de test.
Pour démontrer, accédez à vos modèles répertoire et créez le fichier suivant selinux.j2 modèle :
[[email protected] templates]$ cat selinux.j2
{% set selinux_status = ansible_facts['selinux']['status'] %}
{% if selinux_status == "enabled" %}
"SELINUX IS ENABLED"
{% elif selinux_status == "disabled" %}
"SELINUX IS DISABLED"
{% else %}
"SELINUX IS NOT AVAILABLE"
{% endif %}
La première instruction du modèle crée une nouvelle variable selinux_statusand
définissez sa valeur sur ansible_facts['selinux']['status']
.
Vous utilisez alors selinux_status
dans votre si condition de test pour déterminer si SELinux est activé, désactivé ou non installé. Dans chacun des trois cas différents, vous affichez un message qui reflète le statut de Selinux.
Remarquez comment le si déclaration dans Jinja2 imite if de Python déclaration; n'oubliez pas d'utiliser {% endif %}
.
Revenez maintenant au répertoire de votre projet et créez le fichier suivant selinux-status.yml livre de jeu :
[[email protected] plays]$ cat selinux-status.yml
---
- name: Check SELinux Status
hosts: all
tasks:
- name: Display SELinux Status
debug:
msg: "{{ ansible_facts['selinux']['status'] }}"
- name: Create selinux.out using Jinja2
template:
src: selinux.j2
dest: /tmp/selinux.out
Allez-y et lancez le playbook :
[[email protected] plays]$ ansible-playbook selinux-status.yml
PLAY [Check SELinux Status] ****************************************************
TASK [Gathering Facts] *********************************************************
ok: [node4]
ok: [node2]
ok: [node3]
ok: [node1]
TASK [Display SELinux Status] **************************************************
ok: [node1] => {
"msg": "enabled"
}
ok: [node2] => {
"msg": "disabled"
}
ok: [node3] => {
"msg": "enabled"
}
ok: [node4] => {
"msg": "Missing selinux Python library"
}
TASK [Create selinux.out using Jinja2] *****************************************
changed: [node4]
changed: [node1]
changed: [node3]
changed: [node2]
PLAY RECAP *********************************************************************
node1 : ok=3 changed=1 unreachable=0 failed=0 skipped=0
node2 : ok=3 changed=1 unreachable=0 failed=0 skipped=0
node3 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 node4 : ok=3 changed=1 unreachable=0 failed=0 skipped=0
À partir de la sortie du playbook ; vous pouvez voir que SELinux est activé sur les deux node1 et nœud3 . J'ai désactivé SELinux sur node2 avant d'exécuter le playbook et node4 n'a pas installé SELinux car Ubuntu utilise AppArmor au lieu de SELinux.
Enfin, vous pouvez exécuter la commande ad hoc suivante pour inspecter le contenu de selinux.out sur tous les hôtes gérés :
[[email protected] plays]$ ansible all -m command -a "cat /tmp/selinux.out"
node4 | CHANGED | rc=0 >>
"SELINUX IS NOT AVAILABLE"
node2 | CHANGED | rc=0 >>
"SELINUX IS DISABLED"
node3 | CHANGED | rc=0 >>
"SELINUX IS ENABLED"
node1 | CHANGED | rc=0 >>
"SELINUX IS ENABLED"
Boucle dans Jinja2
Vous pouvez utiliser le pour déclaration dans Jinja2 pour parcourir les éléments d'une liste, d'une plage, etc. Par exemple, la boucle for suivante itérera sur les nombres de la range(1,11) et affichera donc les nombres de 1->10 :
{% for i in range(1,11) %}
Number {{ i }}
{% endfor %}
Remarquez comment la boucle for de Jinja2 imite la syntaxe de la boucle for de Python; encore une fois n'oubliez pas de terminer la boucle avec {% endfor %}
.
Créons maintenant un exemple complet qui montre la puissance des boucles for dans Jinja2. Accédez à votre répertoire de modèles et créez le fichier suivant hosts.j2 fichier modèle :
[[email protected] templates]$ cat hosts.j2
{% for host in groups['all'] %}
{{ hostvars[host].ansible_facts.default_ipv4.address }} {{ hostvars[host].ansible_facts.fqdn }} {{ hostvars[host].ansible_facts.hostname }}
{% endfor %}
Remarquez ici que vous avez utilisé une nouvelle variable spéciale intégrée (magique) hostvars qui est essentiellement un dictionnaire contenant tous les hôtes de l'inventaire et les variables qui leur sont affectées.
Vous avez itéré sur tous les hôtes de votre inventaire, puis pour chaque hôte ; vous avez affiché la valeur de trois variables :
- {{ hostvars[host].ansible_facts.default_ipv4.address }}
- {{ hostvars[host].ansible_facts.fqdn }}
- {{ hostvars[host].ansible_facts.hostname }}
Notez également que vous devez inclure ces trois variables sur la même ligne côte à côte pour correspondre au format de /etc/hosts fichier.
Retournez maintenant dans votre répertoire de projets et créez le fichier local-dns.yml suivant livre de jeu :
[[email protected] plays]$ cat local-dns.yml
---
- name: Dynamically Update /etc/hosts File
hosts: all
tasks:
- name: Update /etc/hosts using Jinja2
template:
src: hosts.j2
dest: /etc/hosts
Ensuite, lancez le playbook :
[[email protected] plays]$ ansible-playbook local-dns.yml
PLAY [Dynamically Update /etc/hosts File] *********************************************
TASK [Gathering Facts] ***************************
ok: [node4]
ok: [node2]
ok: [node1]
ok: [node3]
TASK [Update /etc/hosts using Jinja2] ***********************************************
changed: [node4]
changed: [node3]
changed: [node1]
changed: [node2]
PLAY RECAP **********************
node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node3 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
node4 : ok=2 changed=1 unreachable=0 failed=0 skipped=0
Tout semble bon jusqu'ici; exécutez maintenant la commande ad hoc suivante pour vérifier que /etc/hosts le fichier est correctement mis à jour sur node1 :
[[email protected] plays]$ ansible node1 -m command -a "cat /etc/hosts"
node1 | CHANGED | rc=0 >>
10.0.0.5 node1.linuxhandbook.local node1
10.0.0.6 node2.linuxhandbook.local node2
10.0.0.7 node3.linuxhandbook.local node3
10.0.0.8 node4.linuxhandbook.local node4
Parfait! Semble correctement formaté comme prévu.
J'espère que vous réalisez maintenant la puissance des modèles Jinja2 dans Ansible. Restez à l'écoute pour le prochain didacticiel où vous apprendrez à protéger les informations et les fichiers sensibles à l'aide d'Ansible Vault.