Référence complète • Automation & Configuration Management
# 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[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# 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# 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# 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:# 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 # toutansible_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# 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"-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# 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é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_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- 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 liste1. 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# 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- 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- 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{# 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 %}# 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 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.*')- 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# 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{{ }} autour des expressions !# 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"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"# 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"# 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)# 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# 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]# 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"# 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# 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# 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# 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# 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!"# 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
---
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# 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# 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# 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# 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- 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)"# 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# 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: trueansible.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# 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# 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# 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# 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# 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') }}# 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