Answers: <p>Your very first role include does not have variables provided with it, so it will fail.</p>
  
  <p>Here's an excerpt from above showing this.  Notice lines 1-2 have no variables after them (unlike the include following that which does correctly provide the variables).</p>
  
  <pre><code>- include_role:
      name: gluster-node-partition
  
  - name: Create data1 partition
    include_role:
      name: gluster-node-partition
    vars:
      device_name: '/dev/sdb'
      partition_name: 'data1'
  </code></pre>
  
  <p>As <code>roles/gluster-node-partition/tasks/main.yml</code> uses device_name twice, and it is not defined for that first call, it will fail. The two usages are noted on line 2 and on the last line below.</p>
  
  <pre><code>  parted:
      device: '{{ device_name }}'
      number: 1
      label: gpt
      name: '{{ partition_name }}'
      state: present
    become: true
  
  - name: 'Create filesystem on {{ partition_name }} partition'
    filesystem:
      fstype: btrfs
      dev: '{{ device_name }}1' #should expand to something like '/dev/sdb1'
  </code></pre>
  
Answers: CC BY-SA 4.0
Answers: 2020-03-30T07:39:46.927Z
Answers: Thanks, it works now :) added the solution to the first post
Answers: dfsg76
Answers: CC BY-SA 4.0
Answers: 2020-03-29T17:18:42.000Z
Answers: 2020-03-29T17:30:41.053Z
Answers: 2020-03-29T17:30:41.053Z
Answers: John Humphreys
Answers: <p>You might want to use the group vars feature, so that your playbooks stay clean and re-usable.
  You define a <code>storageservers</code> group in your inventory; associated with this group, Ansible will look for <code>group_vars/storageservers.yml</code> for the vars to associate with this group. Here, you can set the variables:</p>
  
  <pre><code># group_vars/storageservers.yml
  ---
  partitions:
   - device_name: /dev/sdb
     partition_name: /data1
   - device_name: /dev/sdc
     partition_name: /data2
   - device_name: /dev/sdd
     partition_name: /data3
  </code></pre>
  
  <p>Now, you have a list of partitions which will be picked up when you target <code>hosts: storageservers</code>, which you can loop over with one statement instead of 3:</p>
  
  <pre><code># playbook.yml
  ---
  hosts: storage
  become: true
  roles:
    - gluster-node-partition
  </code></pre>
  
  <p>Updated tasks:</p>
  
  <pre><code># roles/gluster-node-partition/tasks.yml
  - name: "Create {{ item['partition_name'] }} partition"
    parted:
      device: "{{ item['device_name'] }}"
      number: 1
      label: gpt
      name: "{{ item['partition_name' }}"
      state: present
    loop: "{{ partitions }}"
  
  - name: "Create filesystem on {{ item['partition_name'] }} partition"
    filesystem:
      fstype: btrfs
      dev: "{{ item['device_name'] }}1" #should expand to something like '/dev/sdb1'
    item: "{{ partitions }}"
  
  - name: "Create mount point for {{ item['partition_name'] }} partition"
    file:
      path: '/{{ item['partition_name'] }}'
      state: directory
    loop: "{{ partitions }}"
  
  - name: "Mount {{ item['partition_name'] }} partition"
    mount:
      path: "/{{ item['partition_name'] }}"
      src: "LABEL={{ item['partition_name'] }}"
      fstype: btrfs
      state: present
    loop: "{{ partitions }}"
  </code></pre>
  
  <p>Doing it this way separates variables from tasks. If you want to add or change a filesystem, you only need to change the <em>variable</em> and not the <em>playbook</em>.</p>
  
  <p>You also have a much cleaner playbook -- just a few lines. It's clear that this <em>all</em> of the filesystem stuff is contained in the role.</p>
  
  <p>If you have a different set of machines where you want different mounts, you only have to add a new group, give that group a new <code>partitions</code> variable, and target it in the same way by setting <code>hosts: other_storage_servers</code>.</p>
  
  <p>For reference, see the Ansible docs on :</p>
  
  <ul>
  <li><a href="https://docs.ansible.com/ansible/latest/user_guide/intro_patterns.html" rel="nofollow noreferrer">Targetting groups</a></li>
  <li><a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable" rel="nofollow noreferrer">Variable precedence</a></li>
  <li><a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#iterating-over-a-list-of-hashes" rel="nofollow noreferrer">Looping over hashes</a></li>
  </ul>
  
