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

Posted

技术标签:

【中文标题】如何使用 ansible 在一个循环中挂载多个磁盘【英文标题】:How to mount multiple disks in a loop using ansible 【发布时间】:2020-11-15 21:09:06 【问题描述】:

我最近才开始使用 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 变量未定义错误。有没有办法将volumename设置为全局以便下一个剧本可以访问它或者我如何改进这个代码?

【问题讨论】:

【参考方案1】:

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

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

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

您可以做的是为您要执行的任务创建一个自己的任务-文件,并将其包含在您的剧本中(循环包含)。 这已由@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 "


【讨论】:

谢谢,我刚试过,是的,你是对的 include_tasks 只是循环多个任务的方法,但问题仍然是循环传递动态变量,如“lun”并构建一个变量volumename 需要在任务中进一步使用,而 Ansible 似乎并不擅长。不确定是否有更好的方法来做到这一点。 不确定我是否关注。您当然可以使用 set_fact 创建一个新变量,该变量可以被另一个剧本使用。 (我可以使用调试添加一个不太有用的示例,看看它是否可以理解)- 您下面的解决方案要好得多。谢谢。【参考方案2】:

通读文档后,我找到了实现这一目标的方法。

正确的方法是使用 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 选项时,您需要在每个任务中分别传递标签关键字(如果您使用的是一个)。

【讨论】:

以上是关于如何使用 ansible 在一个循环中挂载多个磁盘的主要内容,如果未能解决你的问题,请参考以下文章

如何将一个磁盘上的目录挂载到另一个目录下

FAQ如何在CentOS下挂载磁盘?

LINUX如何将磁盘永久挂载到一个文件夹下面呢?

LINUX如何将磁盘永久挂载到一个文件夹下面呢?

使用 Ansible 复制多个文件

多个硬盘挂载到同一个目录