ANSIBLE CHEAT SHEET

Référence complète • Automation & Configuration Management

🔍

📦 Installation & Setup

Installation
# Via pip (recommandé) pip install ansible # Via pipx (isolé) pipx install ansible # RHEL / Fedora sudo dnf install ansible-core # Debian / Ubuntu sudo apt install ansible # Vérifier la version ansible --version ansible-community --version
ansible.cfg Config
Ordre de lecture : ANSIBLE_CONFIG (env) → ./ansible.cfg → ~/.ansible.cfg → /etc/ansible/ansible.cfg
[defaults] inventory = ./inventory remote_user = ansible host_key_checking = False forks = 20 timeout = 30 log_path = /var/log/ansible.log roles_path = ./roles collections_path = ./collections retry_files_enabled = False [privilege_escalation] become = True become_method = sudo become_user = root become_ask_pass = False [ssh_connection] pipelining = True ssh_args = -o ControlMaster=auto -o ControlPersist=60s
💡 pipelining = True réduit le nombre de connexions SSH et accélère significativement l'exécution.
Préparer les hôtes SSH
# Générer une clé SSH ssh-keygen -t ed25519 -C "ansible" # Distribuer la clé sur tous les hôtes ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host # Tester la connectivité ansible all -m ping # Tester avec mot de passe ansible all -m ping --ask-pass -u admin

📂 Inventaire

Format INI (statique)
# inventory/hosts.ini [webservers] web01 ansible_host=192.168.1.10 web02 ansible_host=192.168.1.11 [dbservers] db01 ansible_host=192.168.1.20 ansible_port=2222 [production:children] webservers dbservers [production:vars] ansible_user=deploy ansible_become=true ntp_server=time.example.com
Format YAML
# inventory/hosts.yml all: children: webservers: hosts: web01: ansible_host: 192.168.1.10 web02: ansible_host: 192.168.1.11 vars: http_port: 80 dbservers: hosts: db01: ansible_host: 192.168.1.20 production: children: webservers: dbservers:
Commandes inventaire
# Lister tous les hôtes ansible-inventory --list -y # Graphe des groupes ansible-inventory --graph # Info sur un hôte spécifique ansible-inventory --host web01 # Inventaire multiple ansible-playbook -i inv/staging -i inv/prod site.yml # Patterns de sélection ansible 'webservers' -m ping ansible 'webservers:&production' -m ping # intersection ansible 'webservers:!web01' -m ping # exclusion ansible 'web*' -m ping # wildcard ansible 'all' -m ping # tout
Variables spéciales d'inventaire
ansible_host # IP ou hostname ansible_port # Port SSH (défaut: 22) ansible_user # Utilisateur SSH ansible_password # Mot de passe SSH ansible_ssh_private_key_file # Clé privée ansible_become # Activer privilege escalation ansible_become_method # sudo, su, doas... ansible_become_user # Utilisateur cible (root) ansible_become_password # Mot de passe sudo ansible_connection # ssh, local, winrm... ansible_python_interpreter # /usr/bin/python3

Commandes Ad-Hoc

Syntaxe de base
# Syntaxe générale ansible <pattern> -m <module> -a "<arguments>" [options] # Ping tous les hôtes ansible all -m ping # Exécuter une commande ansible webservers -m command -a "uptime" # Shell (pipes, redirections) ansible all -m shell -a "df -h | grep /dev/sda" # Copier un fichier ansible all -m copy -a "src=./file dest=/tmp/file mode=0644" # Installer un paquet ansible all -m dnf -a "name=httpd state=present" -b # Démarrer un service ansible all -m service -a "name=httpd state=started enabled=yes" -b # Créer un utilisateur ansible all -m user -a "name=deploy state=present" -b # Collecter les facts ansible web01 -m setup ansible web01 -m setup -a "filter=ansible_os_family"
Options courantes
-i inventory # Fichier d'inventaire -m module # Module à utiliser -a "args" # Arguments du module -b / --become # Escalade de privilèges -K / --ask-become-pass # Demander sudo pass -k / --ask-pass # Demander SSH pass -u user # Utilisateur SSH -f 20 # Nombre de forks (parallélisme) -v / -vv / -vvv # Verbosité -C / --check # Dry run (ne change rien) -D / --diff # Afficher les diffs --limit web01 # Limiter à un hôte --list-hosts # Lister les hôtes ciblés

