When working with Ansible's with_items
loop to secure multiple SSL keys, we often face an output pollution problem. The default behavior prints the entire file attributes dictionary for each item, making logs unnecessarily verbose and hard to read.
The standard output includes all file metadata (permissions, timestamps, ownership) when we only care about the file path being processed. Here's what you typically see:
ok: [127.0.0.1] => (item={u'uid': 0, u'woth': False, u'mtime': 1454939377.264, ... u'path': u'/etc/ssl/foo.key' ... })
1. Using Custom Callback Plugins
Create callback_plugins/minimal.py
:
from ansible.plugins.callback.default import CallbackModule
class CallbackModule(CallbackModule):
def v2_runner_item_on_ok(self, result):
path = result._result.get('item', {}).get('path', '')
if path:
self._display.display(f"Processing SSL key: {path}", color='green')
Then in ansible.cfg
:
[defaults]
callback_plugins = ./callback_plugins
stdout_callback = minimal
2. Filtering with Jinja2
Modify your playbook to use a custom msg:
- name: Secure ssl keys
file: path={{ item.path }} user=root group=root mode=600
with_items: secure_ssl_keys_result.files
loop_control:
label: "{{ item.path }}"
3. Using debug with Conditional Display
- name: Debug path only
debug:
msg: "Securing {{ item.path }}"
with_items: secure_ssl_keys_result.files
when: secure_ssl_keys_result.files | length > 0
- name: Actual file task with silent output
file: path={{ item.path }} user=root group=root mode=600
with_items: secure_ssl_keys_result.files
no_log: true
When dealing with hundreds of SSL keys, the first solution (custom callback) is most efficient as it:
- Reduces memory usage by avoiding duplicate debug tasks
- Maintains clean output without affecting execution flow
- Preserves all actual error messages
For more control, you can modify verbosity based on inventory groups:
- name: Secure ssl keys
file: path={{ item.path }} user=root group=root mode=600
with_items: secure_ssl_keys_result.files
vars:
ansible_display_args_to_stdout: "{{ 'all' if verbose_mode else 'path' }}"
When working with Ansible's with_items
loop, the default output behavior can be overwhelming, especially when processing multiple files with the find
module. The full dictionary output for each item includes numerous file attributes that often aren't relevant during playbook execution.
- name: Find SSL certificates
find:
paths: "/etc/ssl/"
patterns: "*.key"
recurse: yes
register: ssl_certs
- name: Secure permissions
file:
path: "{{ item.path }}"
owner: root
group: root
mode: "0600"
with_items: "{{ ssl_certs.files }}"
Method 1: Using debug with loop_control
The most elegant solution is to combine a debug task with loop_control
and label
parameter:
- name: Secure SSL keys (clean output)
file:
path: "{{ item.path }}"
owner: root
group: root
mode: "0600"
with_items: "{{ secure_ssl_keys_result.files }}"
loop_control:
label: "{{ item.path }}"
Method 2: Custom msg with debug
For more control over the output format, use a debug task before your main operation:
- name: Display processing path
debug:
msg: "Securing {{ item.path }}"
with_items: "{{ secure_ssl_keys_result.files }}"
changed_when: false
- name: Actual file modification (silent)
file:
path: "{{ item.path }}"
owner: root
group: root
mode: "0600"
with_items: "{{ secure_ssl_keys_result.files }}"
no_log: true
Using callback plugins
For permanent solution across all playbooks, configure a custom callback plugin in ansible.cfg
:
[defaults]
stdout_callback = actionable
bin_ansible_callbacks = True
Filtering with json_query
When you need to pre-process complex item structures:
- name: Process filtered items
debug:
msg: "{{ item }}"
with_items: "{{ secure_ssl_keys_result.files | json_query('[].path') }}"
While these methods improve readability, be aware of:
- Additional tasks may slightly impact playbook execution time
- Debug tasks still consume memory for output buffering
- Complex Jinja2 filters in
loop_control
might slow down processing