Graham Nicholls
Graham Nicholls

Reputation: 561

Iterating over an array within an array in Ansible

I wish to create entries in /etc/security.limits.conf
The data structure will look something like this:

limits:
  - root:
    - "soft nproc unlimited"
    - "hard nfile unlimited"
  - ec2-user:
    - "soft nproc 4096"

Producing lines in /etc/security.conf like so:

root soft nproc unlimited
root hard nfile unlimited
ec2-user soft nproc 4096

The data definition produces a dictionary of arrays. The outer dictionary is keyed by user, each of which has its own array of lines to add.

I expect the code to look something like this pseudocode:

  for user in $limits   
     for line in $user  
        lineinfile $line ...  
     end  
  end  

I just can't see how to do this with Ansible.

I've been doing debugging with a debug task so I can see what the {{ item }} contains - like so:

 - name: limits | Set limits in /etc/security/limits.conf
     debug:
       msg: item is {{ item }}
     loop: "{{ limits }} "

But how do I get at the individual elements of the array? There could be up to 16 possible array elements - one for each tunable parameter.

I've found this impossible to google - all the results refer to Ansible docs, which I've read thoroughly - is not always with comprehension.

Any pointers much appreciated, and apologies if I'm missing something obvious!

Upvotes: 1

Views: 10015

Answers (2)

edesz
edesz

Reputation: 12406

Using with_subelements:

File varloops.yml:

---
- name: Loop using with_subelements
  hosts: localhost
  connection: local
  vars_files:
    - vars.yml
  gather_facts: no


  tasks:
    - name: create a test file
      file:
        path: "{{ mytestfile }}"
        state: touch

     - name: create required entries in file
       lineinfile:
         dest: "{{ mytestfile }}"
         line: "{{ item.0.name }} {{ item.1 }}"
       with_subelements:
         - "{{ limits }}""
         - contents

File vars.yml:

---
mytestfile: ~/ansible-projects/test.txt

limits:
  - name: root
    contents:
      - "soft nproc unlimited"
      - "hard nfile unlimited"
  - name: ec2-user
    contents:
      - "soft nproc 4096"

I run this with:

$ ansible-playbook varloops.yml

and $ cat test.txt shows:

  root soft nproc unlimited
  root hard nfile unlimited
  ec2-user soft nproc 4096

lineinfile nested dict example

Upvotes: 3

Ignacio Millán
Ignacio Millán

Reputation: 8066

The best I've got is using subelements module. It is necessary to change the data structure, but it is also a best practice to use named elements instead of just nested lists:

   limits:
   - user: root
     limits:
     - "soft nproc unlimited"
     - "hard nfile unlimited"
   - user: ec2-user
     limits:
     - "soft nproc 4096"

And the task:

- debug:
    msg: "username is {{ item.0.user }}, security limits are {{item.1 }}"
  loop: "{{ query('subelements', limits, 'limits')  }}"

Upvotes: 2

Related Questions