Answers: <p>I solved this with the Jinja test "exists" and the select filter to filter away the resulting 'AnsibleUndefined' values. The "is exists" test checks if the path exists on the ansible control host. This is the place the credentials are stored.</p>
  
  <p>The solved code is below:</p>
  
  <pre class="lang-yaml prettyprint-override"><code>    ---
      - hosts: localhost
        tasks:
        - name: Include users.yaml and setup all vars for nexus
          include_vars:
            file: users.yaml
            name: users
        - set_fact:
            tmp_user:
            - username: "{{ item.username }}"
              first_name: "{{ item.first_name }}"
              last_name: "{{ item.last_name }}"
              email: "{{ item.email }}"
              password: "{{ lookup('password', 'credentials/' + item.username + '/password.txt length=15 chars=ascii_letters') }}"
              roles: "{{ item.roles }}"
          loop: "{{ users.nexus_local_users }}"
          register: tmp_users
          when: "not '{{ playbook_dir }}/credentials/{{ item.username }}/password.txt' is exists"
        - set_fact:
            tmp_user: "{{ item.ansible_facts.tmp_user | combine(item.item) }}"
          with_items: "{{ tmp_users.results }}"
          register: tmp_users_sorted
          when: "not item is skipped"
        - set_fact:
            nexus_local_users: "{{ tmp_users_sorted.results | map(attribute='item.ansible_facts.tmp_user') | list | select('defined') | list }}"
        - debug:
            msg: "{{ nexus_local_users }}"
  </code></pre>
  
  <p>The following was added/changed:</p>
  
  <pre class="lang-yaml prettyprint-override"><code>        when: "not '{{ playbook_dir }}/credentials/{{ item.username }}/password.txt' is exists"
  </code></pre>
  
  <pre class="lang-yaml prettyprint-override"><code>        nexus_local_users: "{{ tmp_users_sorted.results | map(attribute='item.ansible_facts.tmp_user') | list | select('defined') | list }}"
  </code></pre>
  
  <pre class="lang-yaml prettyprint-override"><code>       when: "not item is skipped"
  </code></pre>
  
  <p>This makes for a compact solution without adding more tasks/files.</p>
  
  <p>For more information see: <a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html" rel="nofollow noreferrer">https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html</a></p>
  
Answers: CC BY-SA 4.0
Answers: 2020-04-10T10:00:39.637Z
Answers: 2020-04-10T11:48:56.230Z
Answers: 2020-04-10T11:48:56.230Z
Answers: Gijs Peerlings
Answers: <p>You should first <a href="https://docs.ansible.com/ansible/latest/modules/stat_module.htm" rel="nofollow noreferrer">stat</a> for the password file, and then set the fact depending on whether the <a href="https://docs.ansible.com/ansible/latest/modules/stat_module.html#return-stat/exists" rel="nofollow noreferrer">file.stat.exists</a> or not. And both those tasks need to be performed for each user.</p>
  
  <p>As of Ansible 2.4 you can dynamically <a href="https://docs.ansible.com/ansible/latest/modules/include_tasks_module.html" rel="nofollow noreferrer">include_tasks</a> and perform a <a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html" rel="nofollow noreferrer">loop</a> on it. Meaning that you can group a few tasks in a file and loop those tasks for every value in your loop-variable.</p>
  
  <p>I think this should be able to solve your problem by creating a separate tasks file containing these tasks that should be run for each user:</p>
  
  <p>Stat for the password-file:</p>
  
  <pre class="lang-yaml prettyprint-override"><code>   - name: Check if password-file exists for user
       stat:
          path: "credentials/{{ item.username }}/password.txt"
       register: password_file
  </code></pre>
  
  <p>Next you can define your tmp_user var when the password.txt-file exists:</p>
  
  <pre class="lang-yaml prettyprint-override"><code>   - name: Set fact for user
       set_fact:
         tmp_user:
          - username: "{{ item.username }}"
            first_name: "{{ item.first_name }}"
            last_name: "{{ item.last_name }}"
            email: "{{ item.email }}"
            password: "{{ lookup('password', 'credentials/' + item.username + '/password.txt length=15 chars=ascii_letters') }}"
            roles: "{{ item.roles }}"
        when: password_file.stat.exists
        register: set_tmp_user
  </code></pre>
  
  <p>Then, if previous task defined a new fact tmp_user, that fact should be added to the tmp_users list. </p>
  
  <pre class="lang-yaml prettyprint-override"><code>   - name: Add user to list
       set_fact:
         tmp_users: {{ tmp_users + [ tmp_user ] }}
       when: not set_tmp_user is skipped
  </code></pre>
  
  <p>(not sure by head if you can use <code>when: set_tmp_user is changed</code> but <code>not is skipped</code> should do the job)</p>
  
  <p>Then in you main tasks-file, you create an empty tmp_users list and call an include_tasks in a loop to loop through the above tasks:</p>
  
  <pre class="lang-yaml prettyprint-override"><code>   - name: Include users.yaml and setup all vars for nexus
       include_vars:
         file: users.yaml
         name: users
  
     - name: Initialize tmp_users
       set_fact:
          tmp_users: []
  
     - name: Set user facts
       include_tasks: set_user_facts.yml
       loop: "{{ users.nexus_local_users }}"
  </code></pre>
  
  <p>Disclaimer: I have not been able to test this out, or check its syntax, but I assume the general idea of which I try to accomplish here should be clear?</p>
  
  <p>Also be aware that you currently can't perform a loop inside the included tasks file as that loop will by default overwrite the <code>item</code>-variable defined by the tasks-loop. See <a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#defining-inner-and-outer-variable-names-with-loop-var" rel="nofollow noreferrer">defining inner and outer variable names with loop var</a> to solve this.</p>
  
  <p>And an additional tip: add a debug task as first task to your included tasks file to output the current <code>item.username</code> in the loop.</p>
  