Answers: CC BY-SA 4.0
Answers: 2020-03-30T07:16:05.513Z
Answers: Thanks a lot for the suggestion :)
Answers: dfsg76
Answers: CC BY-SA 4.0
Answers: 2020-03-30T04:31:00.090Z
Answers: 2020-03-30T04:31:00.090Z
Answers: Bruce Becker
Body: <p><strong>Original question:</strong></p>
  
  <p>I want to roll out a partitioning layout for a home lab setup of GlusterFS and also want to do it using Ansible so I can re-use the configuration for a more stable setup later on. This is also the first time I work with Ansible so please bear with me ;)</p>
  
  <p>How do I use variables across roles correctly?</p>
  
  <p>I created a role for the basic partitioning of a single data disk and I want to have 3 disks on each node.</p>
  
  <p>My nodes are as follows (path = <code>inventories/staging/hosts.yaml</code>)</p>
  
  <pre><code>all:
    hosts:
      node1:
        ansible_host: node1
      node2:
        ansible_host: node2
  
  storageservers:
    hosts:
      node1:
        ansible_host: node1
      node2:
        ansible_host: node2
  </code></pre>
  
  <p>The base role used by the aggregating role is as follows (path = <code>roles/gluster-node-partition/tasks/main.yml</code>):</p>
  
  <pre><code>---
  # tasks file for gluster-node-partition
  - name: 'Create {{ partition_name }} partition'
    parted:
      device: '{{ device_name }}'
      number: 1
      label: gpt
      name: '{{ partition_name }}'
      state: present
    become: true
  
  - name: 'Create filesystem on {{ partition_name }} partition'
    filesystem:
      fstype: btrfs
      dev: '{{ device_name }}1' #should expand to something like '/dev/sdb1'
    become: true
  
  - name: 'Create mount point for {{ partition_name }} partition'
    file:
      path: '/{{ partition_name }}'
      state: directory
    become: true
  
  - name: 'Mount {{ partition_name }} partition'
    mount:
      path: '/{{ partition_name }}'
      src: 'LABEL={{ partition_name }}'
      fstype: btrfs
      state: present
    become: true
  </code></pre>
  
  <p>The aggregating role is as follows (path = <code>roles/gluster-node/tasks/main.yml</code>):</p>
  
  <pre><code>---
  # tasks file for gluster-node
  - include_role:
      name: gluster-node-partition
  
  - name: Create data1 partition
    include_role:
      name: gluster-node-partition
    vars:
      device_name: '/dev/sdb'
      partition_name: 'data1'
  
  - name: Create data2 partition
    include_role:
      name: gluster-node-partition
    vars:
      device_name: '/dev/sdc'
      partition_name: 'data2'
  
  - name: Create data3 partition
    include_role:
      name: cluster-node-partition
    vars:
      device_name: '/dev/sdd'
      partition_name: 'data3'
  </code></pre>
  
  <p>I invoke the following command <code>ansible-playbook -i inventories/playground/hosts.yaml site.yml -K</code></p>
  
  <p>The output is as follows</p>
  
  <pre><code>BECOME password: 
  
  PLAY [storageservers] *****************************************************************************************************************************************
  
  TASK [Gathering Facts] ****************************************************************************************************************************************
  ok: [node2]
  ok: [node1]
  
  TASK [include_role : gluster-node-partition] ******************************************************************************************************************
  
  TASK [gluster-node-partition : Create {{ partition_name }} partition] *****************************************************************************************
  fatal: [node1]: FAILED! =&gt; {"msg": "The task includes an option with an undefined variable. The error was: 'device_name' is undefined\n\nThe error appears to be in '/home/user/ansible/roles/gluster-node-partition/tasks/main.yml': line 3, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n# tasks file for gluster-node-partition\n- name: 'Create {{ partition_name }} partition'\n  ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n    with_items:\n      - {{ foo }}\n\nShould be written as:\n\n    with_items:\n      - \"{{ foo }}\"\n"}
  fatal: [node2]: FAILED! =&gt; {"msg": "The task includes an option with an undefined variable. The error was: 'device_name' is undefined\n\nThe error appears to be in '/home/user/ansible/roles/gluster-node-partition/tasks/main.yml': line 3, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n# tasks file for gluster-node-partition\n- name: 'Create {{ partition_name }} partition'\n  ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n    with_items:\n      - {{ foo }}\n\nShould be written as:\n\n    with_items:\n      - \"{{ foo }}\"\n"}
  
  PLAY RECAP ****************************************************************************************************************************************************
  node1                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
  node2                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0  
  </code></pre>
  
  <p><strong>Solution by w00te:</strong>
  Thanks to w00te, it works now :) added the vars like this (<code>roles/gluster-node/tasks/main.yml</code>)</p>
  
  <pre><code># tasks file for gluster-node
  - include_role:
      name: gluster-node-partition
    vars:
      device_name: '/dev/sdb'
      partition_name: 'data1'
  </code></pre>
  
