Home > OS >  Ansible - 'with_items' pointed directly at 'vars' rather than expanding them fir
Ansible - 'with_items' pointed directly at 'vars' rather than expanding them fir

Time:08-06

First off thank you for any assistance here, this is my first post on here despite using it as a great resource for years!

I have recently been learning and using Ansible a lot more as part of a new role I'm in for work and my manager has asked me to make a change that I find a little confusing.

I have a task that runs a shell command and loops through the command using the with_items module

- name: add non-existent buckets
  shell: "timeout 30 mc --config-dir={{ mc_config }} mb opt/{{item}}"
  with_items: "{{ bucket_list }}"

I have been asked to change this to point directly at the variables rather than expanding them first and I am struggling to understand what this means and how to go about it.

I have tried various ways of writing this out but no luck whatsoever. The frustrating part of all this is that the above works but apparently makes the Ansible engine do more work than it needs to do.

Thanks in advance and please let me know if I need to provide any more information!

CodePudding user response:

I understand that you like to know "How to increase the performance and decrease execution time of specific tasks?". I understand that you like to create multiple new buckets or directories under a specified path opt/ in a MinIO Baremetal Infrastructure via the mc mb command.

It is an equivalent like of mkdir -p /opt/{this,is,my,list,of,subdirectories,to,create}. I understand that you do not want to loop over the command, instead providing a directory list for the command.

To achieve for goal you may have a look into the following example, documentation and further links.

---
- hosts: test
  become: false
  gather_facts: false

  vars:

    DIR_LIST: [this,is,my,list,of,subdirectories,to,create]

  tasks:

  - name: Create subdirectories (loop)
    shell:
      cmd: "mkdir -p /home/{{ ansible_user }}/{{ item }}"
      warn: false
    loop: "{{ DIR_LIST }}"

  - name: Create subdirectories (list)
    shell:
      cmd: "mkdir -p /home/{{ ansible_user }}/{% raw %}{{% endraw %}{{ DIR_LIST | join(',') }}{% raw %}}{% endraw %}"
      warn: false

resulting into run and execution times of

TASK [Create subdirectories (loop)] ******************
changed: [test.example.com] => (item=this)
changed: [test.example.com] => (item=is)
changed: [test.example.com] => (item=my)
changed: [test.example.com] => (item=list)
changed: [test.example.com] => (item=of)
changed: [test.example.com] => (item=subdirectories)
changed: [test.example.com] => (item=to)
changed: [test.example.com] => (item=create)
Friday 29 July 2022 (0:00:14.023) 0:00:14.064 ********

TASK [Create subdirectories (list)] ******************
changed: [test.example.com]

Friday 29 July 2022 (0:00:02.172) 0:00:16.236 ********
======================================================
Create subdirectories (loop) ------------------ 14.02s
Create subdirectories (list) ------------------- 2.17s

Whereby looping over modules or commands and providing one parameter for the module or command per run results into a lot of overhead, providing the list directly to the command or module might be possible and increase performance and decrease runtime and resource consumption.

An (other) example for this is the yum module

When used with a loop: each package will be processed individually, it is much more efficient to pass the list directly to the name option

If your command mc mb produce similar results as mentioned in documentation

You can also use mc mb against the local filesystem to produce similar results to the mkdir -p commandline tool.

you might be able provide a list of directories to the command via Ansible too, in example like

mc mb opt/{this,is,my,list,of,subdirectories,to,create}

For this the command needs to include curly braces which needs to be escaped in Ansible. The directory list would need to be a string, whereby the directories are comma separated. For this you can use the join() filter.

Is there a way to pass a list to a command and get it to iterate over each item without a loop?

Finally you would end up with

- name: add non-existent buckets
  shell: 
    cmd: "timeout 30 mc --config-dir={{ mc_config }} mb opt/{% raw %}{{% endraw %}{{ bucket_list | join(',') }}{% raw %}}{% endraw %}"

Further Q&A

Further Documentation

Further Readings

  • Related