Answers: CC BY-SA 4.0
Answers: 2020-04-09T15:38:52.253Z
Answers: 2020-04-09T15:38:52.253Z
Answers: Robin Roevens
Body: <p>I have written some Ansible code to put users from the users.yaml file in the variable 'nexus_local_users' to be used by a role. When doing this a random password is created and written to the 'credentials/{{ user }}/password.txt' file. </p>
  
  <p>I'm looking for a condition that can make sure that once the user is created it won't be added to the variable again, to make sure the user isn't added twice. My first thought to achieve this was to check if a password has been generated already. </p>
  
  <p>Is there any way to make sure a user is only added to this variable once and not on consecutive runs?</p>
  
  <p>Here is a snapshot of the code I am using:</p>
  
  <pre><code>    - name: Include users.yaml and setup all vars for nexus
        include_vars:
          file: users.yaml
          name: users
      - set_fact:
         tmp_user:
          - username: "{{ item.username }}"
            first_name: "{{ item.first_name }}"
            last_name: "{{ item.last_name }}"
            email: "{{ item.email }}"
            password: "{{ lookup('password', 'credentials/' + item.username + '/password.txt length=15 chars=ascii_letters') }}"
            roles: "{{ item.roles }}"
        loop: "{{ users.nexus_local_users }}" 
        register: tmp_users
      - set_fact:
          tmp_user: "{{ item.item | combine(item.ansible_facts.tmp_user) }}"
        with_items: "{{ tmp_users.results }}"
        register: tmp_users
      - set_fact:
          nexus_local_users: "{{ tmp_users.results | map(attribute='ansible_facts.tmp_user') | list }}"
  </code></pre>
  
  <p>I'm looking for something like this but can't figure out how to implement it (the when condition):</p>
  
  <pre><code>    - set_fact:
         tmp_user:
          - username: "{{ item.username }}"
            first_name: "{{ item.first_name }}"
            last_name: "{{ item.last_name }}"
            email: "{{ item.email }}"
            password: "{{ lookup('password', 'credentials/' + item.username + '/password.txt length=15 chars=ascii_letters') }}"
            roles: "{{ item.roles }}"
        loop: "{{ users.nexus_local_users }}"
        when: **directory/file credentials/{{ user }}/password.txt exists**
        register: tmp_users
  </code></pre>
  
  <p>Thanks in advance!</p>
  
  <p>Gijs</p>
  
