Aller au contenu

Utilisation des blocks

Mise à jour :

logo

Dans une infrastructure automatisée, la fiabilité et la gestion fine des tâches sont des éléments essentiels pour assurer des déploiements stables et sans erreurs. Ansible, en tant qu’outil d’automatisation de configuration, permet déjà de gérer efficacement ces aspects grâce aux playbooks. Cependant, lorsque vous travaillez sur des environnements complexes, il est parfois nécessaire de regrouper des tâches, gérer des erreurs, ou encore définir des actions spécifiques en cas d’échec d’une opération. C’est là que les blocks entrent en jeu.

Pourquoi utiliser des blocks dans Ansible ?

Les blocks apportent une méthode puissante pour organiser et regrouper les tâches. Leur utilisation devient indispensable dans les environnements complexes où il est nécessaire de mieux gérer les erreurs et d’implémenter des comportements spécifiques selon les situations. Un block vous permet non seulement de structurer vos playbooks de manière plus lisible et maintenable, mais aussi de définir des actions à prendre en cas de réussite, d’échec, ou de conditions particulières.

Prenons un scénario dans lequel vous déployez une application web sur plusieurs serveurs. Ce processus pourrait inclure des étapes telles que l’installation des dépendances, la configuration du serveur web, le déploiement du code et le redémarrage du service. Si une étape échoue (par exemple, la configuration échoue à cause d’une erreur de syntaxe dans un fichier de configuration), il est indispensable de pouvoir gérer proprement cette situation. Sans blocks, vous seriez obligé d’ajouter des vérifications d’erreur pour chaque tâche, ce qui alourdit le code et rend le playbook plus difficile à maintenir.

Grâce aux blocks, vous pouvez regrouper ces tâches et spécifier ce qui doit se passer en cas de problème, tout en gardant votre playbook plus propre et lisible. En combinant cela avec les directives rescue et always, vous pouvez :

  • Gérer les erreurs : Si une tâche échoue, exécuter une série d’actions pour atténuer l’impact de l’échec (comme annuler des changements).
  • Exécuter des tâches conditionnelles : Avec always, vous pouvez vous assurer qu’une tâche sera exécutée quoi qu’il arrive, par exemple un redémarrage de service ou un nettoyage.
  • Faciliter le rollback : Lors de modifications complexes, vous pouvez spécifier un comportement de rollback si quelque chose se passe mal, en rétablissant un état stable.

Syntaxe de base d’un block

Un block est défini à l’aide de la directive block dans un playbook Ansible. À l’intérieur du block, vous pouvez inclure autant de tâches que nécessaire, en suivant la syntaxe habituelle d’Ansible. L’idée est de regrouper des tâches qui sont liées ou qui doivent être exécutées dans une certaine séquence.

---
- hosts: webservers
tasks:
- block:
- name: Installer Apache
ansible.builtin.apt:
name: apache2
state: present
- name: Copier le fichier de configuration d'Apache
ansible.builtin.copy:
src: /path/to/config
dest: /etc/apache2/apache2.conf

Dans cet exemple, nous avons deux tâches regroupées sous un blokc : l’installation d’Apache et la copie d’un fichier de configuration. Le bloc permet de les lier de manière logique, car elles participent toutes deux au processus d’installation et de configuration d’un serveur web.

Gestion des erreurs avec rescue et always

Les blocks prennent toute leur puissance avec les sections rescue et always, qui permettent de spécifier des comportements en cas de succès ou d’échec de l’une ou plusieurs tâches du block.

  • rescue : Cette section est exécutée si une ou plusieurs tâches dans le block échouent. C’est une manière efficace de gérer les erreurs en automatisant une série d’actions correctives.
  • always : Cette section contient des tâches qui seront toujours exécutées, que les tâches du block aient échoué ou non. Cela est particulièrement utile pour des actions de nettoyage ou de notifications.

Voici un exemple complet d’un block avec les sections rescue et always :

---
- hosts: app_servers
tasks:
- block:
- name: Télécharger et installer l'application
ansible.builtin.get_url:
url: https://example.com/app.tar.gz
dest: /tmp/app.tar.gz
- name: Extraire l'application
ansible.builtin.unarchive:
src: /tmp/app.tar.gz
dest: /opt/app/
remote_src: yes
- name: Configurer l'application
command: /opt/app/configure.sh
rescue:
- name: Supprimer les fichiers de l'application en cas d'erreur
ansible.builtin.file:
path: /opt/app
state: absent
always:
- name: Nettoyer le fichier temporaire
ansible.builtin.file:
path: /tmp/app.tar.gz
state: absent

Dans cet exemple, trois tâches sont définies dans le block : le téléchargement, l’extraction et la configuration de l’application. Si l’une des tâches échoue (par exemple, la configuration ne se termine pas correctement), la section rescue est exécutée, supprimant les fichiers de l’application pour restaurer l’état du serveur à son état initial. Qu’il y ait une erreur ou non, la section always s’assure que le fichier temporaire /tmp/app.tar.gz est toujours supprimé, afin d’éviter de laisser des fichiers inutiles sur le système.

Utiliser des conditions avec les blocks

L’un des avantages majeurs des blocks dans Ansible est qu’ils peuvent être combinés avec des conditions pour adapter l’exécution des tâches en fonction de l’état du système ou des résultats de tâches précédentes. Cette flexibilité permet de contrôler finement l’exécution des blocks, en s’assurant que certaines actions ne se produisent que si certaines conditions sont remplies. L’utilisation des conditions avec des blocks permet de rendre vos playbooks plus dynamiques et robustes, en réagissant aux situations rencontrées lors de l’exécution.

