Score:1

How can I shorten 'item' value in Ansible console output?

in flag

I'm struggling with the title for this question, so feel free to edit it to make it more meaningful.

Let's say you have a task in Ansible and you register the output. For example:

- name: Set up working directory
  shell: mktemp -d
  register: workdir

And I want to use the registered output to do another task. For example:

- name: Create a file
  with_items: "{{ workdir.stdout }}"
  shell: touch {{ item }}/test-file

That all works great. Now, I want to loop both tasks N times. (I know I could extract this into a separate yaml file, and use include_tasks combined with loop, but I don't want to have two playbooks.) Thus, I update to:

- name: Set up working directory
  shell: mktemp -d
  register: workdir
  loop:
  - 1
  - 2

As a result of the loop, the workdir variable has taken a different structure, so iterating through it is now slightly different. For example:

- name: Create a file
  with_items: "{{ workdir.results }}"
  shell: touch {{ item.stdout }}/test-file

When the playbook is running, the Ansible console displays the entire value for "item" on each iteration. That makes the output noisy and difficult for a human to parse visually. For example:

TASK [Create a file] ***************************************************
changed: [localhost] => (item={'cmd': 'mktemp -d', 'stdout': '/tmp/tmp.a
ncF0iBqzP', 'stderr': '', 'rc': 0, 'start': '2023-05-26 15:22:46.458962'
, 'end': '2023-05-26 15:22:46.465557', 'delta': '0:00:00.006595', 'chang
ed': True, 'invocation': {'module_args': {'_raw_params': 'mktemp -d', '_
uses_shell': True, 'warn': True, 'stdin_add_newline': True, 'strip_empty
_ends': True, 'argv': None, 'chdir': None, 'executable': None, 'creates'
: None, 'removes': None, 'stdin': None}}, 'stdout_lines': ['/tmp/tmp.anc
F0iBqzP'], 'stderr_lines': [], 'failed': False, 'item': 1, 'ansible_loop
_var': 'item'})
changed: [localhost] => (item={'cmd': 'mktemp -d', 'stdout': '/tmp/tmp.v
Tpkvx6RK0', 'stderr': '', 'rc': 0, 'start': '2023-05-26 15:22:46.727879'
, 'end': '2023-05-26 15:22:46.734876', 'delta': '0:00:00.006997', 'chang
ed': True, 'invocation': {'module_args': {'_raw_params': 'mktemp -d', '_
uses_shell': True, 'warn': True, 'stdin_add_newline': True, 'strip_empty
_ends': True, 'argv': None, 'chdir': None, 'executable': None, 'creates'
: None, 'removes': None, 'stdin': None}}, 'stdout_lines': ['/tmp/tmp.vTp
kvx6RK0'], 'stderr_lines': [], 'failed': False, 'item': 2, 'ansible_loop
_var': 'item'})

Here's my question:

Is there a way to

  • abbreviate the output of 'item' in the Ansible console output?
  • change the loop so that it iterates differently, like:
with_items: "{{ workdir.results.*.stdout }}"
shell: touch {{ item }}/test-file
  • some filter that can modify the items?
  • some other clever solution?
Score:3
br flag

There are more options:

shell> cat pb.yml
- hosts: localhost

  tasks:

    - command: mktemp -d
      register: workdir
      with_sequence: end=2

    - command: "touch {{ item.stdout }}/test-file" 
      loop: "{{ workdir.results }}"
      loop_control:
        label: "{{ item.stdout }}"

gives

shell> ansible_playbook pb.yml

PLAY [localhost] *****************************************************************************

TASK [command] *******************************************************************************
changed: [localhost] => (item=1)
changed: [localhost] => (item=2)

TASK [command] *******************************************************************************
changed: [localhost] => (item=/tmp/tmp.2pOVwfrYLI)
changed: [localhost] => (item=/tmp/tmp.FyF0JCghAo)

PLAY RECAP ***********************************************************************************
localhost: ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

  • Optionally, create a list of the directories first
shell> cat pb.yml
- hosts: localhost

  vars:

    workdirs: "{{ workdir.results|map(attribute='stdout') }}"

  tasks:

    - command: mktemp -d
      register: workdir
      with_sequence: end=2

    - command: "touch {{ item }}/test-file" 
      loop: "{{ workdirs }}"

gives the same

shell> ansible-playbook pb.yml

PLAY [localhost] *****************************************************************************

TASK [command] *******************************************************************************
changed: [localhost] => (item=1)
changed: [localhost] => (item=2)

TASK [command] *******************************************************************************
changed: [localhost] => (item=/tmp/tmp.OOHLqAfFlX)
changed: [localhost] => (item=/tmp/tmp.T5lF2ZruwZ)

PLAY RECAP ***********************************************************************************
localhost: ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Notes:

- hosts: localhost

  vars:

    workdirs: "{{ workdir.results|map(attribute='path') }}"

  tasks:

    - tempfile:
        state: directory
      register: workdir
      with_sequence: end=2

    - file:
        state: touch
        path: "{{ item }}/test-file" 
      loop: "{{ workdirs }}"

    - file:
        state: absent
        path: "{{ item }}"
      loop: "{{ workdirs }}"
Ginnungagap avatar
gu flag
It might be worth using an `always` block to ensure cleanup though leaving temporary files on error might be desirable as well.
user3629081 avatar
in flag
The `loop_control` > `label` is exactly what I was in need of, thank you!! And I appreciate all the other notes and tips, too. I need to go study more about filters, they look really useful.
user3629081 avatar
in flag
@Vladimir Botka I have a question about your second solution, where you list of the directories first. I notice that the play is setting the `workdirs` variable before the `workdir` variable even exists. How does order-of-operations make this function? Seems like chicken-and-egg problem.
br flag
It is not a `setting` actually. It's rather a `declaration` that is evaluated on demand. See [Lazy evaluation](https://stackoverflow.com/questions/57025699/how-is-it-possible-that-ansible-loop-items-be-referenced-by-variables-outside-th/57026116#57026116).
br flag
It is also very useful to understand the `'instantiation'` of variables, i.e. when a variable becomes an attribute of *hostvars*. See [Take some variable values from one host and use them in another host](https://stackoverflow.com/questions/71795614/ansible-take-some-variable-values-from-one-host-and-use-them-in-another-host/71797724#71797724).
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.