Comments: CC BY-SA 4.0
Comments: 2020-04-09T11:17:38.460Z
Comments: looks like you need a `stat` before the loop, and then a when conditional based on the outcome of that?
Comments: Bruce Becker
Comments: CC BY-SA 4.0
Comments: 2020-04-09T12:03:54.393Z
Comments: Can I loop the `stat` as well? It needs to check all the directory's and based on that figure out if the user was already created. This means there is a directory per user in the credentials folder if that user was already created.
Comments: Gijs Peerlings
Tags: <ansible><automation><passwords>
Title: Ansible: When 'directory/file exists' in a loop
UserDisplayName: Gijs Peerlings
ThreadText: # Ansible: When 'directory/file exists' in a loop
  
  (Asked by: username_0 on 2020-04-09)
  
  I have written some Ansible code to put users from the users.yaml file in the variable 'nexus\_local\_users' to be used by a role. When doing this a random password is created and written to the 'credentials/{{ user }}/password.txt' file.
  
  I'm looking for a condition that can make sure that once the user is created it won't be added to the variable again, to make sure the user isn't added twice. My first thought to achieve this was to check if a password has been generated already.
  
  Is there any way to make sure a user is only added to this variable once and not on consecutive runs?
  
  Here is a snapshot of the code I am using:
  
  ```
      - name: Include users.yaml and setup all vars for nexus
        include_vars:
          file: users.yaml
          name: users
      - set_fact:
         tmp_user:
          - username: "{{ item.username }}"
            first_name: "{{ item.first_name }}"
            last_name: "{{ item.last_name }}"
            email: "{{ item.email }}"
            password: "{{ lookup('password', 'credentials/' + item.username + '/password.txt length=15 chars=ascii_letters') }}"
            roles: "{{ item.roles }}"
        loop: "{{ users.nexus_local_users }}" 
        register: tmp_users
      - set_fact:
          tmp_user: "{{ item.item | combine(item.ansible_facts.tmp_user) }}"
        with_items: "{{ tmp_users.results }}"
        register: tmp_users
      - set_fact:
          nexus_local_users: "{{ tmp_users.results | map(attribute='ansible_facts.tmp_user') | list }}"
  
  ```
  
  I'm looking for something like this but can't figure out how to implement it (the when condition):
  
  ```
      - set_fact:
         tmp_user:
          - username: "{{ item.username }}"
            first_name: "{{ item.first_name }}"
            last_name: "{{ item.last_name }}"
            email: "{{ item.email }}"
            password: "{{ lookup('password', 'credentials/' + item.username + '/password.txt length=15 chars=ascii_letters') }}"
            roles: "{{ item.roles }}"
        loop: "{{ users.nexus_local_users }}"
        when: **directory/file credentials/{{ user }}/password.txt exists**
        register: tmp_users
  
  ```
  
  Thanks in advance!
  
  username_0
  
  **Tags:** ansible, automation, passwords
  
  > **Comments:**
  > **username_1**: looks like you need a `stat` before the loop, and then a when conditional based on the outcome of that?  
  > **username_0**: Can I loop the `stat` as well? It needs to check all the directory's and based on that figure out if the user was already created. This means there is a directory per user in the credentials folder if that user was already created.  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_0 on 2020-04-10. Score: 2 | Accepted answer
  
  I solved this with the Jinja test "exists" and the select filter to filter away the resulting 'AnsibleUndefined' values. The "is exists" test checks if the path exists on the ansible control host. This is the place the credentials are stored.
  
  The solved code is below:
  
  ```yaml
      ---
      - hosts: localhost
        tasks:
        - name: Include users.yaml and setup all vars for nexus
          include_vars:
            file: users.yaml
            name: users
        - set_fact:
            tmp_user:
            - username: "{{ item.username }}"
              first_name: "{{ item.first_name }}"
              last_name: "{{ item.last_name }}"
              email: "{{ item.email }}"
              password: "{{ lookup('password', 'credentials/' + item.username + '/password.txt length=15 chars=ascii_letters') }}"
              roles: "{{ item.roles }}"
          loop: "{{ users.nexus_local_users }}"
          register: tmp_users
          when: "not '{{ playbook_dir }}/credentials/{{ item.username }}/password.txt' is exists"
        - set_fact:
            tmp_user: "{{ item.ansible_facts.tmp_user | combine(item.item) }}"
          with_items: "{{ tmp_users.results }}"
          register: tmp_users_sorted
          when: "not item is skipped"
        - set_fact:
            nexus_local_users: "{{ tmp_users_sorted.results | map(attribute='item.ansible_facts.tmp_user') | list | select('defined') | list }}"
        - debug:
            msg: "{{ nexus_local_users }}"
  
  ```
  
  The following was added/changed:
  
  ```yaml
          when: "not '{{ playbook_dir }}/credentials/{{ item.username }}/password.txt' is exists"
  
  ```
  
  ```yaml
          nexus_local_users: "{{ tmp_users_sorted.results | map(attribute='item.ansible_facts.tmp_user') | list | select('defined') | list }}"
  
  ```
  
  ```yaml
         when: "not item is skipped"
  
  ```
  
  This makes for a compact solution without adding more tasks/files.
  
  For more information see: <https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html>
  
  
  ---
  
  ### Answer by username_2 on 2020-04-09. Score: 2
  
  You should first [stat](https://docs.ansible.com/ansible/latest/modules/stat_module.htm) for the password file, and then set the fact depending on whether the [file.stat.exists](https://docs.ansible.com/ansible/latest/modules/stat_module.html#return-stat/exists) or not. And both those tasks need to be performed for each user.
  
  As of Ansible 2.4 you can dynamically [include\_tasks](https://docs.ansible.com/ansible/latest/modules/include_tasks_module.html) and perform a [loop](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html) on it. Meaning that you can group a few tasks in a file and loop those tasks for every value in your loop-variable.
  
  I think this should be able to solve your problem by creating a separate tasks file containing these tasks that should be run for each user:
  
  Stat for the password-file:
  
  ```yaml
     - name: Check if password-file exists for user
       stat:
          path: "credentials/{{ item.username }}/password.txt"
       register: password_file
  
  ```
  
  Next you can define your tmp\_user var when the password.txt-file exists:
  
  ```yaml
     - name: Set fact for user
       set_fact:
         tmp_user:
          - username: "{{ item.username }}"
            first_name: "{{ item.first_name }}"
            last_name: "{{ item.last_name }}"
            email: "{{ item.email }}"
            password: "{{ lookup('password', 'credentials/' + item.username + '/password.txt length=15 chars=ascii_letters') }}"
            roles: "{{ item.roles }}"
        when: password_file.stat.exists
        register: set_tmp_user
  
  ```
  
  Then, if previous task defined a new fact tmp\_user, that fact should be added to the tmp\_users list.
  
  ```yaml
     - name: Add user to list
       set_fact:
         tmp_users: {{ tmp_users + [ tmp_user ] }}
       when: not set_tmp_user is skipped
  
  ```
  
  (not sure by head if you can use `when: set_tmp_user is changed` but `not is skipped` should do the job)
  
  Then in you main tasks-file, you create an empty tmp\_users list and call an include\_tasks in a loop to loop through the above tasks:
  
  ```yaml
     - name: Include users.yaml and setup all vars for nexus
       include_vars:
         file: users.yaml
         name: users
  
     - name: Initialize tmp_users
       set_fact:
          tmp_users: []
  
     - name: Set user facts
       include_tasks: set_user_facts.yml
       loop: "{{ users.nexus_local_users }}"
  
  ```
  
  Disclaimer: I have not been able to test this out, or check its syntax, but I assume the general idea of which I try to accomplish here should be clear?
  
  Also be aware that you currently can't perform a loop inside the included tasks file as that loop will by default overwrite the `item`-variable defined by the tasks-loop. See [defining inner and outer variable names with loop var](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#defining-inner-and-outer-variable-names-with-loop-var) to solve this.
  
  And an additional tip: add a debug task as first task to your included tasks file to output the current `item.username` in the loop.
  
  
  ---
  
  