Answers: <p>I found a solution using file globs.  Since I have a configuration file for each site, I can simply use the list of those files to iterate over all of them.   That way I don't have the list of sites in my task file even once, let alone twice.   All I need to do to add a site is add a file.</p>
  
  <p>To make things a little easier I created a directory for the templates:</p>
  
  <ul>
  <li><code>roles/webserver/templates/apache-sites/sitea.conf.j2</code></li>
  <li><code>roles/webserver/templates/apache-sites/siteb.conf.j2</code></li>
  <li><code>roles/webserver/templates/apache-sites/sitec.conf.j2</code></li>
  <li><code>roles/webserver/templates/apache-sites/sited.conf.j2</code></li>
  </ul>
  
  <p>Then in <code>roles/webserver/tasks/main.yml</code> I can use that list of files and some regular expressions:</p>
  
  <pre><code>---
  - block:
    - name: Install apache site conf
      template: src={{item}} dest=/etc/apache2/sites-available/{{item|regex_replace(".*/","")|regex_replace("\.j2$","")}} mode=0644
      with_fileglob:
      - "roles/webserver/templates/apache-sites/*"
    - name: Enable site apache conf
      command: a2ensite {{item|regex_replace(".*/","")|regex_replace("\.conf\.j2$","")}}
      args:
        creates: /etc/apache2/sites-enabled/{{item|regex_replace(".*/","")|regex_replace("\.j2$","")}}
      with_fileglob:
      - "roles/webserver/templates/apache-sites/*"
    become: yes
  </code></pre>
  
  <p>This technique could even be used with empty dummy files to create a list for other applications.</p>
  
Answers: CC BY-SA 3.0
Answers: 2018-01-08T16:05:49.950Z
Answers: 2018-01-08T16:24:58.400Z
Answers: 2018-01-08T16:24:58.400Z
Answers: Stephen Ostermiller
Answers: <p>Konstantin gave a good answer; here is an additional flavor on it.</p>
  
  <p>I will commonly define the lists as variables, and just write two separate loops over the same variable:</p>
  
  <pre><code>┌─[jamesph@geror] - [~/temp] - [Sat Jan 13, 10:06]
  └─[$]&gt; cat loops-1.yml
  - hosts: localhost
    gather_facts: no
    vars:
      menu:
        - Egg and Spam
        - Spam, bacon, sausage and Spam
        - Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam
    tasks:
      - debug:
          msg: "We have {{ item }}"
        with_items: "{{ menu }}"
      - debug:
          msg: "I love {{ item }}!"
        with_items: "{{ menu }}"
  ┌─[jamesph@geror] - [~/temp] - [Sat Jan 13, 10:06]
  └─[$]&gt; ansible-playbook loops-1.yml
   [WARNING]: Unable to parse /etc/ansible/hosts as an inventory source
  
   [WARNING]: No inventory was parsed, only implicit localhost is available
  
   [WARNING]: Could not match supplied host pattern, ignoring: all
  
   [WARNING]: provided hosts list is empty, only localhost is available
  
  
  PLAY [localhost] **********************************************************************************************************************
  
  TASK [debug] **************************************************************************************************************************
  ok: [localhost] =&gt; (item=Egg and Spam) =&gt; {
      "changed": false,
      "item": "Egg and Spam",
      "msg": "We have Egg and Spam"
  }
  ok: [localhost] =&gt; (item=Spam, bacon, sausage and Spam) =&gt; {
      "changed": false,
      "item": "Spam, bacon, sausage and Spam",
      "msg": "We have Spam, bacon, sausage and Spam"
  }
  ok: [localhost] =&gt; (item=Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam) =&gt; {
      "changed": false,
      "item": "Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam",
      "msg": "We have Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam"
  }
  
  TASK [debug] **************************************************************************************************************************
  ok: [localhost] =&gt; (item=Egg and Spam) =&gt; {
      "changed": false,
      "item": "Egg and Spam",
      "msg": "I love Egg and Spam!"
  }
  ok: [localhost] =&gt; (item=Spam, bacon, sausage and Spam) =&gt; {
      "changed": false,
      "item": "Spam, bacon, sausage and Spam",
      "msg": "I love Spam, bacon, sausage and Spam!"
  }
  ok: [localhost] =&gt; (item=Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam) =&gt; {
      "changed": false,
      "item": "Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam",
      "msg": "I love Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam!"
  }
  
  PLAY RECAP ****************************************************************************************************************************
  localhost                  : ok=2    changed=0    unreachable=0    failed=0
  </code></pre>
  
  <p>This works nicely with <a href="https://docs.ansible.com/ansible/latest/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable" rel="nofollow noreferrer">variable precedence</a>, for instance by defining different sets of servers per environment.  It also works when you need to perform various other non-looped tasks in-between the two loops.</p>
  
