主机组成员及其 host_vars 的 Ansible 嵌套循环
Ansible nested loop over host group members and their host_vars
谁能帮我构造嵌套循环?
我正在创建简单的备份角色,它将为备份准备客户端服务器,它也会准备备份服务器。备份服务器将在指定时间从客户端下载备份。我想为每个客户端定义不同的时间和不同的文件夹(by host_vars)。
我的工作流程:
备份服务器
- 安装包
- 创建备份用户
- 创建备份目录
客户端
- 安装包
- 将备份的服务器 ssh 密钥添加到 authorized_keys(有限制)
- 一些ssh设置
- 重新加载 sshd
备份服务器
- 为下载备份设置 cron 作业(每个客户端都应该有自己的 cron 条目 - 不同的时间和不同的备份文件夹集)
我有这个角色的第一个版本,它应用于服务器的客户端组。备份服务器是在 delegate_to:
语句的帮助下配置的。但是在备份服务器上创建 cron 文件有问题,因为有类似 'race condition' 的东西。当 playbook 完成时,备份的服务器 cron 文件中只有一个随机条目。但我希望所有客户端服务器都应该有条目。我试图打开问题 https://github.com/ansible/ansible/issues/74189 - 我得到了答案,我应该更改对此问题的访问权限。
第二次尝试是重写ansible role。然后我可以将它应用于备份服务器而不是客户端组。现在我在客户端服务器组上使用 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']
.
请问怎么做?
我不会遍历 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'])
是为了在列表的开头创建一个空元素,使其以 [=17= 开头],否则你将有
... backup /home --include /var/www --include /srv --exclude '**' ...
## ^--- missing "--include " here
Cron 模块和并行写入
关于提到的 GitHub 问题,您可以通过使用 throttle: 1
(documentation)[= 解决这个问题(在一台主机上并行写入 crontab 文件) 22=]
即你的 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 - 嵌套循环
您可以按照文档所述构建循环中的循环,方法是使用一个任务作为带有 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 - 预生成结构
使用产品过滤器创建列表列表:
['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 }}"
谁能帮我构造嵌套循环?
我正在创建简单的备份角色,它将为备份准备客户端服务器,它也会准备备份服务器。备份服务器将在指定时间从客户端下载备份。我想为每个客户端定义不同的时间和不同的文件夹(by host_vars)。
我的工作流程:
备份服务器
- 安装包
- 创建备份用户
- 创建备份目录
客户端
- 安装包
- 将备份的服务器 ssh 密钥添加到 authorized_keys(有限制)
- 一些ssh设置
- 重新加载 sshd
备份服务器
- 为下载备份设置 cron 作业(每个客户端都应该有自己的 cron 条目 - 不同的时间和不同的备份文件夹集)
我有这个角色的第一个版本,它应用于服务器的客户端组。备份服务器是在 delegate_to:
语句的帮助下配置的。但是在备份服务器上创建 cron 文件有问题,因为有类似 'race condition' 的东西。当 playbook 完成时,备份的服务器 cron 文件中只有一个随机条目。但我希望所有客户端服务器都应该有条目。我试图打开问题 https://github.com/ansible/ansible/issues/74189 - 我得到了答案,我应该更改对此问题的访问权限。
第二次尝试是重写ansible role。然后我可以将它应用于备份服务器而不是客户端组。现在我在客户端服务器组上使用 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']
.
请问怎么做?
我不会遍历 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'])
是为了在列表的开头创建一个空元素,使其以 [=17= 开头],否则你将有
... backup /home --include /var/www --include /srv --exclude '**' ...
## ^--- missing "--include " here
Cron 模块和并行写入
关于提到的 GitHub 问题,您可以通过使用 throttle: 1
(documentation)[= 解决这个问题(在一台主机上并行写入 crontab 文件) 22=]
即你的 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 - 嵌套循环
您可以按照文档所述构建循环中的循环,方法是使用一个任务作为带有 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 - 预生成结构
使用产品过滤器创建列表列表:
['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 }}"