On vient de voir template en détail : idéal pour générer un fichier complet à partir d’un gabarit. Mais parfois, le besoin est bien plus modeste : modifier une seule ligne dans un fichier existant, sans toucher au reste. Utiliser template pour ça serait disproportionné — c’est là qu’intervient lineinfile.
Le cas d’usage de lineinfile
Imaginons qu’on doive simplement s’assurer qu’une ligne précise est présente dans un fichier de configuration système, sans réécrire le fichier entier :
- name: S'assurer que le swappiness est réglé correctement
ansible.builtin.lineinfile:
path: /etc/sysctl.conf
line: "vm.swappiness=10"
regexp: "^vm.swappiness="Ici, regexp indique à Ansible quelle ligne chercher pour la remplacer si elle existe déjà (peu importe sa valeur actuelle), et line indique la ligne finale voulue. Si aucune ligne ne correspond au regexp, la ligne est simplement ajoutée à la fin du fichier.
Pourquoi ne pas utiliser template pour ce cas ?
Techniquement, on pourrait générer tout /etc/sysctl.conf avec un template. Mais ce fichier appartient au système, contient potentiellement des dizaines de réglages ajoutés par d’autres processus, d’autres paquets, ou d’autres administrateurs. Le réécrire entièrement avec template écraserait tout ce qui n’est pas dans votre gabarit — un risque bien réel de casser des réglages qui n’ont rien à voir avec votre playbook.
lineinfile respecte le reste du fichier : il ne touche qu’à la ligne qui l’intéresse, laisse tout le reste intact.
Le tableau de décision
| Situation | Module à privilégier |
|---|---|
| Générer un fichier de configuration entier, propre à votre application | template |
| Modifier une seule ligne dans un fichier système partagé | lineinfile |
| Ajouter un bloc de plusieurs lignes identifiable (voir ci-dessous) | blockinfile |
| Le fichier n’est géré par personne d’autre que votre playbook | template (plus lisible et maintenable qu’une série de lineinfile) |
Le cas intermédiaire : blockinfile
Entre « une seule ligne » et « tout le fichier », il existe un module qu’on n’a pas encore cité : blockinfile. Il insère (ou retire) un bloc entier, délimité par des marqueurs automatiques, sans toucher au reste du fichier :
- name: Ajouter un bloc de configuration personnalisé
ansible.builtin.blockinfile:
path: /etc/hosts
block: |
10.0.1.10 nrd-web1
10.0.1.20 nrd-db1Ansible entoure automatiquement ce bloc de commentaires marqueurs (# BEGIN ANSIBLE MANAGED BLOCK / # END ANSIBLE MANAGED BLOCK), ce qui lui permet de retrouver exactement ce bloc lors d’une prochaine exécution, pour le mettre à jour ou le supprimer proprement — sans jamais toucher au reste du fichier.
regexp : le piège à connaître avec lineinfile
Un point d’attention important : sans regexp (ou avec un regexp trop large), lineinfile peut ajouter la même ligne à chaque exécution, cassant l’idempotence :
# ❌ Sans regexp : la ligne est ajoutée à chaque exécution si "line" ne matche jamais exactement une ligne existante
- name: Ajouter une ligne (mauvaise pratique)
ansible.builtin.lineinfile:
path: /etc/sysctl.conf
line: "vm.swappiness=10"
# ✅ Avec regexp : Ansible trouve la ligne existante (quelle que soit sa valeur actuelle) et la remplace
- name: Ajouter une ligne (bonne pratique)
ansible.builtin.lineinfile:
path: /etc/sysctl.conf
line: "vm.swappiness=10"
regexp: "^vm.swappiness="Le réflexe à prendre : dès que vous utilisez lineinfile pour modifier un réglage existant plutôt qu’ajouter une ligne totalement nouvelle, pensez systématiquement au regexp.
Ce qu’il faut retenir
template: pour un fichier entier, propre à votre application.lineinfile: pour une seule ligne, dans un fichier partagé avec d’autres réglages.blockinfile: pour un bloc de plusieurs lignes, identifiable et gérable indépendamment du reste du fichier.regexpaveclineinfileest ce qui garantit l’idempotence — sans lui, la ligne peut être dupliquée à chaque exécution.