18

I'm trying to use ansible to loop over a list of lists to install some packages. But {{item}} is returning every element in the sub lists rather than the sublist itself. I have a yaml file which come from a manifest list from outside ansible and it looks like this:

---
modules:
 - ['module','version','extra']
 - ['module2','version','extra']
 - ['module3','version','extra']

My task looks like this:

task:
 - include_vars: /path/to/external/file.yml
 - name: install modules
   yum: name={{item.0}} state=installed
   with_items: "{{ modules }}"

When I run that I get:

fatal: [localhost]: FAILED! => {"failed": true, "msg": "ERROR! int object has no element 0"}

When I try:

- debug: msg="{{item}}"
  with_items: "{{module}}"

it prints every element (module, version, extra, and so on), not just the sublist (which is what I would expect)

Neybar
  • 303
  • 1
  • 3
  • 10

4 Answers4

17

An alternative way to solve this issue is to use a complex item instead of a list of list. Structure your variables like this:

- modules:
  - {name: module1, version: version1, info: extra1}
  - {name: module2, version: version2, info: extra2}
  - {name: module3, version: version3, info: extra3}

Then you can still use with_items, like this:

- name: Printing Stuffs...
  shell: echo This is "{{ item.name }}", "{{ item.version }}" and "{{ item.info }}"
  with_items: "{{modules}}"
gameweld
  • 1,319
  • 15
  • 21
  • 1
    This helped my case with Ansible 2.2.1. Ran into a similar issue with list of lists where `{{ item.0 }}` was expanded incorrectly to '.' or '', and using a dictionary per list item fixed this. – RichVel Feb 03 '17 at 09:29
10

Replace with_items: "{{ modules }}" with:

  • in Ansible 2.5 and later (refer to with_list porting guide):

    loop: "{{ modules }}"
    
  • in Ansible 2.0 and later:

    with_list: "{{ modules }}"
    
  • in any Ansible pre-2.0:

    with_items:
      - "{{ modules }}"
    

    This way you'd have three levels of nested lists, and the default behaviour flattens only two of them.

techraf
  • 64,883
  • 27
  • 193
  • 198
7

Unfortunately, this is the intended behavior. Please see this discussion on with_tems and nested lists

helloV
  • 50,176
  • 7
  • 137
  • 145
  • OMG, don't know what kind of crack mpdehaan was on when he made this decision but it makes `with_items` work in a completely inconsistent way. Plus, maybe his syntactical purity idea was still valid in 2014, but by now Ansible has become such a convoluted mess (precisely because he doesn't want it to be a programming language, so you end up needing all kinds of non-programming-language hacks to get it to do what you want) that at least having `with_items` just do what it says would make much more sense. I guess we have `loop` now which does do what you would expect. Lesson: avoid `with_items`. – Frans Mar 03 '22 at 06:12
7

@helloV already provided the answer that you can not do this using with_items, i am going to show you how you can use your current data structure with with_nested to get the desired output.

Here is an example playbook:

---
- hosts:
    - localhost
  vars:
    - modules:
      - ['module1','version1','extra1']
      - ['module2','version2','extra2']
      - ['module3','version3','extra3']

  tasks:
    - name: Printing Stuffs...
      shell: echo This is "{{ item.0 }}", "{{ item.1 }}" and "{{ item.2 }}"
      with_nested:
       - modules

Now you will get the following as stdout_lines:

This is module1, version1 and extra1
This is module2, version2 and extra2
This is module3, version3 and extra3
heemayl
  • 39,294
  • 7
  • 70
  • 76
  • I swear I tried this as I was iterating over various options. I just tried it again, and it worked exactly as I was hoping. – Neybar Mar 08 '16 at 22:14
  • 1
    So I jumped the gun, it still isn't working. my datastructure has one line in it at the moment: cpann_modules: - ['Algorithm::Diff', '0'] error is: failed: [alpha.bluehost.com] => (item=[u'A', u'l', u'g', u'o', u'r', u'i', u't', u'h', u'm', u':', u':', u'D', u'i', u'f', u'f']) => {"changed": false, "failed": true, "item": ["A", "l", "g", "o", "r", "i", "t", "h", "m", ":", ":", "D", "i", "f", "f"], "msg": "No Package matching ... [ error truncated ] you can see that it is trying to iterate over every character in the first line, which is silly. – Neybar Mar 08 '16 at 22:33
  • @Neybar As per questions example, it's working for me as you can see in my answer..could you add your current example to the question so that I can check.. – heemayl Mar 09 '16 at 01:00