Aller au contenu
Infrastructure as Code medium

Débogueur Ansible interactif : debugger: on_failed et REPL au runtime

9 min de lecture

Logo Ansible

Quand une tâche échoue dans un playbook de 100 lignes, relancer tout est lent et frustrant. Ansible fournit un débogueur interactif qui ouvre un REPL Python au moment de l’échec : on inspecte les variables (p task_vars['x']), on modifie les arguments à chaud (task.args['name'] = 'nginx'), on rejoue la tâche modifiée (redo), on continue le playbook (continue). Activable au niveau task ou play avec debugger: on_failed.

Cette page détaille les 6 commandes du REPL, le workflow recommandé pour fixer une variable au runtime, et les 2 cas où ne pas activer le débogueur (CI/CD, AWX/AAP, cron).

  • Activer debugger: on_failed au niveau task ou play.
  • Inspecter variables, arguments, résultat avec p.
  • Modifier les args (task.args['x'] = 'y') et rejouer avec redo.
  • Injecter une variable manquante via task_vars.
  • Quitter proprement (continue, quit).
  • Quand NE PAS utiliser le débogueur (interactif requis).

Trois niveaux d’activation, du plus fin au plus large.

tasks:
- name: Tâche fragile
ansible.builtin.dnf:
name: nginx
state: present
debugger: on_failed # ← s'active uniquement sur cette tâche
- hosts: webservers
debugger: on_failed # ← s'active sur toutes les tasks de ce play
tasks:
- ...
Fenêtre de terminal
ANSIBLE_ENABLE_TASK_DEBUGGER=True ansible-playbook lab.yml

Granularité : task > play > global. La task gagne en cas de conflit.

ValeurEffet
alwaysOuvre le REPL après chaque tâche (TDD, très lent)
neverDésactive (default sauf si globalement activé)
on_failedRecommandé — REPL uniquement en cas d’échec
on_unreachableREPL uniquement si l’host devient unreachable
on_skippedREPL si la tâche est skippée (rare)

Quand une tâche échoue, vous voyez :

TASK [Installer nginx-impossible] ***
fatal: [db1.lab]: FAILED! => {"msg": "...nginx-impossible..."}
[db1.lab] TASK: Installer nginx-impossible (debug)>

Le prompt (debug)> indique que vous êtes dans le REPL. Tapez help pour la liste.

CommandeEffet
p <expr>Print Python — ex p task, p task.args, p task_vars['x'], p result._result
task.args['x'] = 'y'Modifie un argument de la tâche en mémoire
task_vars['x'] = 'y'Injecte une variable dans le scope de la tâche
update_task (u)Recrée la tâche avec les nouvelles variables/args
redo (r)Rejoue la tâche modifiée
continue (c) / quit (q)Continuer / abandonner le playbook

Workflow type — fix d’un mauvais nom de paquet

Section intitulée « Workflow type — fix d’un mauvais nom de paquet »
  1. La tâche échoue :

    fatal: [db1.lab]: FAILED! => {"msg": "Failed to install: nginx-impossible..."}
    [db1.lab] TASK: Installer nginx-impossible (debug)>
  2. Inspecter ce qui a été passé :

    (debug)> p task.args
    {'name': 'nginx-impossible', 'state': 'present'}
  3. Modifier l’argument :

    (debug)> task.args['name'] = 'nginx'
  4. Rejouer :

    (debug)> redo
    changed: [db1.lab]
  5. Continuer :

    (debug)> continue
    TASK [Tâche suivante] ***
    ...

🔍 Observation : on a fixé un bug sans modifier le YAML ni relancer le playbook. Sur une fleet de 50 hôtes où une seule tâche plante, c’est inestimable.

- ansible.builtin.copy:
dest: "{{ target_dir }}/file.txt"
content: "Hello"
mode: "0644"

Si target_dir n’est pas défini :

fatal: [db1.lab]: FAILED! => {"msg": "...'target_dir' is undefined..."}
[db1.lab] TASK: copy (debug)>

Au REPL :

(debug)> p task_vars.get('target_dir', 'undefined')
'undefined'
(debug)> task_vars['target_dir'] = '/tmp'
(debug)> update_task
(debug)> redo
changed: [db1.lab]

🔍 Observation : task_vars['x'] = 'y' injecte la variable, update_task (raccourci u) recrée la tâche avec le nouveau scope, puis redo rejoue. Workflow puissant pour résoudre les undefined variable.

- hosts: webservers
strategy: free # ← DANGER avec le débogueur
debugger: on_failed

Avec strategy: free, pendant que vous êtes au prompt (debug)> sur web1.lab, les tâches de web2.lab continuent à tourner. Race conditions garanties.

Toujours garder strategy: linear (default) en debug pour avoir une pause synchrone sur tous les hosts.

Le débogueur est interactif. À ne jamais activer dans :

  • CI/CD (GitHub Actions, GitLab CI) : pas de stdin → le pipeline freeze indéfiniment.
  • AWX / AAP : les jobs n’ont pas de prompt utilisateur.
  • Cron / systemd timers : pareil.
  • Production : laisser debugger: on_failed dans un playbook commit en prod = bombe à retardement.

Pour ces contextes, préférer :

  • -vvv + logs détaillés (page Verbosité).
  • ANSIBLE_KEEP_REMOTE_FILES=1 + inspection forensic.
  • ansible-navigator replay <artifact.json> (page EE) pour rejouer un échec sans relancer.

Le lab troubleshooting/debugger (labs/troubleshooting/debugger/) couvre les 6 exercices : activer debugger: on_failed, inspecter les vars, modifier les args, injecter une variable, comprendre strategy: linear vs free. Challenge final : fix d’un target_dir manquant au runtime.

  • debugger: on_failed au niveau task ou play, pas en production.
  • p print accepte n’importe quelle expression Python (vars, args, result).
  • task.args['x'] = ... + redo modifie un argument et rejoue.
  • task_vars['x'] = ... + update_task + redo injecte une variable manquante.
  • strategy: linear mandatory en debug (race conditions avec free).
  • Jamais de débogueur en CI, AAP, cron, ou prod (interactivité requise).

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn