<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>

CC BY-SA 4.0
2020-03-30T07:39:46.927Z
Thanks, it works now :) added the solution to the first post
dfsg76
CC BY-SA 4.0
2020-03-29T17:18:42.000Z
2020-03-29T17:30:41.053Z
2020-03-29T17:30:41.053Z
John Humphreys
<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>

CC BY-SA 4.0
2020-03-30T07:16:05.513Z
Thanks a lot for the suggestion :)
dfsg76
CC BY-SA 4.0
2020-03-30T04:31:00.090Z
2020-03-30T04:31:00.090Z
Bruce Becker
<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>

<ansible><glusterfs>
I don't fully understand how to use variables in Ansible roles
dfsg76
# 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
Variable precedence
Looping over hashes

> **Comments:**
> **username_0**: Thanks a lot for the suggestion :)  

---

