Search code examples
listloopsansiblepathstructure

Ansible loop through list to build folder structure


i got the following lists:

vars:

  - sftp_users:

    - name: user1

      authorized: [user1.pub]

      append: True

      home: /cdrstorage/sftp/user1

      sftp_directories:

      - folder1

      - folder2

    - name: user2

      authorized: [user2.pub]

      append: True

      home: /cdrstorage/sftp/user2

      sftp_directories:

      - folder3

  - sftp_subdirectories:

    - source

    - processed

    - rejected

And i would like to generate the following structure for each user with its "sftp_directories" and some common "sftp_subdirectories" like this

/cdrstorage/sftp/user1/folder1/source

/cdrstorage/sftp/user1/folder1/processed

/cdrstorage/sftp/user1/folder1/rejected

/cdrstorage/sftp/user1/folder2/source

/cdrstorage/sftp/user1/folder2/processed

/cdrstorage/sftp/user1/folder2/rejected

/cdrstorage/sftp/user2/folder3/source

/cdrstorage/sftp/user2/folder3/processed

/cdrstorage/sftp/user2/folder3/rejected

How can I achieve this the best.

I have tried it with with_nested and with_subelements. Couldn't achieve it.


Solution

  • The below Jinja

      sublist: |
        {% filter from_yaml %}
        {% for user in sftp_users %}
        {% for dir in user.sftp_directories %}
        {% for subdir in sftp_subdirectories %}
        - {{ user.home }}/{{ dir }}/{{ subdir }}
        {% endfor %}
        {% endfor %}
        {% endfor %}
        {% endfilter %}
    

    will create the list

      sublist:
      - /cdrstorage/sftp/user1/folder1/source
      - /cdrstorage/sftp/user1/folder1/processed
      - /cdrstorage/sftp/user1/folder1/rejected
      - /cdrstorage/sftp/user1/folder2/source
      - /cdrstorage/sftp/user1/folder2/processed
      - /cdrstorage/sftp/user1/folder2/rejected
      - /cdrstorage/sftp/user2/folder3/source
      - /cdrstorage/sftp/user2/folder3/processed
      - /cdrstorage/sftp/user2/folder3/rejected
    

    If you want to iterate the structure combine the lists

      subdirs: "{{ sftp_users|
                   map(attribute='sftp_directories')|
                   map('product', sftp_subdirectories)|
                   map('map', 'join', '/')|
                   map('community.general.dict_kv', 'subdirs') }}"
      sftp_subdirs: "{{ sftp_users|zip(subdirs)|map('combine') }}"
    

    gives

      sftp_subdirs:
      - append: true
        authorized:
        - user1.pub
        home: /cdrstorage/sftp/user1
        name: user1
        sftp_directories:
        - folder1
        - folder2
        subdirs:
        - folder1/source
        - folder1/processed
        - folder1/rejected
        - folder2/source
        - folder2/processed
        - folder2/rejected
      - append: true
        authorized:
        - user2.pub
        home: /cdrstorage/sftp/user2
        name: user2
        sftp_directories:
        - folder3
        subdirs:
        - folder3/source
        - folder3/processed
        - folder3/rejected
    

    Now, you can iterate the list with subelements

        - debug:
            msg: "{{ item.0.home }}/{{ item.1 }}"
          loop: "{{ sftp_subdirs|subelements('subdirs') }}"
          loop_control:
            label: "{{ item.0.name }}"
    

    gives (abridged)

      msg: /cdrstorage/sftp/user1/folder1/source
      msg: /cdrstorage/sftp/user1/folder1/processed
      msg: /cdrstorage/sftp/user1/folder1/rejected
      msg: /cdrstorage/sftp/user1/folder2/source
      msg: /cdrstorage/sftp/user1/folder2/processed
      msg: /cdrstorage/sftp/user1/folder2/rejected
      msg: /cdrstorage/sftp/user2/folder3/source
      msg: /cdrstorage/sftp/user2/folder3/processed
      msg: /cdrstorage/sftp/user2/folder3/rejected
    

    Example of a complete playbook for testing

    - hosts: localhost
    
      vars:
    
        sftp_users:
          - append: true
            authorized: [user1.pub]
            home: /cdrstorage/sftp/user1
            name: user1
            sftp_directories: [folder1, folder2]
          - append: true
            authorized: [user2.pub]
            home: /cdrstorage/sftp/user2
            name: user2
            sftp_directories: [folder3]
        sftp_subdirectories: [source, processed, rejected]
    
        subdirs: "{{ sftp_users|
                     map(attribute='sftp_directories')|
                     map('product', sftp_subdirectories)|
                     map('map', 'join', '/')|
                     map('community.general.dict_kv', 'subdirs') }}"
        sftp_subdirs: "{{ sftp_users|zip(subdirs)|map('combine') }}"
        sublist: |
          {% filter from_yaml %}
          {% for user in sftp_users %}
          {% for dir in user.sftp_directories %}
          {% for subdir in sftp_subdirectories %}
          - {{ user.home }}/{{ dir }}/{{ subdir }}
          {% endfor %}
          {% endfor %}
          {% endfor %}
          {% endfilter %}
    
      tasks:
    
        - debug:
            var: subdirs
        - debug:
            var: sublist
        - debug:
            var: sftp_subdirs
    
        - debug:
            msg: "{{ item.0.home }}/{{ item.1 }}"
          loop: "{{ sftp_subdirs|subelements('subdirs') }}"
          loop_control:
            label: "{{ item.0.name }}"
          tags: loop