Ansible: Variables et logique
Notions abordées
- Variables dans Ansible
- Structures conditionnelles (
if,when) - Boucles (
loops) - Handlers
Suivi d'un laboratoire intégrant ces notions.
Variables
Dans Ansible, dès que les playbooks deviennent légèrement plus complexes, il devient primordial de déclarer et d'utiliser des variables. En effet, les variables permettent de rendre les playbooks plus dynamiques, réutilisables et faciles à maintenir.
Prenons l'exemple d'une entreprise qui déploie une application web sur plusieurs serveurs. Chaque serveur peut avoir des configurations différentes, telles que le port d'écoute, le nom de la base de données, ou encore les chemins des fichiers de configuration. Nous pourrions définir ces informations directement dans les playbooks, comme nous l'aurions fait en utilisant les notions apprises la semaine dernière:
---
- name: Déployer l'application web
hosts: webservers
tasks:
- name: Configurer le port d'écoute
lineinfile:
path: /etc/myapp/config.ini
regexp: '^port='
line: 'port=8080'
- name: Configurer la base de données
lineinfile:
path: /etc/myapp/config.ini
regexp: '^database='
line: 'database=mydb'
Cependant, cette façon de faire comporte ses limitations:
- Si nous devons changer le port d'écoute ou le nom de la base de données, nous devons modifier manuellement chaque playbook où ces valeurs sont définies.
- Si nous avons plusieurs serveurs avec des configurations différentes, nous devrons créer des playbooks distincts pour chaque serveur, ce qui entraîne une duplication de code et complique la maintenance.
- Retrouver ces valeurs dans un long playbook peut devenir fastidieux.
C'est là qu'entre en jeu les variables.En utilisant des variables, nous pouvons écrire un seul playbook qui s'adapte à chaque serveur en fonction de ses besoins spécifiques.
Hiérarchie des variables
Il existe plusieurs façons de définir des variables dans Ansible. Ils sont listés ici par ordre de priorité, de la plus basse à la plus haute (c'est-à-dire que les variables définies plus bas dans la liste écraseront les variables définies plus haut) :
- Variables définies dans les rôles dans
defaults(defaults/main.yml) - Variables définies dans les fichiers d'inventaire:
- Variables définies dans le répertoire d'inventaire
hosts.iniouhosts.ymlpour un groupe spécifique - Variables définies dans le répertoire
group_vars/all - Variables définies dans le répertoire
group_vars/<nom_du_groupe> - Variables définies dans le répertoire d'inventaire
hosts.iniouhosts.ymlpour un hôte spécifique - Variables définies dans le répertoire
host_vars/<nom_de_l_hôte>
- Variables définies dans le répertoire d'inventaire
- Variables définies dans les playbooks
- avec le mot-clé
vars - avec le mot-clé
vars_files
- avec le mot-clé
- Variables définies dans les rôles dans
vars(vars/main.yml) - Variables définies avec
set_factouregister - Variables définies via la ligne de commande avec l'option
-eou--extra-vars
Puisque nous verrons les rôles au prochain cours, nous verrons les points 2 à 7 (sauf 4) dans ce cours.
Variables dans les fichiers d'inventaire
Nous avons déjà vu comment définir des groupes et des hôtes dans un fichier d'inventaire, que nous avions appelé hosts.ini. Nous pouvons également définir des variables spécifiques à un hôte ou à un groupe d'hôtes dans ce fichier.
Les variables les plus communes à définir dans un fichier d'inventaire sont les informations de connexion, telles que l'utilisateur SSH, le mot de passe, ou la clé privée.
Par exemple:
[webservers]
web1 ansible_host=192.168.1.10 ansible_user=alice ansible_ssh_private_key_file=/path/to/key
web2 ansible_host=192.168.1.11 ansible_user=bob ansible_ssh_private_key_file=/path/to/key
[dbservers]
db1 ansible_host=192.168.1.20 ansible_user=carol ansible_ssh_private_key_file=/path/to/key
[webservers:vars]
http_port=80
max_clients=200
[all:vars]
ntp_server=ntp.example.com
Ici, les variables ansible_user et ansible_ssh_private_key_file sont définies pour chaque hôte individuellement, les variables http_port et max_clients sont définies pour tous les hôtes du groupe webservers, tandis que ntp_server est définie pour tous les hôtes de l'inventaire.
⚠️ S'il y a conflit entre des variables définies dans le fichier d'inventaire, alors la priorité sera accordée aux variables définies dans les sections spécifiques aux hôtes par rapport aux sections spécifiques aux groupes.
Variables définies dans les dossiers host_vars et group_vars
Ansible permet également de définir des variables dans des fichiers séparés situés dans les dossiers host_vars et group_vars. Ces dossiers doivent être situés dans le même répertoire que votre fichier d'inventaire ou dans le répertoire racine de votre projet Ansible. Ce sont des dossiers spéciaux qu'Ansible reconnaît automatiquement.
Supposons que nous gardons le fichier d'inventaire indiqué plus haut, voici comment organiser ces dossiers :
├── hosts.ini
├── host_vars/
│ ├── web1.yml
│ └── db1.yml
└── group_vars/
├── webservers.yml
└── dbservers.yml
Les fichiers YAML dans host_vars et group_vars contiennent des paires clé-valeur définissant les variables. Comme leurs noms l'indiquent, les fichiers dans host_vars sont spécifiques à un hôte, tandis que ceux dans group_vars sont spécifiques à un groupe d'hôtes.
Par exemple, le fichier host_vars/web1.yml pourrait contenir :
---
apache_port: 8080
document_root: /var/www/html/webserver1
Et le fichier host_vars/webserver2.yml pourrait contenir :
---
apache_port: 9090
document_root: /var/www/html/webserver2
Et le fichier group_vars/webservers.yml pourrait contenir :
---
max_clients: 300
enable_ssl: true
Ici, apache_port et document_root sont des variables spécifiques à l'hôte web1, tandis que max_clients et enable_ssl sont des variables communes à tous les hôtes du groupe webservers.
Si un conflit de noms de variables survient, les variables définies dans host_vars auront la priorité sur celles définies dans group_vars.
Variables définies dans les playbooks
Les variables peuvent également être définies directement dans les playbooks Ansible en utilisant les mots-clé vars ou vars_files. Par exemple, dans un playbook, vous pouvez définir des variables comme suit :
---
- name: Introduction aux variables
hosts: localhost
vars:
app_name: "MonApplication"
app_version: "1.2.3"
app_port: 8080
tasks:
- name: Afficher les informations de l'application
debug:
msg: "L'application {{ app_name }} version {{ app_version }} écoute sur le port {{ app_port }}"
Ici, les variables app_name, app_version, et app_port sont définies dans le playbook et peuvent être utilisées dans les tâches du playbook.
Il est aussi possible de définir un fichier externe contenant des variables et de l'inclure dans le playbook avec vars_files :
---
- name: Utiliser des variables depuis un fichier
hosts: localhost
vars_files:
- vars/app_config.yml
tasks:
- name: Afficher la configuration de la base de données
debug:
msg: "DB: {{ database.user }}@{{ database.host }}:{{ database.port }}/{{ database.name }}"
- name: Afficher la configuration de backup
debug:
msg: "Backup activé: {{ backup.enabled }}, Rétention: {{ backup.retention_days }} jours"
Avec un fichier vars/app_config.yml comme suit :
---
database:
host: "db.example.com"
port: 5432
name: "production_db"
user: "app_user"
backup:
enabled: true
retention_days: 30
destination: "/backup/db"
Variables définies avec set_fact ou register
Ansible permet également de définir des variables dynamiquement pendant l'exécution d'un playbook en utilisant le module set_fact ou register. Cela est utile lorsque vous souhaitez créer ou modifier des variables en fonction des résultats des tâches précédentes.
Nous avons vu au cours précédent l'utilisation de register pour capturer la sortie d'une commande. Par exemple :
---
- name: Capturer la sortie d'une commande
hosts: localhost
tasks:
- name: Obtenir la date actuelle
command: date
register: current_date
- name: Afficher la date actuelle
debug:
msg: "La date actuelle est : {{ current_date.stdout }}"
Ici, la tâche command: date exécute la commande date et stocke sa sortie dans la variable current_date. La tâche suivante utilise cette variable pour afficher la date actuelle.
Le module set_fact permet également de définir des variables personnalisées.
Par exemple :
---
- name: Définir des variables dynamiques avec set_fact
hosts: localhost
tasks:
- name: Définir une variable dynamique
set_fact:
dynamic_variable: "Valeur dynamique"
- name: Afficher la variable dynamique
debug:
msg: "La variable dynamique est : {{ dynamic_variable }}"
Il est utile d'utiliser set_fact lorsque vous souhaitez créer des variables basées sur des conditions ou des résultats de tâches précédentes. Nous verrons les conditions plus en détail dans la section suivante.
En cas de conflit de noms, les variables définies avec set_fact auront la priorité sur celles définies avec register.
Variables passées via la ligne de commande
Il est également possible de passer des variables directement via la ligne de commande lors de l'exécution d'un playbook en utilisant l'option -e ou --extra-vars. Par exemple :
ansible-playbook playbook.yml -e "app_port=9090 app_debug=true"
Cela définit les variables app_port et app_debug pour le playbook en cours d'exécution. Les variables passées de cette manière ont la plus haute priorité et écraseront toutes les autres définitions de variables.
Conditions et boucles
Ansible permet d'utiliser des conditions et des boucles pour contrôler le flux d'exécution des tâches dans un playbook.
Les conditions sont définies à l'aide du mot-clé when, tandis que les boucles sont définies à l'aide du mot-clé loop.
Conditions avec when
Nous utilisons le mot-clé when pour exécuter une tâche uniquement si une condition spécifique est remplie. Par exemple :
---
- name: Exemple de condition avec when
hosts: localhost
vars:
is_production: true
tasks:
- name: Tâche exécutée uniquement en production
debug:
msg: "Ceci est une tâche de production."
when: is_production
Ici, la tâche ne sera exécutée que si la variable is_production est vraie.
La valeur de la condition peut être basée sur n'importe quelle variable définie dans le playbook, l'inventaire, ou même des faits collectés à partir des hôtes.
Voici un exemple comportant différentes conditions :
---
- name: Conditions basiques
hosts: localhost
vars:
environment: "production"
enable_monitoring: true
app_version: 2.5
tasks:
- name: Tâche seulement en production
debug:
msg: "Configuration de production activée"
when: environment == "production"
- name: Tâche seulement si monitoring activé
debug:
msg: "Installation des outils de monitoring"
when: enable_monitoring
- name: Vérifier la version de l'application
debug:
msg: "Version récente détectée"
when: app_version >= 2.0
- name: Conditions multiples (AND)
debug:
msg: "Production avec monitoring"
when:
- environment == "production"
- enable_monitoring
- name: Conditions multiples (OR)
debug:
msg: "Environnement de développement ou de test"
when: environment == "dev" or environment == "test"
Explications des conditions:
- La tâche "Tâche seulement en production" s'exécute uniquement si l'environnement est "production" (comparaison de chaînes).
- La tâche "Tâche seulement si monitoring activé" s'exécute si la variable
enable_monitoringest vraie (variable booléenne). - La tâche "Vérifier la version de l'application" s'exécute si la version de l'application est supérieure ou égale à 2.0 (comparaison numérique).
- La tâche "Conditions multiples (AND)" s'exécute si les deux conditions sont vraies (utilisation de listes pour AND).
- La tâche "Conditions multiples (OR)" s'exécute si l'une des conditions est vraie (utilisation de l'opérateur
or).
Comparaison avec variables facts
Ansible collecte automatiquement des informations sur les hôtes appelées facts. Vous l'avez remarqué dans le cours précédent avec la tâche gather_facts qui collecte ces faits. Il est possible de utiliser ces faits dans des conditions when. Par exemple :
---
- name: Exemple avec des facts
hosts: all
tasks:
- name: Tâche exécutée uniquement sur les hôtes Linux
debug:
msg: "Ceci est un hôte Linux."
when: ansible_facts['os_family'] == "Debian"
Ici, la tâche ne sera exécutée que sur les hôtes dont la famille d'OS est "Debian".
Les facts disponibles peuvent être consultés en exécutant la commande ansible -m setup <nom_de_l_hôte>. Le résultat sera assez long!
Conditions avec des variables enregistrées
Il est également possible d'utiliser des variables enregistrées avec register dans des conditions when. Par exemple :
----
name: Exemple avec des variables enregistrées
hosts: localhost
tasks:
- name: Exécuter une commande et enregistrer la sortie
command: /bin/echo "Hello World"
register: command_result
- name: Tâche exécutée si la commande a réussi
debug:
msg: "La commande a réussi avec la sortie : {{ command_result.stdout }}"
when: command_result.rc == 0
Ici, la tâche de débogage ne sera exécutée que si la commande précédente a réussi (code de retour rc égal à 0). Pour cela, il faut d'accéder aux attributs de la variable enregistrée. Pour une commande, les attributs courants sont :
stdout: la sortie standard de la commandestderr: la sortie d'erreur de la commanderc: le code de retour de la commande (0 indique généralement le succès)
Cependant, les attributs disponibles peuvent varier en fonction du module utilisé. Pour connaître les attributs spécifiques disponibles pour une tâche enregistrée, vous pouvez consulter la documentation du module Ansible correspondant.
Les mots-clés failed_when et changed_when
Par défaut, une tâche Ansible est considérée comme ayant échoué si le code de retour (rc) est différent de zéro. De plus, une tâche est considérée comme ayant modifié l'état du système (c'est-à-dire "changed") si elle effectue une action qui modifie effectivement quelque chose sur l'hôte cible.
Cependant, il est possible de personnaliser cette logique en utilisant les mots-clés failed_when et changed_when.
Par exemple :
---
- name: Exemple avec failed_when
hosts: localhost
tasks:
- name: Exécuter une commande personnalisée
command: /bin/false
register: command_result
failed_when: command_result.rc != 0 and "'specific error' in command_result.stderr"
Ici, la tâche sera considérée comme ayant échoué uniquement si le code de retour est différent de zéro et que la sortie d'erreur contient la chaîne "specific error". Sinon, la tâche sera considérée comme réussie, même si le code de retour est différent de zéro.
Pourquoi définir l'état d'échec est important? Parce que cela affecte le flux d'exécution du playbook. Si une tâche échoue, Ansible arrêtera l'exécution du playbook par défaut, sauf si vous utilisez ignore_errors: yes ou gérez les erreurs avec des blocs rescue.
Il est également possible de simplement mettre failed_when: false pour forcer une tâche à toujours réussir, quel que soit son résultat.
De même, le mot-clé changed_when permet de contrôler si une tâche est considérée comme ayant modifié l'état du système. Par exemple :
---
name: Exemple avec changed_when
hosts: localhost
tasks:
- name: Exécuter une commande
command: /bin/true
register: command_result
changed_when: false
Ici, la tâche sera toujours considérée comme n'ayant pas modifié l'état du système. Par défaut, le module command considère qu'il a modifié l'état du système, mais en utilisant changed_when: false, nous annulons ce comportement.
Cela aura un impact sur les rapports d'Ansible, car les tâches "changed" sont souvent utilisées pour indiquer que quelque chose a été modifié sur l'hôte cible.
Exemple complet avec conditions
Voici un exemple complet combinant plusieurs types de conditions :
---
- name: Conditions avec register
hosts: localhost
tasks:
- name: Vérifier si un service existe
stat:
path: /etc/systemd/system/nginx.service
register: nginx_service
- name: Message si le service existe
debug:
msg: "Nginx est installé en tant que service"
when: nginx_service.stat.exists
- name: Exécuter une commande
command: echo "test"
register: cmd_result
changed_when: false
- name: Vérifier si la commande a réussi
debug:
msg: "Commande réussie avec code: {{ cmd_result.rc }}"
when: cmd_result.rc == 0
- name: Test avec failed_when
command: /bin/false
register: failing_command
failed_when: false # Empêcher l'échec du playbook
- name: Réagir à l'échec
debug:
msg: "La commande a échoué comme prévu"
when: failing_command.rc != 0
Explications :
- La première tâche utilise le module
statpour vérifier si le service Nginx existe et enregistre le résultat dansnginx_service. La tâche suivante affiche un message si le service existe, en utilisant une conditionwhenet l'attributexistsde la variable enregistrée. - La troisième tâche exécute une commande simple et enregistre le résultat dans
cmd_result. Cette tâche sera considérée comme n'ayant pas modifié l'état du système grâce àchanged_when: false. - La quatrième tâche affiche un message si la commande précédente a réussi, en vérifiant le code de retour avec une condition
when. - La cinquième tâche exécute une commande qui échoue, mais grâce à
failed_when: false, elle ne provoque pas l'échec du playbook. - La dernière tâche affiche un message si la commande a effectivement échoué, en utilisant une condition
whenbasée sur le code de retour.
Boucles avec loop
Ansible permet d'exécuter une tâche plusieurs fois en utilisant des boucles définies avec le mot-clé loop. Par exemple :
---
- name: Exemple de boucle avec loop
hosts: localhost
tasks:
- name: Installer plusieurs paquets
apt:
name: "{{ item }}"
state: present
loop:
- git
- curl
- vim
La syntaxe {{ item }} est utilisée pour référencer l'élément courant de la boucle. Dans cet exemple, la tâche installe les paquets git, curl, et vim un par un.
Il est possible d'itérer sur des listes plus complexes, comme des dictionnaires. Par exemple :
---
- name: Exemple de boucle avec dictionnaires
hosts: localhost
tasks:
- name: Créer plusieurs utilisateurs
user:
name: "{{ item.name }}"
state: present
uid: "{{ item.uid }}"
loop:
- { name: "alice", uid: 1001 }
- { name: "bob", uid: 1002 }
- { name: "carol", uid: 1003 }
La syntaxe {{ item.name }} et {{ item.uid }} est utilisée pour accéder aux clés du dictionnaire courant dans la boucle.
Boucle avec condition
Il est également possible de combiner des boucles avec des conditions when. Par exemple :
- name: Boucle avec condition
hosts: localhost
tasks:
- name: Installer des paquets conditionnellement
apt:
name: "{{ item }}"
state: present
loop:
- git
- curl
- vim
when: item != "vim"
Ici, la tâche installe les paquets git et curl, mais pas vim, grâce à la condition when qui vérifie que l'élément courant n'est pas "vim".
Le même principe est aussi applicable aux boucles sur des dictionnaires.
---
- name: Boucles conditionnelles
hosts: localhost
vars:
users:
- { name: 'alice', admin: true, active: true }
- { name: 'bob', admin: false, active: true }
- { name: 'charlie', admin: true, active: false }
- { name: 'dave', admin: false, active: true }
tasks:
- name: Traiter seulement les utilisateurs actifs
debug:
msg: "Configuration de {{ item.name }}"
loop: "{{ users }}"
when: item.active
- name: Traiter seulement les admins actifs
debug:
msg: "Droits admin pour {{ item.name }}"
loop: "{{ users }}"
when:
- item.active
- item.admin
Handlers
Les handlers sont des tâches spéciales dans Ansible qui ne s'exécutent que lorsqu'elles sont "notifiées" par d'autres tâches. Ils sont généralement utilisés pour effectuer des actions qui doivent être effectuées après qu'une modification a été apportée, comme redémarrer un service après la mise à jour de sa configuration. Par exemple, si vous modifiez un fichier de configuration pour un service web, vous pouvez notifier un handler pour redémarrer ce service afin que les modifications prennent effet.
---
- name: Exemple avec handlers
hosts: localhost
tasks:
- name: Mettre à jour le fichier de configuration
template:
src: webserver.conf.j2
dest: /etc/webserver/webserver.conf
notify: Redémarrer le service webserver
handlers:
- name: Redémarrer le service webserver
service:
name: webserver
state: restarted
À remarquer:
- La mention
notify: Redémarrer le service webserverdans la tâche indique qu'elle notifie le handler nommé "Redémarrer le service webserver" si la tâche modifie le fichier de configuration. - Le handler "Redémarrer le service webserver" est défini dans la section
handlerset utilise le moduleservicepour redémarrer le service webserver. - L'indentation est importante : les handlers doivent être définis au même niveau que les tâches, mais dans une section distincte appelée
handlers.
Voici quelques points importants à retenir concernant les handlers :
- Les handlers ne seront exécutés que si une tâche les notifie ET que cette tâche a effectivement apporté une modification. Si une tâche ne modifie rien (par exemple, si le fichier de configuration est déjà à jour, le paquet est déjà installé, etc.), alors le handler ne sera pas exécuté. De plus, si une tâche qui devrait notifier un handler n'est pas exécutée (par exemple à cause d’une condition when), alors le handler ne sera pas exécuté.
- Les handlers s’exécutent une seule fois, et uniquement à la fin d’un play. Si vous devez absolument changer ce comportement et exécuter les handlers au milieu d’un playbook, vous pouvez utiliser le module meta, par exemple :
- meta: flush_handlers
- Si le play échoue sur un hôte (ou tous les hôtes) avant que les handlers ne soient notifiés, les handlers ne seront jamais exécutés. Si vous souhaitez que les handlers s’exécutent même après l’échec du playbook, vous pouvez utiliser le module meta comme dans l’exemple ci-dessus dans une tâche séparée, ou utiliser l’option de ligne de commande :
--force-handlers
Notez toutefois que les handlers ne s’exécuteront jamais sur les hôtes devenus injoignables pendant l’exécution du playbook.
Exemple complet avec handlers et conditions :
---
- name: Handlers multiples
hosts: localhost
tasks:
- name: Modifier la configuration Apache
debug:
msg: "Modification de httpd.conf"
changed_when: true
notify:
- reload_apache
- notify_monitoring
- name: Modifier un certificat SSL
debug:
msg: "Installation du nouveau certificat"
changed_when: true
notify:
- reload_apache
- send_slack_notification
handlers:
- name: reload_apache
debug:
msg: ">>> Rechargement d'Apache <<<"
- name: notify_monitoring
debug:
msg: ">>> Notification au système de monitoring <<<"
- name: send_slack_notification
debug:
msg: ">>> Envoi de notification Slack <<<"
Dans cet exemple :
- La tâche "Modifier la configuration Apache" notifie deux handlers :
reload_apacheetnotify_monitoring. - La tâche "Modifier un certificat SSL" notifie également le handler
reload_apacheainsi quesend_slack_notification. - Le handler
reload_apachesera exécuté une seule fois à la fin du play, même s'il est notifié par deux tâches différentes. - Même si les tâches utilisent le module
debugqui ne modifie rien, nous forçons le changement avecchanged_when: truepour illustrer le fonctionnement des handlers. Ainsi, les handlers seront bien exécutés.
Utilisation de listen pour les handlers
Ansible permet également d'utiliser le mot-clé listen pour regrouper plusieurs notifications sous un même nom de handler. Cela permet de simplifier la gestion des notifications lorsque plusieurs tâches doivent notifier le même handler.
Voici un exemple :
---
- name: Handlers avec listen
hosts: localhost
tasks:
- name: Modifier la configuration web
debug:
msg: "Modification de la config web"
changed_when: true
notify: restart_web_stack
- name: Mettre à jour le certificat
debug:
msg: "Mise à jour du certificat"
changed_when: true
notify: restart_web_stack
handlers:
- name: Arrêter nginx
debug:
msg: ">>> Arrêt de Nginx <<<"
listen: restart_web_stack
- name: Vider le cache
debug:
msg: ">>> Vidage du cache <<<"
listen: restart_web_stack
- name: Démarrer nginx
debug:
msg: ">>> Démarrage de Nginx <<<"
listen: restart_web_stack
Dans cet exemple :
- Les deux tâches "Modifier la configuration web" et "Mettre à jour le certificat" notifient le même handler
restart_web_stack. - Le handler
restart_web_stackest défini avec plusieurs sous-tâches utilisant le mot-clélisten. Ainsi, lorsquerestart_web_stackest notifié, toutes les sous-tâches associées seront exécutées dans l'ordre où elles sont définies. - Cela permet de regrouper plusieurs actions liées à une même notification sous un seul nom de handler, simplifiant ainsi la gestion des notifications dans le playbook.
Forcer l'exécution des handlers avec meta: flush_handlers
Par défaut, les handlers sont exécutés à la fin d'un play. Cependant, il est possible de forcer l'exécution des handlers à un moment spécifique dans le playbook en utilisant le module meta avec l'option flush_handlers. Voici un exemple :
---
- name: Handlers avec meta flush
hosts: localhost
tasks:
- name: Modifier la configuration critique
debug:
msg: "Modification critique de la config"
changed_when: true
notify: restart_critical_service
- name: Forcer l'exécution des handlers maintenant
meta: flush_handlers
- name: Tâche qui dépend du redémarrage
debug:
msg: "Cette tâche s'exécute après le redémarrage"
- name: Autre modification
debug:
msg: "Autre modification"
changed_when: true
notify: restart_critical_service
handlers:
- name: restart_critical_service
debug:
msg: ">>> REDÉMARRAGE DU SERVICE CRITIQUE <<<"
Dans cet exemple :
- La tâche "Modifier la configuration critique" notifie le handler
restart_critical_service. - La tâche suivante utilise
meta: flush_handlerspour forcer l'exécution immédiate des handlers notifiés jusqu'à ce point. - La tâche "Tâche qui dépend du redémarrage" s'exécute après que le handler a été exécuté.
- La dernière tâche notifie à nouveau le handler
restart_critical_service, mais cette fois, il sera exécuté à la fin du play, car il n'y a pas de nouveaumeta: flush_handlersaprès cette tâche.