Reputation: 392
I just started working with Ansible recently. I am trying to mount 4 disks on azure VM which were attached using terraform. Each disk was passed with a LUN number and I am fetching the device name(sdc,sdd etc.) for each disk using that LUN no.and grep.
- name: get volume name
shell: echo "/dev/$(ls -l /dev/disk/azure/scsi1 |grep {{ item.lun }}|egrep -o "([^\/]+$)")"
register: volumename
- parted:
device: "{{ volumename.stdout }}"
number: 1
state: present
- filesystem:
fstype: xfs
dev: "{{ volumename.stdout }}"
- mount:
fstype: xfs
opts: noatime
src: "{{ volumename.stdout }}"
path: "{{ item.mountpoint }}"
state: mounted
- command: blkid -s UUID -o value {{ volumename.stdout }}
register: volumename_disk
- blockinfile:
path: /etc/fstab
state: present
block: |
UUID={{ volumename_disk.stdout }} {{ volumename.stdout }} xfs defaults,noatime,nofail 0 0
loop:
- { lun: 'lun0', mountpoint: '/apps/mysql/binlog', diskname: 'binlog' }
- { lun: 'lun1', mountpoint: '/apps/mysql/innodb', diskname: 'innodb' }
- { lun: 'lun2', mountpoint: '/apps/mysql/data', diskname: 'data' }
- { lun: 'lun3', mountpoint: '/apps/mysql', diskname: 'backup' }
tags: test
I keep getting volumename variable is not defined error. Is there any way to set volumename as global so that the next playbook can access it or How I can improve this code ?
Upvotes: 2
Views: 3581
Reputation: 6581
Everything here is awesome. I added something to make parted
idempotent, but it's hard to post it out of context, so...here is the full solution that i put together using the OP's script and @shubham-jairath 's excellent loop:
File: plays/mountdisk.yml
---
# https://stackoverflow.com/questions/63100027/how-to-mount-multiple-disks-in-a-loop-using-ansible
- name: get volume name
shell: echo "/dev/$(ls -l /dev/disk/azure/scsi1 | grep {{ item.lun }} | egrep -o "([^\/]+$)")"
register: volumename
- name: get partition (if any)
shell: blkid | grep "{{ volumename.stdout }}" || true
register: partition
- name: partition and mount
block:
- parted:
device: "{{ volumename.stdout }}"
number: 1
state: present
- filesystem:
fstype: xfs
dev: "{{ volumename.stdout }}"
- mount:
fstype: xfs
opts: noatime
src: "{{ volumename.stdout }}"
path: "{{ item.mountpoint }}"
state: mounted
- command: blkid -s UUID -o value {{ volumename.stdout }}
register: volumename_disk
- blockinfile:
path: /etc/fstab
state: present
block: |
UUID={{ volumename_disk.stdout }} {{ volumename.stdout }} xfs defaults,noatime,nofail 0 0
when: partition.stdout == ""
Upvotes: 0
Reputation: 392
After reading through documentation, I was able to find a way to achieve this.
The right approach would be to use Ansible's dictionary variable.
raid_config:
- lun: "{{ backup_lun }}"
mountpoint: "{{ backup_mountpoint }}"
- lun: "{{ data_lun }}"
mountpoint: "{{ data_mountpoint }}"
- lun: "{{ binlog_lun }}"
mountpoint: "{{ binlog_mountpoint }}"
- lun: "{{ innodb_lun }}"
mountpoint: "{{ innodb_mountpoint }}"
Moved the tasks to a separate file mountdisk.yml and passed a dictionary to the tasks like this
- include_tasks: "mountdisk.yml"
loop: "{{ raid_config }}"
loop_control:
loop_var: disk
tags: test
Upvotes: 1
Reputation: 488
First of all I'm not an expert with ansible, but what it look like you're trying to do is:
Which I think is not possible. The other thing is that the loop
-variables is only available to the task with matching indentation, in your case: blockinfile
.
What you can do is create an own task-file for the tasks you want perform and include that in your playbook (loop over includes). This has been done by @Konstantin in following example: Multiple ansible task with same loop
EXTRA:
Reason why it is NOT available
IF it had been possible to use a single loop
for several tasks, then you would have to make sure to apply it to all the tasks, like:
- block:
task1
...
task2
...
loop:
- { lun: 'lun0', mountpoint: '/apps/mysql/binlog', diskname: 'binlog' }
- { lun: 'lun1', mountpoint: '/apps/mysql/innodb', diskname: 'innodb' }
EXAMPLE:
(Created an example from your comment, I do not think this is a good solution, but it is a solution)
Create a list using set_fact
and then pass this list to another playbook.
Using my existing examples:
my_tasks.yml:
---
- command: echo "{{ item.lun}}"
register: volumename
- set_fact:
volumenames: "{{ volumenames|default([]) + [ { 'name': volumename.stdout } ] }}"
- debug:
msg: "VOLUMENAME is: {{ volumename.stdout }}"
playbook.yml:
---
- hosts: localhost
tasks:
- include_tasks: my_tasks.yml
loop:
- { lun: 'lun0', mountpoint: '/apps/mysql/binlog', diskname: 'binlog' }
- { lun: 'lun1', mountpoint: '/apps/mysql/innodb', diskname: 'innodb' }
- { lun: 'lun2', mountpoint: '/apps/mysql/data', diskname: 'data' }
- { lun: 'lun3', mountpoint: '/apps/mysql', diskname: 'backup' }
- import_playbook: playbook2.yml myvar='{{ volumenames }}'
playbook2.yml
---
- hosts: localhost
tasks:
- debug:
msg: "{{ myvar }}"
Upvotes: 2