Answers: CC BY-SA 3.0
Answers: 2018-01-13T18:11:57.770Z
Answers: 2018-01-13T18:11:57.770Z
Answers: Xiong Chiamiov
Answers: <p>Make separate tasks file <code>make_site.yml</code>:</p>
  
  <pre><code>---
  - name: Install apache site conf
    template:
      src: apache-sites-{{ site }}-conf.j2
      dest: /etc/apache2/sites-available/{{ site }}.conf
      mode: 0644
  
  - name: Enable site apache conf
    command: a2ensite {{ site }}
    args:
      creates: /etc/apache2/sites-enabled/{{ site }}.conf
  </code></pre>
  
  <p>And in your playbook:</p>
  
  <pre><code>- include_tasks: make_site.yml
    with_items:
      - sitea
      - siteb
      - sitec
      - sited
    loop_control:
      loop_var: site
  </code></pre>
  
Answers: CC BY-SA 4.0
Answers: 2019-03-13T13:27:08.290Z
Answers: I was hoping to find a solution without having to create a separate file. Something like a `loop` on a `block` block. That seems to be requested, but rejected via [Ansible GH issue 13262](https://github.com/ansible/ansible/issues/13262). `:-(`
Answers: gertvdijk
Answers: CC BY-SA 3.0
Answers: 2017-12-28T16:59:21.597Z
Answers: 2017-12-28T16:59:21.597Z
Answers: Konstantin Suvorov
Body: <p>I am using an ansible playbook to configure Apache for a list of sites.   The playbook has to copy the virtual host configuration template for each site into place, and then enable each site using <code>a2ensite</code>:</p>
  
  <pre><code>- name: Install apache site conf
    template: src=apache-sites-{{item}}-conf.j2 dest=/etc/apache2/sites-available/{{item}}.conf mode=0644
    with_items:
    - sitea
    - siteb
    - sitec
    - sited
  - name: Enable site apache conf
    command: a2ensite {{item}}
    args:
      creates: /etc/apache2/sites-enabled/{{item}}.conf
    with_items:
    - sitea
    - siteb
    - sitec
    - sited
  </code></pre>
  
  <p>I don't like having to repeat the same list for each task.   How to I configure the playbook to execute both tasks with the same list of items?</p>
  
Tags: <ansible>
Title: Execute multiple Ansible tasks with the same list of items
UserDisplayName: Stephen Ostermiller
ThreadText: # Execute multiple Ansible tasks with the same list of items
  
  (Asked by: username_0 on 2017-12-28)
  
  I am using an ansible playbook to configure Apache for a list of sites. The playbook has to copy the virtual host configuration template for each site into place, and then enable each site using `a2ensite`:
  
  ```
  - name: Install apache site conf
    template: src=apache-sites-{{item}}-conf.j2 dest=/etc/apache2/sites-available/{{item}}.conf mode=0644
    with_items:
    - sitea
    - siteb
    - sitec
    - sited
  - name: Enable site apache conf
    command: a2ensite {{item}}
    args:
      creates: /etc/apache2/sites-enabled/{{item}}.conf
    with_items:
    - sitea
    - siteb
    - sitec
    - sited
  
  ```
  
  I don't like having to repeat the same list for each task. How to I configure the playbook to execute both tasks with the same list of items?
  
  **Tags:** ansible
  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_0 on 2018-01-08. Score: 2 | Accepted answer
  
  I found a solution using file globs. Since I have a configuration file for each site, I can simply use the list of those files to iterate over all of them. That way I don't have the list of sites in my task file even once, let alone twice. All I need to do to add a site is add a file.
  
  To make things a little easier I created a directory for the templates:
  
  * `roles/webserver/templates/apache-sites/sitea.conf.j2`
  * `roles/webserver/templates/apache-sites/siteb.conf.j2`
  * `roles/webserver/templates/apache-sites/sitec.conf.j2`
  * `roles/webserver/templates/apache-sites/sited.conf.j2`
  
  Then in `roles/webserver/tasks/main.yml` I can use that list of files and some regular expressions:
  
  ```
  ---
  - block:
    - name: Install apache site conf
      template: src={{item}} dest=/etc/apache2/sites-available/{{item|regex_replace(".*/","")|regex_replace("\.j2$","")}} mode=0644
      with_fileglob:
      - "roles/webserver/templates/apache-sites/*"
    - name: Enable site apache conf
      command: a2ensite {{item|regex_replace(".*/","")|regex_replace("\.conf\.j2$","")}}
      args:
        creates: /etc/apache2/sites-enabled/{{item|regex_replace(".*/","")|regex_replace("\.j2$","")}}
      with_fileglob:
      - "roles/webserver/templates/apache-sites/*"
    become: yes
  
  ```
  
  This technique could even be used with empty dummy files to create a list for other applications.
  
  
  ---
  
  ### Answer by username_2 on 2017-12-28. Score: 21
  
  Make separate tasks file `make_site.yml`:
  
  ```
  ---
  - name: Install apache site conf
    template:
      src: apache-sites-{{ site }}-conf.j2
      dest: /etc/apache2/sites-available/{{ site }}.conf
      mode: 0644
  
  - name: Enable site apache conf
    command: a2ensite {{ site }}
    args:
      creates: /etc/apache2/sites-enabled/{{ site }}.conf
  
  ```
  
  And in your playbook:
  
  ```
  - include_tasks: make_site.yml
    with_items:
      - sitea
      - siteb
      - sitec
      - sited
    loop_control:
      loop_var: site
  
  ```
  
  > **Comments:**
  > **username_3**: I was hoping to find a solution without having to create a separate file. Something like a `loop` on a `block` block. That seems to be requested, but rejected via [Ansible GH issue 13262](https://github.com/ansible/ansible/issues/13262). `:-(`  
  
  ---
  
  ### Answer by username_1 on 2018-01-13. Score: 2
  
  username_2 gave a good answer; here is an additional flavor on it.
  
  I will commonly define the lists as variables, and just write two separate loops over the same variable:
  
  ```
  ┌─[jamesph@geror] - [~/temp] - [Sat Jan 13, 10:06]
  └─[$]> cat loops-1.yml
  - hosts: localhost
    gather_facts: no
    vars:
      menu:
        - Egg and Spam
        - Spam, bacon, sausage and Spam
        - Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam
    tasks:
      - debug:
          msg: "We have {{ item }}"
        with_items: "{{ menu }}"
      - debug:
          msg: "I love {{ item }}!"
        with_items: "{{ menu }}"
  ┌─[jamesph@geror] - [~/temp] - [Sat Jan 13, 10:06]
  └─[$]> ansible-playbook loops-1.yml
   [WARNING]: Unable to parse /etc/ansible/hosts as an inventory source
  
   [WARNING]: No inventory was parsed, only implicit localhost is available
  
   [WARNING]: Could not match supplied host pattern, ignoring: all
  
   [WARNING]: provided hosts list is empty, only localhost is available
  
  PLAY [localhost] **********************************************************************************************************************
  
  TASK [debug] **************************************************************************************************************************
  ok: [localhost] => (item=Egg and Spam) => {
      "changed": false,
      "item": "Egg and Spam",
      "msg": "We have Egg and Spam"
  }
  ok: [localhost] => (item=Spam, bacon, sausage and Spam) => {
      "changed": false,
      "item": "Spam, bacon, sausage and Spam",
      "msg": "We have Spam, bacon, sausage and Spam"
  }
  ok: [localhost] => (item=Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam) => {
      "changed": false,
      "item": "Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam",
      "msg": "We have Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam"
  }
  
  TASK [debug] **************************************************************************************************************************
  ok: [localhost] => (item=Egg and Spam) => {
      "changed": false,
      "item": "Egg and Spam",
      "msg": "I love Egg and Spam!"
  }
  ok: [localhost] => (item=Spam, bacon, sausage and Spam) => {
      "changed": false,
      "item": "Spam, bacon, sausage and Spam",
      "msg": "I love Spam, bacon, sausage and Spam!"
  }
  ok: [localhost] => (item=Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam) => {
      "changed": false,
      "item": "Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam",
      "msg": "I love Spam, Spam, Spam, Spam, Spam, Spam, baked beans, Spam, Spam, Spam and Spam!"
  }
  
  PLAY RECAP ****************************************************************************************************************************
  localhost                  : ok=2    changed=0    unreachable=0    failed=0
  
  ```
  
  This works nicely with [variable precedence](https://docs.ansible.com/ansible/latest/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable), for instance by defining different sets of servers per environment. It also works when you need to perform various other non-looped tasks in-between the two loops.
  
  
  ---
  
  