📜 Playbooks

Structure d'un playbook
# site.yml --- - name: Configurer les serveurs web hosts: webservers become: true gather_facts: true vars: http_port: 80 doc_root: /var/www/html pre_tasks: - name: Mettre à jour le cache dnf: update_cache: true tasks: - name: Installer Apache dnf: name: httpd state: present - name: Déployer la config template: src: httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf notify: Restart Apache - name: Démarrer Apache service: name: httpd state: started enabled: true handlers: - name: Restart Apache service: name: httpd state: restarted post_tasks: - name: Vérifier le service uri: url: "http://localhost:{{ http_port }}" status_code: 200
Exécuter un playbook
# Exécution standard ansible-playbook site.yml # Avec inventaire spécifique ansible-playbook -i inventory/prod site.yml # Dry run (check mode) ansible-playbook site.yml --check --diff # Vérifier la syntaxe ansible-playbook site.yml --syntax-check # Lister les tâches ansible-playbook site.yml --list-tasks # Lister les hôtes ciblés ansible-playbook site.yml --list-hosts # Verbose / debug ansible-playbook site.yml -vvv # Passer des variables extra ansible-playbook site.yml -e "env=prod version=2.1" # Limiter à certains hôtes ansible-playbook site.yml --limit web01 # Démarrer à une tâche spécifique ansible-playbook site.yml --start-at-task "Déployer la config" # Step by step (confirmation par tâche) ansible-playbook site.yml --step
Import / Include
# import_tasks = statique (résolu à la lecture) tasks: - import_tasks: tasks/install.yml - import_tasks: tasks/config.yml # include_tasks = dynamique (résolu à l'exécution) tasks: - include_tasks: "tasks/{{ ansible_os_family }}.yml" # import_playbook (dans un playbook maître) --- - import_playbook: webservers.yml - import_playbook: dbservers.yml # include_role / import_role tasks: - include_role: name: nginx when: use_nginx | bool
⚠️ import_* = statique → tags/when appliqués à chaque tâche. include_* = dynamique → tags/when appliqués au include lui-même.
Register & Return Values
- name: Vérifier l'espace disque command: df -h / register: disk_result - name: Afficher le résultat debug: msg: "{{ disk_result.stdout }}" # Propriétés utiles de register: # .stdout → sortie standard # .stderr → sortie d'erreur # .rc → code retour # .changed → true si changement # .failed → true si échec # .stdout_lines → stdout en liste

🔤 Variables

Ordre de précédence Important
Du plus faible au plus fort (22 niveaux). Les plus courants :
1. role defaults (roles/x/defaults/main.yml) 2. inventory group_vars (group_vars/all) 3. inventory group_vars (group_vars/groupname) 4. inventory host_vars (host_vars/hostname) 5. play vars (vars: dans le play) 6. play vars_files (vars_files:) 7. play vars_prompt (vars_prompt:) 8. task vars (vars: dans une task) 9. set_fact / register 10. role vars (roles/x/vars/main.yml) 11. block vars 12. include_vars 13. extra vars (-e) ← TOUJOURS GAGNE
💡 Règle d'or : -e (extra vars) écrase TOUT. Les role defaults sont toujours les plus faibles (fait exprès pour être overridés).
Définir des variables
# Dans le playbook - hosts: all vars: http_port: 80 packages: - httpd - mod_ssl # Fichiers de variables vars_files: - vars/common.yml - "vars/{{ env }}.yml" # group_vars / host_vars (fichiers) # group_vars/webservers.yml http_port: 80 max_clients: 200 # host_vars/web01.yml http_port: 8080 # Variable dans une tâche - name: Installer des paquets dnf: name: "{{ packages }}" state: present vars: packages: - nginx - php
vars_prompt (interactif)
- hosts: all vars_prompt: - name: username prompt: "Nom d'utilisateur ?" private: false - name: password prompt: "Mot de passe ?" private: true encrypt: sha512_crypt confirm: true
set_fact (variables dynamiques)
- name: Définir un fact custom set_fact: full_url: "https://{{ domain }}:{{ port }}" is_production: "{{ env == 'prod' }}" # Cacheable (persistant entre plays) - set_fact: my_var: "value" cacheable: true

