对主机组成员及其 host_vars

时间:2021-04-12 11:33:57

标签: ansible ansible-inventory

有人可以帮助我构建嵌套循环吗?

我正在创建简单的备份角色,它将为备份准备客户端服务器,它还将准备备份服务器。备份服务器将在定义的时间从客户端下载备份。我想为每个客户端定义不同的时间和不同的文件夹(通过 host_vars)。

我的工作流程:

  1. 备份服务器

    • 安装软件包
    • 创建备份用户
    • 创建备份目录
  2. 客户

    • 安装软件包
    • 将备份的服务器 ssh 密钥添加到 authorized_keys(有限制)
    • 一些 ssh 设置
    • 重新加载 sshd
  3. 备份服务器

    • 为下载备份设置 cron 作业(每个客户端都应该有自己的 cron 条目 - 不同的时间和不同的备份文件夹集)

我有这个角色的第一个版本,它被应用于服务器的客户端组。备份服务器是在 delegate_to: 语句的帮助下配置的。但是在备份服务器上创建 cron 文件存在问题,因为存在诸如“竞争条件”之类的东西。当 playbook 完成时,备份的服务器 cron 文件中只有一个随机条目。但我希望所有客户端服务器都应该有条目。我试图打开问题 https://github.com/ansible/ansible/issues/74189 - 我得到了答案,我应该更改对此问题的访问权限。

我的第二次尝试是重写 ansible 角色。然后我可以将它应用于备份服务器而不是客户端组。现在我在客户端服务器组上使用 delegate_to:

备份服务器上(简化的)预期 cron 作业的示例:

0 0 * * * backup -include /home --include /var/www --include /srv --exclude '**' backup.lab.local::/ /home/backup/srv1.lab.local
# -> similar entry for srv2
# -> similar entry for srv3

我的场景:

# hosts file
[backup_servers]
backup.lab.local

[testing_servers]
srv1.lab.local
srv2.lab.local
srv3.lab.local

host_vars 文件示例:

# host_vars/srv1.lab.local
backup_folders:
  - /home
  - /var/www
  - /srv

我坚持在备份服务器上创建 cron 条目的任务。我需要循环 groups['testing_servers'] 并且在这个循环中我需要创建另一个 hostvars[<each_host_from_group>]['backup_folder'] 循环。

请问怎么做?

2 个答案:

答案 0 :(得分:1)

我不会遍历 backup_folder,我会 join 这些值。

假设您正确循环 groups['testing_servers'] 主机,例如

0 0 * * * backup {{ ([''] + hostvars[item]['backup_folder']) | join(' --include ') }}  --exclude '**' backup.lab.local::/ /home/backup/{{ item }}

会给:

0 0 * * * backup --include /home --include /var/www --include /srv --exclude '**' backup.lab.local::/ /home/backup/srv1.lab.local

注意:这个奇怪的结构:([''] + hostvars[item]['backup_folder']) 是为了在列表的开头创建一个空元素,使其以 --include 开头,否则你会有

... backup /home --include /var/www --include /srv --exclude '**' ...
##        ^--- missing "--include " here

答案 1 :(得分:0)

Cron 模块和并行写入

关于提到的 GitHub 问题,您可以使用 throttle: 1 (documentation)

即您的 cron 剧本应包含:

  tasks:
    - name: "Set backup cron job"
      ansible.builtin.cron:
        name: "Backup cron job for {{ inventory_hostname }}"
        user: root
        minute: "{{ backup_minute }}"
        hour: "{{ backup_hour }}"
        day: "{{ backup_day }}"
        month: "{{ backup_month }}"
        weekday: "{{ backup_weekday }}"
        job: "rdiff-backup --create-full-path --remote-schema \"ssh -C -i /home/backup/.ssh/id_rsa -p {{ ansible_port | default(22) }} -o 'StrictHostKeyChecking no' \\%s rdiff-backup --server\" --include /path/to/dir --exclude '**' {{ ansible_host }}::/ /home/backup/{{ inventory_hostname }}"
      delegate_to: deb10.lab.local
      throttle: 1                       # <--------- THIS IS THE IMPORTANT LINE

嵌套循环

你提到的使用嵌套循环的另一种方式可以通过在 Ansible 中使用嵌套循环来完成,或者通过预先构建嵌套结构,然后对其进行迭代:

Ansible - 嵌套循环

Documentation

您可以按照文档所述在循环中构建循环,方法是将一个任务用作带有 include_tasks 模块的外循环,以及一个带有重命名的循环控制变量 (loop_var) 的循环。

如文档中的示例所示,您需要将其分成两个文件:

# main.yml tasks file
- include_tasks: inner.yml
  loop:
    - 1
    - 2
    - 3
  loop_control:
    loop_var: outer_item

# inner.yml tasks file
- name: Print outer and inner items
  ansible.builtin.debug:
    msg: "outer item={{ outer_item }} inner item={{ item }}"
  loop:
    - a
    - b
    - c

Jinja2 - 预生成结构

Documentation

使用产品过滤器创建列表列表:

['alice', 'bob'] |product(['clientdb', 'employeedb', 'providerdb'])|list

创造

[('alice', 'clientdb'), ('alice', 'employeedb'), ('alice', 'providerdb'), ('bob', 'clientdb'), ('bob', 'employeedb'), ('bob', 'providerdb')]

例如文档状态中的示例,您可以使用类似于以下的代码:

- name: Give users access to multiple databases
  community.mysql.mysql_user:
    name: "{{ item[0] }}"
    priv: "{{ item[1] }}.*:ALL"
    append_privs: yes
    password: "foo"
  loop: "{{ ['alice', 'bob'] |product(['clientdb', 'employeedb', 'providerdb'])|list }}"
相关问题