
Le module ansible.builtin.copy est le module de transfert de référence en Ansible. Il pousse un fichier du control node vers le managed node, ou écrit un contenu inline via content:. Cette page couvre les options qui font la différence en production : mode:, owner:, backup: true, validate:, et le piège du content: non terminé par \n. copy: agit sur la donnée (octets transférés) — pour gérer uniquement les métadonnées, utiliser file:.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Les deux modes de
copy::src:(fichier local) vscontent:(inline). - Les options critiques :
mode,owner,group,backup,force,validate. - Le piège idempotence/diff quand
content:n’est pas terminé par\n. - Quand préférer
template:plutôt quecopy:(interpolation Jinja2 nécessaire).
Prérequis
Section intitulée « Prérequis »- Avoir un lab fonctionnel avec au moins un managed node (cf. Préparer le lab KVM).
- Connaître la syntaxe d’un play (cf. Plays et tasks).
Mode 1 — Transfert d’un fichier local (src:)
Section intitulée « Mode 1 — Transfert d’un fichier local (src:) »Le mode le plus courant. Le fichier source est cherché dans files/ du playbook (ou via chemin absolu/relatif), et transféré tel quel sur le managed node.
- name: Deployer le banner SSH ansible.builtin.copy: src: files/issue.net dest: /etc/issue.net owner: root group: root mode: "0644" backup: truebackup: true crée dest.<timestamp> avant écrasement — utile en troubleshooting et pour les rollbacks rapides. À utiliser systématiquement sur les fichiers de configuration critiques (sshd_config, nginx.conf).
mode: accepte la forme octale ("0644" — toujours en string pour éviter le piège YAML qui interprète 0644 comme un nombre) ou la forme symbolique ("u=rw,g=r,o=r"). Préférer l’octale, plus concise.
Mode 2 — Contenu inline (content:)
Section intitulée « Mode 2 — Contenu inline (content:) »Pour des fichiers courts (banner, motd, fichier de tag), content: évite de créer un fichier dans files/.
- name: Marquer le serveur comme provisionne ansible.builtin.copy: content: "Provisionne par Ansible le {{ ansible_date_time.iso8601 }}\n" dest: /etc/ansible-managed mode: "0644"Piège fréquent : oublier le \n final. Sans newline, la commande cat /etc/ansible-managed affiche la ligne accolée au prompt, et certains parseurs (cron, systemd) refusent les fichiers sans newline final. Toujours terminer content: par \n.
Pour des contenus dépassant 5-10 lignes, passer à template: — content: devient illisible avec des sauts de ligne échappés.
Validate : exécuter une commande de validation avant d’écraser
Section intitulée « Validate : exécuter une commande de validation avant d’écraser »validate: lance une commande externe sur le fichier temporaire, et n’écrase la cible que si la commande renvoie 0. Pattern critique pour sshd_config, nginx.conf, sudoers — un fichier mal formé verrouille le système.
- name: Deployer sshd_config valide ansible.builtin.copy: src: files/sshd_config dest: /etc/ssh/sshd_config mode: "0600" backup: true validate: 'sshd -t -f %s'Le %s est remplacé par le chemin du fichier temporaire. Si sshd -t échoue, /etc/ssh/sshd_config reste intact — pas de coupure SSH possible.
Idempotence et diff
Section intitulée « Idempotence et diff »copy: est idempotent : si le fichier source a le même checksum que la destination, et les mêmes permissions, la tâche reste ok (pas changed). La détection se fait via SHA1 côté managed node.
Conséquence : modifier le mode: sans toucher au contenu → changed. Modifier juste un caractère du fichier source → changed. Re-exécuter sans modification → ok.
ansible-playbook --check --diff montre précisément les octets qui changeraient — utiliser systématiquement avant un déploiement en production.
Options moins connues mais utiles
Section intitulée « Options moins connues mais utiles »| Option | Usage |
|---|---|
force: false | N’écrase pas si dest existe déjà — utile pour des configs initiales que l’utilisateur a customisées |
remote_src: true | src: est sur le managed node, pas sur le control node |
directory_mode: | Mode des répertoires créés en chemin (utile avec recursive copy) |
unsafe_writes: true | Permet l’écriture sur des FS qui ne supportent pas rename atomique (NFS sans verrous) |
decrypt: true | Déchiffre le fichier source si chiffré avec Ansible Vault |
Pièges courants
Section intitulée « Pièges courants »| Symptôme | Cause | Fix |
|---|---|---|
Fichier copié avec mode: 0644 non quoté | YAML interprète 0644 comme nombre 644 (octets 1004) | Toujours quoter : mode: "0644" |
content: apparaît sans newline final | Oubli du \n | Ajouter \n à la fin de la string |
changed: à chaque run sur un fichier statique | Contenu du files/ modifié par éditeur (CRLF, EOF) | Vérifier cat -A files/source |
validate: ignoré | Le %s manque dans la commande | Ajouter %s : validate: 'sshd -t -f %s' |
À retenir
Section intitulée « À retenir »copy:transfère un fichier (src:) ou un contenu inline (content:) avec idempotence par checksum SHA1.mode:toujours quoté ("0644") pour éviter le piège YAML octal/décimal.backup: truesur tout fichier de config critique — coût nul, valeur énorme en troubleshooting.validate:est obligatoire poursshd_config,nginx.conf,sudoers: pas de validate = risque de lockout.- Au-delà de 5-10 lignes, passer à
template:plutôt quecontent:inline.
Pratiquer dans le lab
Section intitulée « Pratiquer dans le lab »Cette page a un lab d’accompagnement : labs/modules-fichiers/copy/ dans stephrobert/ansible-training.
git clone https://github.com/stephrobert/ansible-training.gitcd ansible-trainingcat labs/modules-fichiers/copy/README.mdcat labs/modules-fichiers/copy/challenge/README.mdChallenge — sur web1.lab :
- Copier
challenge/files/banner-ssh.txtvers/etc/ssh/banner-rhceavecmode: "0644",backup: true. - Écrire en inline (
content:) le fichier/etc/motd-rhce.
Validation pytest+testinfra :
ansible-playbook solution.ymlpytest -v labs/modules-fichiers/copy/challenge/tests/6 tests vérifient l’existence, le mode, le contenu et l’owner des deux fichiers.