我有一个包含 3 个盒子的环境,部分安装作业创建一个备份脚本和一个关联的 cron 作业来运行该脚本。目前,该作业仅进入 01 实例并每小时运行一次。
- name: Create Backup script cron job
cron:
name: "S3 Backup"
minute: "0"
hour: "{{ backup_frequency }}"
job: "{{ app_home_dir }}/tools/aws_s3_backup.sh"
when: inventory_hostname in groups['admin']
become: true
我希望拥有它,以便脚本可以运行到所有 3 个实例上,并在所有三个实例上创建 cronjob,但相应的框仅每 3 小时运行一次...
Box 1 ... hour : 01,04,07,10,13,16,19,22
Box 2 ... hour : 02,05,08,11,14,17,20,23
Box 3 ... hour : 03,06,09,12,15,18,21,00
我知道获取相关时间的数学理论 - 即获取盒子编号,然后在计数器上对 0-23 进行模 3 循环,看看它是否等于 {box num},如果是,则将其包含在小时列表中盒子。
但是,我不知道这是否需要通过 Jinja 完成,还是可以直接在 Ansible 代码本身中完成?然后怎么办?
如有任何帮助,我们将不胜感激!
假设您的主机名类似于
box-1
、box-2
等,您可以执行以下操作:
- hosts: all
gather_facts: false
tasks:
- set_fact:
backup_frequency: >-
{{ range(box_num|int, 25, 3)|join(", ") }}
vars:
box_num: >-
{{ inventory_hostname.split('-')[1]|int }}
- debug:
var: backup_frequency
这个 几乎 可以工作并为
backup_frequency
生成如下所示的值:
ok: [box-1] => {
"backup_frequency": "1, 4, 7, 10, 13, 16, 19, 22"
}
ok: [box-2] => {
"backup_frequency": "2, 5, 8, 11, 14, 17, 20, 23"
}
ok: [box-3] => {
"backup_frequency": "3, 6, 9, 12, 15, 18, 21, 24"
}
请注意,最后的
24
是错误的 box-3
。如果 Ansible 有 modulo
函数,我们可以解决这个问题……它没有,但我们可以通过将以下代码放入 filter_plugins/filters.py
中来提供一个:
def filter_modulo(v, mod):
return v % mod
class FilterModule:
def filters(self):
return {
'modulo': filter_modulo,
}
这让我们可以写:
- hosts: all
gather_facts: false
tasks:
- set_fact:
backup_frequency: >-
{{ range(box_num|int, 25, 3)|map('modulo', 24)|join(", ") }}
vars:
box_num: >-
{{ inventory_hostname.split('-')[1]|int }}
- debug:
var: backup_frequency
产生:
ok: [box-1] => {
"backup_frequency": "1, 4, 7, 10, 13, 16, 19, 22"
}
ok: [box-2] => {
"backup_frequency": "2, 5, 8, 11, 14, 17, 20, 23"
}
ok: [box-3] => {
"backup_frequency": "3, 6, 9, 12, 15, 18, 21, 0"
}
...这就是你想要的。
大括号内发生的逻辑,采用 jinja 语法。
看起来像伪的
hour: {{ box_name | regex'[0-9]'| to_int | modulo(3) }}
设置频率,获取小时范围并重新排列列表
freq: "{{ ansible_play_hosts_all|length }}"
ranges: |
[{% for start in range(0, freq|int) %}
{{ range(start|int, 24, freq|int) }},
{% endfor %}]
ranges0: "{{ ranges[1:] + [ranges.0] }}"
给予
ranges0:
- [1, 4, 7, 10, 13, 16, 19, 22]
- [2, 5, 8, 11, 14, 17, 20, 23]
- [0, 3, 6, 9, 12, 15, 18, 21]
获取索引
index: "{{ ansible_play_hosts_all.index(inventory_hostname) }}"
并设置时间
- debug:
msg: "hour: {{ ranges0[index|int]|join(',') }}"
给予
ok: [box-1] =>
msg: 'hour: 1,4,7,10,13,16,19,22'
ok: [box-2] =>
msg: 'hour: 2,5,8,11,14,17,20,23'
ok: [box-3] =>
msg: 'hour: 0,3,6,9,12,15,18,21'
用于测试的完整剧本示例
- hosts: box-1,box-2,box-3
vars:
freq: "{{ ansible_play_hosts_all|length }}"
ranges: |
[{% for start in range(0, freq|int) %}
{{ range(start|int, 24, freq|int) }},
{% endfor %}]
ranges0: "{{ ranges[1:] + [ranges.0] }}"
index: "{{ ansible_play_hosts_all.index(inventory_hostname) }}"
tasks:
- debug:
var: ranges0|to_yaml
run_once: true
- debug:
msg: "hour: {{ ranges0[index|int]|join(',') }}"