如何使用ansible循环挂载多个磁盘

How to mount multiple disks in a loop using ansible

我最近才开始使用 Ansible。我正在尝试在使用 terraform 连接的 azure VM 上安装 4 个磁盘。每个磁盘都传递了一个 LUN 编号,我正在使用该 LUN no.and 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 variable is not defined 错误。有什么方法可以将卷名设置为全局以便下一个剧本可以访问它或我如何改进此代码?

首先我不是 ansible 方面的专家,但是你想要做的看起来是:

  • 对多个任务使用相同的循环。

我认为这是不可能的。另一件事是 loop-variables 仅适用于具有匹配缩进的任务,在您的情况下:blockinfile.

您可以做的是为您要执行的任务创建一个自己的 task 文件,并将其包含在您的剧本中(循环包含)。 这是由 @Konstantin 在以下示例中完成的:Multiple ansible task with same loop

额外:
Reason why it is NOT available
如果可以将单个 loop 用于多项任务,那么您必须确保将其应用于所有任务,例如:

- block:
    task1
     ...
    task2
     ...
  loop:
    - { lun: 'lun0', mountpoint: '/apps/mysql/binlog', diskname: 'binlog' }
    - { lun: 'lun1', mountpoint: '/apps/mysql/innodb', diskname: 'innodb' }

示例:

(根据您的评论创建了一个示例,我认为这不是一个好的解决方案,但它是一个解决方案) 使用 set_fact 创建一个列表,然后将此列表传递给另一个剧本。
使用我现有的示例:

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
这样我就能够获取 lun 和挂载点作为 disk.lun 和 disk.mountpoint。 注意:在使用 include_tasks 选项时,您需要在每个任务中单独传递标签关键字(如果您正在使用一个)。