Search code examples
loopsansiblenested-loops

Ansible nested_loops and product filter


I want to improve my ansible role because i have a lot of users to roll out.

For each user that is created there will be also multiple folders

created and this is very time consuming.

This is my users.yml file where i put every single user in (>1000)

ftp_users:
  testuser1:
    public_key: "public key"
    password: "sha string"
    home: /home/testuser1
    customer_type: linux
  testuser2:
    public_key: "public key"
    password: "sha string"
    home: /home/testuser2
    customer_type: windows

For this 2 users i want to create two folders "in" and "out".

Therefore i've created two tasks where i iterating over the dictionary:

- name: Create required out-folder for jailed users.
  become: true
  ansible.builtin.file:
    owner: "{{ item.key }}"
    group: ftpusers
    mode: 0770
    path: "/home/{{ item.value.customer_type }}/{{ item.key }}/out"
    state: directory
  loop: "{{ ftp_users | dict2items }}"
  when: "'state' not in item.value or item.value.state == 'present'"

- name: Create required in-folder for jailed users.
  become: true
  ansible.builtin.file:
    owner: "{{ item.key }}"
    group: ftpusers
    mode: 0770
    path: "/home/{{ item.value.customer_type }}/{{ item.key }}/in"
    state: directory
  loop: "{{ ftp_users | dict2items }}"
  when: "'state' not in item.value or item.value.state == 'present'"

This is very stupid because it takes a lot of time when 1000 users are rolled out.

I want to make one tasks to simultaniously create the "in" and "out" folder for every user, that i dont have to iterate two times over the whole dictionary.

What would be better nested_loops or the product filter?

Can someone show me an example?


Solution

  • Unfortunately block doesnt accept loop, so you could use include_tasks:

    - name: "tips4"
      hosts: localhost
      gather_facts: false
      vars:
        ftp_users:
          testuser1:
            public_key: "public key"
            password: "sha string"
            home: /home/testuser1
            customer_type: linux
          testuser2:
            public_key: "public key"
            password: "sha string"
            home: /home/testuser2
            customer_type: windows
    
      tasks: 
        - name: Create required out-folder for jailed users
          include_tasks: create_folders.yml
          loop: "{{ ftp_users | dict2items }}"
          when: "'state' not in item.value or item.value.state == 'present'"
    

    Create another file create_folders.yml in same folder than your playbook

    # create_folders.yml
    ---
    - name: Create required out-folder for jailed users
      debug:
        msg: "owner: {{ item.key }}, path: /home/{{ item.value.customer_type }}/{{ item.key }}/out"
    
    - name: Create required in-folder for jailed users
      debug:
        msg: "owner: {{ item.key }}, path: /home/{{ item.value.customer_type }}/{{ item.key }}/in"
    

    result:

    TASK [Create required out-folder for jailed users]
    ok: [localhost] => {
        "msg": "owner: testuser1, path: /home/linux/testuser1/out"
    }
    
    TASK [Create required in-folder for jailed users] 
    ok: [localhost] => {
        "msg": "owner: testuser1, path: /home/linux/testuser1/in"
    }
    
    TASK [Create required out-folder for jailed users] 
    ok: [localhost] => {
        "msg": "owner: testuser2, path: /home/windows/testuser2/out"
    }
    
    TASK [Create required in-folder for jailed users] 
    ok: [localhost] => {
        "msg": "owner: testuser2, path: /home/windows/testuser2/in"
    }
    

    with this playbook, in and out folder are created in same loop, so you just iterate one time...