Pour associer une condition à un block, il suffit d’utiliser la directive when, comme pour les tâches individuelles. La condition sera évaluée avant l’exécution des tâches contenues dans le block. Si la condition est remplie, alors toutes les tâches du block seront exécutées ; dans le cas contraire, le block sera ignoré.

---
- hosts: app_servers
tasks:
- name: Vérifier si le service Nginx est actif
ansible.builtin.systemd:
name: nginx
state: started
register: nginx_status
- block:
when: nginx_status.state == "started"
- name: Télécharger l'application
ansible.builtin.get_url:
url: https://example.com/app.tar.gz
dest: /tmp/app.tar.gz
- name: Installer l'application
ansible.builtin.command: tar -xzf /tmp/app.tar.gz -C /opt/app/
rescue:
- name: Supprimer l'application en cas d'échec
ansible.builtin.file:
path: /opt/app/
state: absent
always:
- name: Envoyer une notification de statut
community.general.mail:
to: admin@example.com
subject: "Statut du déploiement"
body: "Le déploiement a échoué ou réussi."

Ici, le block ne sera exécuté que si Nginx est actif. Si une erreur survient pendant le téléchargement ou l’installation de l’application, la section rescue s’exécutera pour supprimer l’application. Ensuite, quelle que soit l’issue, la section always enverra un email pour informer l’administrateur du statut du déploiement.

Cas d’usage de rescue et always

Les directives rescue et always d’Ansible offrent des mécanismes puissants pour gérer les erreurs et garantir l’exécution de certaines tâches, quelles que soient les circonstances. Ensemble, elles permettent d’assurer la stabilité des opérations automatisées et d’implémenter des comportements spécifiques en fonction des résultats des tâches. Voici les principaux cas d’usage pour chacune de ces directives.

Utilisation de rescue

La directive rescue permet de définir des tâches correctives qui s’exécutent uniquement en cas d’échec d’une ou plusieurs tâches dans un block. Cela est essentiel pour assurer des actions de récupération ou de rollback lorsque des erreurs se produisent. Voici les cas d’usage principaux pour rescue :

  • Rollback des changements en cas d’échec : Si une opération critique échoue (comme une mise à jour de service ou une configuration système), vous pouvez définir des actions de rollback pour restaurer l’état initial du système.
  • Annulation de modifications partielles : Dans des processus complexes avec plusieurs étapes, si une tâche échoue en milieu de processus, rescue permet d’annuler toutes les modifications déjà effectuées pour éviter un état incohérent.
  • Nettoyage de ressources temporaires : Si une tâche échoue, rescue peut être utilisé pour nettoyer des fichiers temporaires, arrêter des services partiellement démarrés ou supprimer des configurations non valides.
  • Récupération d’erreurs réseau : Dans des environnements distribués, rescue peut gérer des échecs de connexions ou des erreurs réseau en essayant des solutions alternatives (comme basculer vers un serveur secondaire ou changer de méthode).
  • Actions alternatives en cas d’échec : Si une méthode échoue (par exemple, le démarrage d’un service via une commande), rescue peut essayer d’autres méthodes ou solutions pour accomplir la tâche.
  • Récupération automatique des services : Dans les infrastructures critiques, rescue peut être utilisé pour redémarrer automatiquement des services ou systèmes en cas d’échec d’une tâche de maintenance ou de configuration.

Utilisation de always

La directive always garantit que certaines tâches seront exécutées, que les tâches précédentes réussissent ou échouent. Cela est particulièrement utile pour des opérations qui doivent être effectuées inconditionnellement. Voici les principaux cas d’usage pour always :

  • Nettoyage systématique : always est souvent utilisé pour assurer le nettoyage de fichiers temporaires, de logs ou de configurations, qu’une tâche ait réussi ou non. Cela permet de maintenir un environnement propre.
  • Vérification de l’état final d’un service : Après l’exécution d’un playbook, always peut garantir que des vérifications sont faites pour s’assurer que certains services critiques sont démarrés et fonctionnent correctement.
  • Envoi de notifications ou de rapports : always permet de notifier les administrateurs ou les systèmes de monitoring de l’issue d’un processus (via email, Slack, ou un autre canal), qu’il s’agisse d’un succès ou d’un échec.
  • Validation des configurations : Vous pouvez utiliser always pour valider les configurations ou l’intégrité des systèmes à la fin d’un déploiement, peu importe que les tâches aient échoué ou non.
  • Sauvegarde et restauration automatiques : always peut garantir qu’une sauvegarde est systématiquement effectuée ou que des ressources temporaires sont toujours restaurées après l’exécution d’un playbook, indépendamment de l’issue des autres tâches.
  • Redémarrage obligatoire des services : always permet de s’assurer que certains services sont toujours redémarrés après des opérations, qu’il y ait eu des erreurs ou non, garantissant ainsi la continuité des services.

Conclusion

L’utilisation des blocks dans Ansible, associée aux directives rescue et always, permet de rendre vos playbooks non seulement plus robustes, mais aussi plus flexibles face aux erreurs et aux situations imprévues. En structurant vos tâches avec des blocks, vous pouvez regrouper des opérations liées et gérer des scénarios complexes, tout en conservant un contrôle granulaire sur les actions correctives ou systématiques à prendre.