我最近刚刚开始使用 Ansible。我正在尝试在使用 terraform 连接的 azure VM 上安装 4 个磁盘。每个磁盘都传递了一个 LUN 编号,我正在使用该 LUN 编号和 grep 获取每个磁盘的设备名称(sdc、sdd 等)。
- 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
我不断收到“volumename 变量未定义”错误。有什么方法可以将卷名称设置为全局,以便下一个剧本可以访问它或者我如何改进此代码?
首先,我不是 ansible 专家,但你想要做的是:
我认为这是不可能的。另一件事是,
loop
变量仅适用于具有匹配缩进的任务,在您的情况下:blockinfile
。
您可以做的是为您想要执行的任务创建一个自己的task文件,并将其包含在您的剧本中(循环包含)。 这是由 @Konstantin 在以下示例中完成的:具有相同循环的多个 ansible 任务
额外:
不可用的原因
如果可以使用单个
loop
来完成多个任务,那么您必须确保将其应用于所有任务,例如:
- block:
task1
...
task2
...
loop:
- { lun: 'lun0', mountpoint: '/apps/mysql/binlog', diskname: 'binlog' }
- { lun: 'lun1', mountpoint: '/apps/mysql/innodb', diskname: 'innodb' }
示例:
(根据您的评论创建了一个示例,我认为这不是一个好的解决方案,但它是一个解决方案) 使用
set_fact
创建列表,然后将此列表传递到另一个 playbook。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 }}"
阅读文档后,我找到了实现此目的的方法。
正确的方法是使用 Ansible 的字典变量。
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 }}"
将任务移动到单独的文件 mountdisk.yml 并将字典传递给任务,如下所示
- include_tasks: "mountdisk.yml"
loop: "{{ raid_config }}"
loop_control:
loop_var: disk
tags: test
这里的一切都很棒。我添加了一些东西来使
parted
幂等,但很难将其脱离上下文发布,所以...这是我使用 OP 的脚本和 @shubham-jairath 的出色循环组合在一起的完整解决方案:
文件: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
- meta: end_play
when: partition.stdout != ""
- 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
文件:play/mountmyvmdisk.yml
---
- hosts: Mycoolhosts
gather_facts: true
become: true
vars:
disksToMount:
- lun: "lun0"
mountpoint: "/mnt/mycooldisk"
tasks:
- include_tasks: "mountdisk.yml"
loop: "{{ disksToMount }}"