Tags: <ansible><glusterfs>
Title: I don't fully understand how to use variables in Ansible roles
UserDisplayName: dfsg76
ThreadText: # I don't fully understand how to use variables in Ansible roles
  
  (Asked by: username_0 on 2020-03-29)
  
  **Original question:**
  
  I want to roll out a partitioning layout for a home lab setup of GlusterFS and also want to do it using Ansible so I can re-use the configuration for a more stable setup later on. This is also the first time I work with Ansible so please bear with me ;)
  
  How do I use variables across roles correctly?
  
  I created a role for the basic partitioning of a single data disk and I want to have 3 disks on each node.
  
  My nodes are as follows (path = `inventories/staging/hosts.yaml`)
  
  ```
  all:
    hosts:
      node1:
        ansible_host: node1
      node2:
        ansible_host: node2
  
  storageservers:
    hosts:
      node1:
        ansible_host: node1
      node2:
        ansible_host: node2
  
  ```
  
  The base role used by the aggregating role is as follows (path = `roles/gluster-node-partition/tasks/main.yml`):
  
  ```
  ---
  # tasks file for gluster-node-partition
  - name: 'Create {{ partition_name }} partition'
    parted:
      device: '{{ device_name }}'
      number: 1
      label: gpt
      name: '{{ partition_name }}'
      state: present
    become: true
  
  - name: 'Create filesystem on {{ partition_name }} partition'
    filesystem:
      fstype: btrfs
      dev: '{{ device_name }}1' #should expand to something like '/dev/sdb1'
    become: true
  
  - name: 'Create mount point for {{ partition_name }} partition'
    file:
      path: '/{{ partition_name }}'
      state: directory
    become: true
  
  - name: 'Mount {{ partition_name }} partition'
    mount:
      path: '/{{ partition_name }}'
      src: 'LABEL={{ partition_name }}'
      fstype: btrfs
      state: present
    become: true
  
  ```
  
  The aggregating role is as follows (path = `roles/gluster-node/tasks/main.yml`):
  
  ```
  ---
  # tasks file for gluster-node
  - include_role:
      name: gluster-node-partition
  
  - name: Create data1 partition
    include_role:
      name: gluster-node-partition
    vars:
      device_name: '/dev/sdb'
      partition_name: 'data1'
  
  - name: Create data2 partition
    include_role:
      name: gluster-node-partition
    vars:
      device_name: '/dev/sdc'
      partition_name: 'data2'
  
  - name: Create data3 partition
    include_role:
      name: cluster-node-partition
    vars:
      device_name: '/dev/sdd'
      partition_name: 'data3'
  
  ```
  
  I invoke the following command `ansible-playbook -i inventories/playground/hosts.yaml site.yml -K`
  
  The output is as follows
  
  ```
  BECOME password: 
  
  PLAY [storageservers] *****************************************************************************************************************************************
  
  TASK [Gathering Facts] ****************************************************************************************************************************************
  ok: [node2]
  ok: [node1]
  
  TASK [include_role : gluster-node-partition] ******************************************************************************************************************
  
  TASK [gluster-node-partition : Create {{ partition_name }} partition] *****************************************************************************************
  fatal: [node1]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'device_name' is undefined\n\nThe error appears to be in '/home/user/ansible/roles/gluster-node-partition/tasks/main.yml': line 3, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n# tasks file for gluster-node-partition\n- name: 'Create {{ partition_name }} partition'\n  ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n    with_items:\n      - {{ foo }}\n\nShould be written as:\n\n    with_items:\n      - \"{{ foo }}\"\n"}
  fatal: [node2]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'device_name' is undefined\n\nThe error appears to be in '/home/user/ansible/roles/gluster-node-partition/tasks/main.yml': line 3, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n# tasks file for gluster-node-partition\n- name: 'Create {{ partition_name }} partition'\n  ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n    with_items:\n      - {{ foo }}\n\nShould be written as:\n\n    with_items:\n      - \"{{ foo }}\"\n"}
  
  PLAY RECAP ****************************************************************************************************************************************************
  node1                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
  node2                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0  
  
  ```
  
  **Solution by w00te:**
  Thanks to w00te, it works now :) added the vars like this (`roles/gluster-node/tasks/main.yml`)
  
  ```
  # tasks file for gluster-node
  - include_role:
      name: gluster-node-partition
    vars:
      device_name: '/dev/sdb'
      partition_name: 'data1'
  
  ```
  
  **Tags:** ansible, glusterfs
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2020-03-29. Score: 1 | Accepted answer
  
  Your very first role include does not have variables provided with it, so it will fail.
  
  Here's an excerpt from above showing this. Notice lines 1-2 have no variables after them (unlike the include following that which does correctly provide the variables).
  
  ```
  - include_role:
      name: gluster-node-partition
  
  - name: Create data1 partition
    include_role:
      name: gluster-node-partition
    vars:
      device_name: '/dev/sdb'
      partition_name: 'data1'
  
  ```
  
  As `roles/gluster-node-partition/tasks/main.yml` uses device\_name twice, and it is not defined for that first call, it will fail. The two usages are noted on line 2 and on the last line below.
  
  ```
    parted:
      device: '{{ device_name }}'
      number: 1
      label: gpt
      name: '{{ partition_name }}'
      state: present
    become: true
  
  - name: 'Create filesystem on {{ partition_name }} partition'
    filesystem:
      fstype: btrfs
      dev: '{{ device_name }}1' #should expand to something like '/dev/sdb1'
  
  ```
  
  > **Comments:**
  > **username_0**: Thanks, it works now :) added the solution to the first post  
  
  ---
  
  ### Answer by username_2 on 2020-03-30. Score: 1
  
  You might want to use the group vars feature, so that your playbooks stay clean and re-usable.
  You define a `storageservers` group in your inventory; associated with this group, Ansible will look for `group_vars/storageservers.yml` for the vars to associate with this group. Here, you can set the variables:
  
  ```
  # group_vars/storageservers.yml
  ---
  partitions:
   - device_name: /dev/sdb
     partition_name: /data1
   - device_name: /dev/sdc
     partition_name: /data2
   - device_name: /dev/sdd
     partition_name: /data3
  
  ```
  
  Now, you have a list of partitions which will be picked up when you target `hosts: storageservers`, which you can loop over with one statement instead of 3:
  
  ```
  # playbook.yml
  ---
  hosts: storage
  become: true
  roles:
    - gluster-node-partition
  
  ```
  
  Updated tasks:
  
  ```
  # roles/gluster-node-partition/tasks.yml
  - name: "Create {{ item['partition_name'] }} partition"
    parted:
      device: "{{ item['device_name'] }}"
      number: 1
      label: gpt
      name: "{{ item['partition_name' }}"
      state: present
    loop: "{{ partitions }}"
  
  - name: "Create filesystem on {{ item['partition_name'] }} partition"
    filesystem:
      fstype: btrfs
      dev: "{{ item['device_name'] }}1" #should expand to something like '/dev/sdb1'
    item: "{{ partitions }}"
  
  - name: "Create mount point for {{ item['partition_name'] }} partition"
    file:
      path: '/{{ item['partition_name'] }}'
      state: directory
    loop: "{{ partitions }}"
  
  - name: "Mount {{ item['partition_name'] }} partition"
    mount:
      path: "/{{ item['partition_name'] }}"
      src: "LABEL={{ item['partition_name'] }}"
      fstype: btrfs
      state: present
    loop: "{{ partitions }}"
  
  ```
  
  Doing it this way separates variables from tasks. If you want to add or change a filesystem, you only need to change the *variable* and not the *playbook*.
  
  You also have a much cleaner playbook -- just a few lines. It's clear that this *all* of the filesystem stuff is contained in the role.
  
  If you have a different set of machines where you want different mounts, you only have to add a new group, give that group a new `partitions` variable, and target it in the same way by setting `hosts: other_storage_servers`.
  
  For reference, see the Ansible docs on :
  
  * [Targetting groups](https://docs.ansible.com/ansible/latest/user_guide/intro_patterns.html)
  * [Variable precedence](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable)
  * [Looping over hashes](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#iterating-over-a-list-of-hashes)
  
  > **Comments:**
  > **username_0**: Thanks a lot for the suggestion :)  
  
  ---
  
  