1

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!

11
  • If you want to create entries in some file, why do you try to iterate in Ansible (as opposed to Jinja2)? Commented Jun 4, 2018 at 14:44
  • Hmmm. Interesting point - I want to leave alone what's there, so was using lineinfile. Maybe I should use a template and j2. My question does still have merit, I believe though. It is sometimes useful to loop through the keys of a dictionary as I've described, I think. Commented Jun 4, 2018 at 14:47
  • There is a blockinfile too, if you want "to leave alone what's there". Commented Jun 4, 2018 at 14:52
  • Thanks. That's true, and a good point. Maybe I am approaching this the wrong way. Nevertheless I stand by my earlier comment - this is still a useful thing to be able to do. If you're telling me that it's not possible, that's very useful information as I'll know to always look for an alternative approach. Do you happen to know that what I'm trying to do is not possible? Thanks again. Commented Jun 4, 2018 at 14:55
  • You see, with limits, I should really be putting each parameter in a different file. The examples split by setting - so produce /etc/security/limitd.d/20_nproc .../30nofiles ,etc. Now, I don't want to do that - I think it's over complicated - but if I did, I'm not sure I could template it - the dictionary key would become a filename (so I'd split not by setting, but by user - or I could re-format the data), and the values the lines in the file. Commented Jun 4, 2018 at 14:58

2 Answers 2

3

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

Sign up to request clarification or add additional context in comments.

Comments

2

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')  }}"

1 Comment

Thank you - that's exactly what I was after. I guess you have to name the elements rather than simply nesting the lists so that you can access them. I've gone with a template, but with your data structure change , all is perfect. Thanks again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.