🧬 Templates Jinja2

Syntaxe Jinja2
{# Commentaire #} {{ variable }} # Afficher une valeur {% instruction %} # Logique (if, for...) # Condition {% if http_port == 80 %} Listen 80 {% elif http_port == 443 %} Listen 443 {% else %} Listen {{ http_port }} {% endif %} # Boucle {% for vhost in vhosts %} <VirtualHost *:{{ vhost.port }}> ServerName {{ vhost.name }} DocumentRoot {{ vhost.docroot }} </VirtualHost> {% endfor %}
Filtres courants
# Valeur par défaut {{ var | default('fallback') }} {{ var | default(omit) }} # omet le paramètre # Manipulation de chaînes {{ name | upper }} {{ name | lower }} {{ name | capitalize }} {{ name | replace('old', 'new') }} {{ path | basename }} {{ path | dirname }} {{ list | join(', ') }} # Type casting {{ value | int }} {{ value | float }} {{ value | bool }} {{ value | string }} # Listes & dicts {{ list | length }} {{ list | first }} {{ list | last }} {{ list | unique }} {{ list | sort }} {{ list | flatten }} {{ list | select('match', '^web') | list }} {{ dict | dict2items }} {{ items | items2dict }} # Hachage & encodage {{ password | password_hash('sha512') }} {{ data | to_json }} {{ data | to_yaml }} {{ data | to_nice_json }} {{ data | b64encode }} {{ data | b64decode }} # Réseau {{ ip | ansible.utils.ipaddr }} {{ '192.168.1.0/24' | ansible.utils.ipsubnet }}
Tests Jinja2
# Tests booléens (utilisés avec `is`) {{ var is defined }} {{ var is undefined }} {{ var is none }} {{ list is iterable }} {{ num is number }} {{ value is string }} {{ path is file }} {{ path is directory }} {{ str is match('regex') }} # début {{ str is search('regex') }} # n'importe où {{ result is changed }} {{ result is succeeded }} {{ result is failed }} {{ result is skipped }} # Utilisation dans when: when: my_var is defined when: result is changed when: inventory_hostname is match('web.*')
Module template
- name: Déployer la configuration template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf owner: root group: root mode: '0644' backup: true validate: "nginx -t -c %s" notify: Reload Nginx
💡 validate permet de tester la config avant de l'appliquer. %s = path du fichier temporaire.

🔀 Conditions & Boucles

when (conditions)
# Condition simple - dnf: name=httpd state=present when: ansible_os_family == "RedHat" # Conditions multiples (AND) when: - ansible_os_family == "RedHat" - ansible_distribution_major_version | int >= 8 # OR when: ansible_os_family == "RedHat" or ansible_os_family == "Suse" # Variable définie / non vide when: my_var is defined when: my_var | length > 0 # Basé sur un register when: result.rc == 0 when: result is changed when: result is failed # Booléen when: enable_ssl | bool when: not skip_install
⚠️ when: utilise du Jinja2 brut → PAS de {{ }} autour des expressions !
loop / with_items
# loop (recommandé) - name: Installer des paquets dnf: name: "{{ item }}" state: present loop: - httpd - mod_ssl - php # loop avec dict - name: Créer des utilisateurs user: name: "{{ item.name }}" groups: "{{ item.groups }}" state: present loop: - { name: alice, groups: wheel } - { name: bob, groups: developers } # loop avec index loop: "{{ packages }}" loop_control: index_var: idx label: "{{ item.name }}" # output propre pause: 3 # pause entre itérations # with_dict - debug: msg: "{{ item.key }} = {{ item.value }}" with_dict: "{{ my_dict }}" # with_fileglob - copy: src: "{{ item }}" dest: /etc/conf.d/ with_fileglob: - "files/*.conf"

🔔 Handlers

Handlers & Notify
tasks: - name: Déployer la config nginx template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: - Reload Nginx - Check Config handlers: - name: Check Config command: nginx -t listen: "restart web" - name: Reload Nginx service: name: nginx state: reloaded listen: "restart web"
💡 Les handlers ne s'exécutent qu'une seule fois à la fin du play, même s'ils sont notifiés plusieurs fois. Utiliser listen: pour grouper des handlers.
Forcer l'exécution
# Exécuter les handlers immédiatement tasks: - name: Config mise à jour template: ... notify: Restart Service - name: Forcer les handlers maintenant meta: flush_handlers - name: Suite des tâches... debug: msg: "Le service est déjà redémarré ici"

🎭 Rôles

Structure d'un rôle
# Créer un rôle ansible-galaxy role init mon_role # Arborescence roles/mon_role/ ├── defaults/ │ └── main.yml # Variables par défaut (précédence faible) ├── files/ │ └── app.conf # Fichiers statiques ├── handlers/ │ └── main.yml # Handlers ├── meta/ │ └── main.yml # Dépendances, metadata ├── tasks/ │ └── main.yml # Tâches principales ├── templates/ │ └── app.conf.j2 # Templates Jinja2 ├── tests/ │ └── test.yml # Tests du rôle └── vars/ └── main.yml # Variables (précédence forte)
💡 defaults/ = variables overridables facilement. vars/ = variables "internes" au rôle, rarement overridées.
Utiliser un rôle
# Dans un playbook - méthode classique - hosts: webservers roles: - common - { role: nginx, http_port: 8080 } - role: postgres vars: pg_version: 16 tags: database # Include dynamique dans tasks tasks: - include_role: name: nginx when: install_nginx | bool - import_role: name: common tasks_from: users.yml # fichier spécifique
Dépendances de rôles
# roles/webapp/meta/main.yml --- dependencies: - role: common - role: nginx vars: nginx_port: 80 - role: php when: enable_php | bool galaxy_info: author: joris description: Webapp deployment role min_ansible_version: "2.15" platforms: - name: EL versions: [8, 9]

🧩 Modules essentiels

Fichiers & Répertoires
# Créer un répertoire - file: path: /opt/myapp state: directory owner: app group: app mode: '0755' # Créer un lien symbolique - file: src: /opt/myapp/current dest: /var/www/app state: link # Supprimer un fichier - file: path: /tmp/old_file state: absent # Copier depuis le contrôleur - copy: src: files/app.conf dest: /etc/app/app.conf owner: root mode: '0644' backup: true # Modifier une ligne dans un fichier - lineinfile: path: /etc/ssh/sshd_config regexp: '^#?PermitRootLogin' line: 'PermitRootLogin no' backup: true # Insérer un bloc - blockinfile: path: /etc/hosts block: | 192.168.1.10 web01 192.168.1.11 web02 marker: "# {mark} ANSIBLE MANAGED"
Paquets & Services
# Installer (RHEL/Fedora) - dnf: name: - httpd - mod_ssl - php state: present # Installer (Debian/Ubuntu) - apt: name: nginx state: present update_cache: true cache_valid_time: 3600 # Module générique - package: name: git state: present # Gérer un service - systemd: name: httpd state: started enabled: true daemon_reload: true # Firewall (firewalld) - firewalld: service: http permanent: true immediate: true state: enabled # Firewall (port) - firewalld: port: 8080/tcp permanent: true immediate: true state: enabled
Utilisateurs & Groupes
# Créer un utilisateur - user: name: deploy groups: wheel append: true shell: /bin/bash password: "{{ 'secret' | password_hash('sha512') }}" generate_ssh_key: true ssh_key_bits: 4096 # Créer un groupe - group: name: developers gid: 1500 state: present # Distribuer une clé SSH - authorized_key: user: deploy key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}" state: present # Supprimer un utilisateur - user: name: old_user state: absent remove: true
Autres modules utiles
# Cron job - cron: name: "Backup quotidien" minute: "0" hour: "2" job: "/opt/scripts/backup.sh" # Télécharger un fichier - get_url: url: https://example.com/app.tar.gz dest: /tmp/app.tar.gz checksum: sha256:abc123... # Extraire une archive - unarchive: src: /tmp/app.tar.gz dest: /opt/app/ remote_src: true # Requête HTTP - uri: url: "http://localhost/api/health" method: GET status_code: 200 register: health_check # Attendre qu'un port soit ouvert - wait_for: host: "{{ inventory_hostname }}" port: 8080 delay: 5 timeout: 60 # SELinux - seboolean: name: httpd_can_network_connect state: true persistent: true # SELinux file context - sefcontext: target: '/opt/myapp(/.*)?' setype: httpd_sys_content_t state: present - command: restorecon -Rv /opt/myapp

🔐 Ansible Vault

Commandes Vault
# Créer un fichier chiffré ansible-vault create secrets.yml # Chiffrer un fichier existant ansible-vault encrypt vars/passwords.yml # Déchiffrer ansible-vault decrypt vars/passwords.yml # Éditer un fichier chiffré ansible-vault edit secrets.yml # Voir le contenu sans déchiffrer ansible-vault view secrets.yml # Changer le mot de passe ansible-vault rekey secrets.yml # Chiffrer une seule variable (inline) ansible-vault encrypt_string 'SuperSecret!' \ --name 'db_password' # Utiliser avec playbook ansible-playbook site.yml --ask-vault-pass ansible-playbook site.yml --vault-password-file ~/.vault_pass # Plusieurs vault IDs ansible-playbook site.yml \ --vault-id dev@prompt \ --vault-id prod@~/.vault_prod
Variables chiffrées inline
# vars/main.yml avec variable vault inline --- db_user: myapp db_password: !vault | $ANSIBLE_VAULT;1.1;AES256 62313365396662343061393464336163... 3233343663383463633231356131643... # Bonne pratique : séparer clair/chiffré # vars/main.yml db_password: "{{ vault_db_password }}" # vars/vault.yml (chiffré) vault_db_password: "SuperSecret!"
💡 Convention : préfixer les variables vault avec vault_ et les référencer dans le fichier en clair via {{ vault_xxx }}.

🌌 Ansible Galaxy

Commandes Galaxy
# Installer un rôle ansible-galaxy role install geerlingguy.docker # Installer une collection ansible-galaxy collection install community.general # Installer depuis un fichier requirements ansible-galaxy install -r requirements.yml # Lister les rôles installés ansible-galaxy role list # Lister les collections installées ansible-galaxy collection list # Supprimer un rôle ansible-galaxy role remove geerlingguy.docker # Créer un rôle ansible-galaxy role init mon_role # Créer une collection ansible-galaxy collection init myns.mycollection
requirements.yml
# requirements.yml --- roles: - name: geerlingguy.docker version: "6.1.0" - name: geerlingguy.nginx - src: https://gitlab.com/team/role.git scm: git version: main name: custom_role collections: - name: community.general version: ">=7.0.0" - name: ansible.posix - name: community.crypto

📊 Facts

Facts système
# Collecter tous les facts ansible web01 -m setup # Filtrer ansible web01 -m setup -a "filter=ansible_distribution*" # Facts courants {{ ansible_hostname }} # web01 {{ ansible_fqdn }} # web01.example.com {{ ansible_distribution }} # RedHat, Ubuntu... {{ ansible_distribution_version }} # 9.3 {{ ansible_os_family }} # RedHat, Debian... {{ ansible_kernel }} # 5.14.0-362.el9 {{ ansible_architecture }} # x86_64 {{ ansible_memtotal_mb }} # 8192 {{ ansible_processor_vcpus }} # 4 {{ ansible_default_ipv4.address }} # 192.168.1.10 {{ ansible_default_ipv4.interface }} # eth0 {{ ansible_devices }} # disques {{ ansible_mounts }} # points de montage {{ ansible_env.HOME }} # /root
Facts custom (local facts)
# Déployer un fact local sur l'hôte # /etc/ansible/facts.d/app.fact [general] app_name = myapp app_version = 2.1.0 environment = production # Accessible via : {{ ansible_local.app.general.app_name }} # Ou en JSON : # /etc/ansible/facts.d/app.fact { "app_name": "myapp", "version": "2.1.0" } # Désactiver la collecte de facts - hosts: all gather_facts: false

🏷️ Tags & Limites

Tags
# Taguer des tâches tasks: - name: Installer Apache dnf: name=httpd state=present tags: - install - apache - name: Configurer Apache template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf tags: [config, apache] # Tags spéciaux tags: always # toujours exécuté tags: never # jamais (sauf si --tags never) # Exécuter seulement certains tags ansible-playbook site.yml --tags "install,config" # Exclure des tags ansible-playbook site.yml --skip-tags "debug" # Lister tous les tags ansible-playbook site.yml --list-tags
Limites & Stratégies
# Limiter l'exécution ansible-playbook site.yml --limit web01 ansible-playbook site.yml --limit 'webservers:!web03' # Rolling update (serial) - hosts: webservers serial: 2 # 2 hôtes à la fois serial: "30%" # ou en pourcentage serial: - 1 # d'abord 1 (canary) - 5 # puis 5 - "100%" # puis le reste # max_fail_percentage max_fail_percentage: 25 # abort si >25% échouent # Stratégies strategy: linear # défaut : tâche par tâche strategy: free # chaque hôte avance seul # Throttle (limiter le parallélisme par tâche) - name: Restart service service: name=httpd state=restarted throttle: 1 # un par un

🛡️ Blocks & Gestion d'erreurs

block / rescue / always
- name: Déploiement avec rollback block: - name: Déployer la nouvelle version copy: src: app-v2.tar.gz dest: /opt/app/ - name: Redémarrer l'app systemd: name: myapp state: restarted - name: Vérifier le health check uri: url: http://localhost:8080/health status_code: 200 rescue: - name: Rollback - restaurer l'ancienne version copy: src: /opt/app/backup/ dest: /opt/app/current/ - name: Redémarrer avec l'ancien code systemd: name: myapp state: restarted always: - name: Envoyer une notification debug: msg: "Déploiement terminé (succès ou rollback)"
Contrôle d'erreurs
# Ignorer les erreurs - command: /opt/app/check.sh ignore_errors: true # Personnaliser ce qui est un "échec" - command: /opt/app/deploy.sh register: result failed_when: - result.rc != 0 - "'ALREADY_DEPLOYED' not in result.stdout" # Personnaliser ce qui est un "changement" - command: /opt/app/status.sh register: status changed_when: "'modified' in status.stdout" # Jamais "changed" - command: cat /etc/hostname changed_when: false # any_errors_fatal - hosts: all any_errors_fatal: true # → arrêt complet si un hôte échoue

📚 Collections

Utiliser des collections
# FQCN (Fully Qualified Collection Name) - ansible.builtin.copy: src: file.txt dest: /tmp/file.txt - community.general.ufw: rule: allow port: '22' - ansible.posix.seboolean: name: httpd_can_network_connect state: true # Déclarer les collections utilisées - hosts: all collections: - community.general - ansible.posix tasks: - seboolean: # pas besoin du FQCN name: httpd_can_network_connect state: true
Collections courantes
ansible.builtin # Modules de base (inclus) → copy, file, template, service, dnf, apt, user, group, command, shell, debug, etc. ansible.posix # SELinux, mount, sysctl, at community.general # ufw, nmcli, parted, lvm, etc. community.crypto # Certificats, openssl community.mysql # MySQL/MariaDB community.postgresql # PostgreSQL community.docker # Docker containers, images community.vmware # VMware vSphere ansible.netcommon # Réseau (base) ansible.utils # Filtres IP, validation amazon.aws # AWS azure.azcollection # Azure google.cloud # GCP

⚙️ Configuration

Variables d'environnement
# Override complet du fichier de config ANSIBLE_CONFIG=/path/to/ansible.cfg # Quelques variables utiles ANSIBLE_INVENTORY=/path/to/hosts ANSIBLE_REMOTE_USER=deploy ANSIBLE_BECOME=True ANSIBLE_BECOME_METHOD=sudo ANSIBLE_HOST_KEY_CHECKING=False ANSIBLE_FORKS=20 ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass ANSIBLE_LOG_PATH=/var/log/ansible.log ANSIBLE_NOCOWS=1 # 🐄 désactiver cowsay ANSIBLE_STDOUT_CALLBACK=yaml # Voir la config actuelle ansible-config dump ansible-config dump --only-changed ansible-config list
Callback plugins (output)
# ansible.cfg [defaults] stdout_callback = yaml # output lisible # Autres options : # stdout_callback = json # output JSON # stdout_callback = debug # très détaillé # stdout_callback = dense # compact # stdout_callback = minimal # ultra-compact # Activer le profiling callbacks_enabled = timer, profile_tasks, profile_roles

🔧 Debug & Troubleshoot

Module debug & assert
# Afficher un message - debug: msg: "Le port HTTP est {{ http_port }}" # Afficher une variable - debug: var: ansible_facts['os_family'] # Afficher avec verbosité minimum - debug: msg: "Info détaillée..." verbosity: 2 # affiché seulement avec -vv+ # Assert (validation) - assert: that: - http_port is defined - http_port | int > 0 - http_port | int < 65536 fail_msg: "Port invalide : {{ http_port }}" success_msg: "Port OK : {{ http_port }}" # Fail volontaire - fail: msg: "Ce playbook nécessite RHEL 9+" when: ansible_distribution_major_version | int < 9
Troubleshooting
# Tester la connectivité ansible all -m ping -vvv # Vérifier l'inventaire ansible-inventory --list -y ansible-inventory --graph # Vérifier la syntaxe ansible-playbook site.yml --syntax-check # Linter (ansible-lint) pip install ansible-lint ansible-lint site.yml # Dry run complet ansible-playbook site.yml --check --diff -v # Debugger interactif tasks: - name: Task problématique command: /bin/false debugger: on_failed # Activer le debugger globalement # ANSIBLE_ENABLE_TASK_DEBUGGER=True # Commandes dans le debugger : # p task → afficher la tâche # p result → afficher le résultat # p vars → afficher les variables # r → relancer la tâche # c → continuer # q → quitter
Lookups
# Lire un fichier local {{ lookup('file', '/etc/hostname') }} # Variable d'environnement {{ lookup('env', 'HOME') }} # Commande locale {{ lookup('pipe', 'date +%Y%m%d') }} # Générer un mot de passe {{ lookup('password', '/dev/null length=20 chars=ascii_letters,digits') }} # Lire depuis un fichier CSV {{ lookup('csvfile', 'web01 file=hosts.csv delimiter=, col=1') }} # Template inline {{ lookup('template', 'mytemplate.j2') }} # URL {{ lookup('url', 'https://api.example.com/config') }} # Fichiers dans un répertoire {{ lookup('fileglob', 'files/*.conf') }}
Tâches asynchrones
# Lancer en async (timeout 300s, poll toutes les 5s) - name: Mise à jour longue dnf: name: '*' state: latest async: 300 poll: 5 # Fire and forget (poll: 0) - name: Script en arrière-plan command: /opt/long_script.sh async: 600 poll: 0 register: async_result # Vérifier plus tard - name: Vérifier le résultat async_status: jid: "{{ async_result.ansible_job_id }}" register: job_result until: job_result.finished retries: 30 delay: 10