10

What configuration is needed to correctly format the standard stream output from tasks in an Ansible ansible-playbook run?

What I run ansible-playbook foo.yaml the output from tasks includes the standard stream (stdout, stderr) content. But the display of these is in a big JSON single-line blob, and not printed as the formatted lines that were sent to the stream.

TASK [Django: Collect media fixture files] ******************************************************************************
ok: [lorem]

TASK [Django: Create superuser] ****************************************************************************** fatal: [lorem]: FAILED! => {"changed": false, "cmd": "python3 -m django createsuperuser\n --noinput\n --username "admin"\n --email "admin@example.com"", "msg": "\n:stderr: CommandError: You must use --full_name with --noinput.\n", "path": "/var/local/dolor/virtualenv/rectory/venv.py3.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/games", "syspath": ["/tmp/ansible_django_manage_payload_uj9f3le8/ansible_django_manage_payload.zip", "/usr/lib/python37.zip", "/usr/lib/python3.7", "/usr/lib/python3.7/lib-dynload", "/usr/local/lib/python3.7/dist-packages", "/usr/lib/python3/dist-packages"]}

What is causing this unwanted formatting of the output? How can I tell Ansible to always format the stream output correctly for display in the ansible-playbook output?

bignose
  • 1,132

3 Answers3

15

Ansible defaults to a machine-readable JSON output, not suitable for human reading. But there are other “callback” modules available, some of which can format the stream output.

  • The misleadingly-named debug module is more suitable for human viewing.
  • Recently, the yaml module formats the stream output as a easy-to-read YAML document.

So, using the ANSIBLE_STDOUT_CALLBACK environment variable:

$ ANSIBLE_STDOUT_CALLBACK=yaml ansible-playbook ansible/deploy.yaml

will change the formatting of stream output:

[…]
TASK [Django: Collect media fixture files] ******************************************************************************
ok: [lorem]

TASK [Django: Create superuser] ****************************************************************************** fatal: [lorem]: FAILED! => changed=false cmd: |- python3 -m django createsuperuser --noinput --username "admin" --email "admin@example.com msg: |- stderr: |- CommandError: You must use --full_name with --noinput. path: "/var/local/dolor/virtualenv/rectory/venv.py3.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/games" syspath: - /tmp/ansible_django_manage_payload_uj9f3le8/ansible_django_manage_payload.zip - /usr/lib/python37.zip - /usr/lib/python3.7 - /usr/lib/python3.7/lib-dynload - /usr/local/lib/python3.7/dist-packages - /usr/lib/python3/dist-packages

bignose
  • 1,132
2

1. Create config file

To get Ansible playbook output nicely formatted as pretty JSON, create a config file:

  • either ansible.cfg, in the same directory as the Ansible playbook file
  • or in the home directory, beginning with a dot, ~/.ansible.cfg
  • or in /etc/ansible/ansible.cfg

Source: https://docs.ansible.com/ansible/latest/reference_appendices/config.html

Bonus: debug also gives pretty stdout, stderr and msg.

File contents:

[defaults]
stdout_callback=debug

2. Run the playbook

Run the playbook in exactly the same way as before.

ansible-playbook foo.yaml

Comparison

Before:

TASK [Django: Collect media fixture files] ******************************************************************************
ok: [lorem]

TASK [Django: Create superuser] ****************************************************************************** fatal: [lorem]: FAILED! => {"changed": false, "cmd": "python3 -m django createsuperuser\n --noinput\n --username "admin"\n --email "admin@example.com"", "msg": "\n:stderr: CommandError: You must use --full_name with --noinput.\n", "path": "/var/local/dolor/virtualenv/rectory/venv.py3.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/games", "syspath": ["/tmp/ansible_django_manage_payload_uj9f3le8/ansible_django_manage_payload.zip", "/usr/lib/python37.zip", "/usr/lib/python3.7", "/usr/lib/python3.7/lib-dynload", "/usr/local/lib/python3.7/dist-packages", "/usr/lib/python3/dist-packages"]}

After:

TASK [Django: Collect media fixture files] ******************************************************************************
ok: [lorem]

TASK [Django: Create superuser] ****************************************************************************** fatal: [lorem]: FAILED! => { "changed": false, "cmd": "python3 -m django createsuperuser\n --noinput\n --username "admin"\n --email "admin@example.com"", "msg": "\n:stderr: CommandError: You must use --full_name with --noinput.\n", "path": "/var/local/dolor/virtualenv/rectory/venv.py3.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/games", "syspath": [ "/tmp/ansible_django_manage_payload_uj9f3le8/ansible_django_manage_payload.zip", "/usr/lib/python37.zip", "/usr/lib/python3.7", "/usr/lib/python3.7/lib-dynload", "/usr/local/lib/python3.7/dist-packages", "/usr/lib/python3/dist-packages" ] }

STDERR:

CommandError: You must use --full_name with --noinput.

MSG:

CommandError: You must use --full_name with --noinput.

0

Complementing the answers that suggest to use the community.general.yaml callback e. g. in ansible.cfg:

[defaults]
stdout_callback = yaml
stderr_callback = yaml

This will be deprecated soon[1]. Instead, you can use the ansible.builtin.default callback with result_format = yaml. Be aware, if you specify it via INI, the name will be callback_result_format, e. g.:

[defaults]
callback_result_format = yaml

[1] DEPRECATED Removed in: version 13.0.0. Why: Starting in ansible-core 2.13, the ansible.builtin.default callback has support for printing output in YAML format. Alternative: Use result_format=yaml.