Ansible 中的幂等性和随机变量
Idempotence and Random Variables in Ansible
有没有办法保证使用随机生成变量的剧本的幂等性?
例如,我想设置我的 crontabs 在不同时间触发多个服务器上的电子邮件,所以我使用 ansible 的 set_fact 模块创建随机整数:
tasks:
- set_fact:
first_run_30="{{ 30 | random }}"
run_once: yes
然后像这样使用 ansible 将这些生成的变量应用到我的 crontab:
- name: Setup cron30job
cron: name=cron30job minute={{first_run_30}},{{first_run_30 | int + 30}} job='/bin/bash /cron30job.sh' state=present user=root
environment:
MAILTO: 'me@somelist.com'
MAILFROM: 'me@somehost.com'
这非常有效,但是,我认为使用这种策略会破坏 ansible 的幂等性原则,因为每次播放时你都会看到一个变化:
TASK: [Setup cron30job] *****************************************
changed: [127.0.0.1]
此外,在 crontab 中,在三个单独的运行期间每次都在 root 下检查:
[ansible]# cat /var/spool/cron/root
#Ansible: cron30job
5,35 * * * * /bin/bash /sw/test/cron30job.sh
#Ansible: cron30job
9,39 * * * * /bin/bash /sw/test/cron30job.sh
#Ansible: cron30job
6,36 * * * * /bin/bash /sw/test/cron30job.sh
如果有解决方法,或者在我的情况下不可能实现幂等,我想知道。
您可以获得与节点相关的内容,而不是随机值,例如主机名的哈希值或 IP 地址的最后一个字节。
这是一个例子:
- name: Get a pseudo-random minute
shell: expr $((16#`echo "{{inventory_hostname}}" | md5sum | cut -c 1-4`)) % 30
register: minute
changed_when: false
从 Ansible 2.3 版开始,可以从种子初始化随机数生成器。这样,您可以创建随机但幂等的数字:
"{{ 59 |random(seed=inventory_hostname) }} * * * * root /script/from/cron"
我使用此模式生成随机的 cron 启动时间:
- 不同目标服务器上的分钟数不同
- 同一服务器上不同日期的不同分钟数(随机性)
- 同一天同一分钟,服务器重复运行 Ansible(幂等)
需要 Ansible >=2.3:
cron:
name: "{{some_name}}_{{item.day}}"
state: present
job: "{{some_job}}"
weekday: "{{item.day}}"
hour: "{{item.hour}}"
minute: "{{59|random(seed=inventory_hostname + item.dow)}}"
with_items:
- { day: 0, hour: 3, dow: "sunday" }
- { day: 1, hour: 7, dow: "monday" }
- { day: 2, hour: 1, dow: "tuesday" }
- { day: 3, hour: 5, dow: "wednesday" }
- { day: 4, hour: 2, dow: "thursday" }
- { day: 5, hour: 4, dow: "friday" }
- { day: 6, hour: 7, dow: "saturday" }
以防万一您没有可用的 ansible >= 2.3
,使用 jinja2 的散列方法:
{{ (inventory_hostname |hash('md5')|int(0, 16)) % 60 }}
有没有办法保证使用随机生成变量的剧本的幂等性?
例如,我想设置我的 crontabs 在不同时间触发多个服务器上的电子邮件,所以我使用 ansible 的 set_fact 模块创建随机整数:
tasks:
- set_fact:
first_run_30="{{ 30 | random }}"
run_once: yes
然后像这样使用 ansible 将这些生成的变量应用到我的 crontab:
- name: Setup cron30job
cron: name=cron30job minute={{first_run_30}},{{first_run_30 | int + 30}} job='/bin/bash /cron30job.sh' state=present user=root
environment:
MAILTO: 'me@somelist.com'
MAILFROM: 'me@somehost.com'
这非常有效,但是,我认为使用这种策略会破坏 ansible 的幂等性原则,因为每次播放时你都会看到一个变化:
TASK: [Setup cron30job] *****************************************
changed: [127.0.0.1]
此外,在 crontab 中,在三个单独的运行期间每次都在 root 下检查:
[ansible]# cat /var/spool/cron/root
#Ansible: cron30job
5,35 * * * * /bin/bash /sw/test/cron30job.sh
#Ansible: cron30job
9,39 * * * * /bin/bash /sw/test/cron30job.sh
#Ansible: cron30job
6,36 * * * * /bin/bash /sw/test/cron30job.sh
如果有解决方法,或者在我的情况下不可能实现幂等,我想知道。
您可以获得与节点相关的内容,而不是随机值,例如主机名的哈希值或 IP 地址的最后一个字节。
这是一个例子:
- name: Get a pseudo-random minute
shell: expr $((16#`echo "{{inventory_hostname}}" | md5sum | cut -c 1-4`)) % 30
register: minute
changed_when: false
从 Ansible 2.3 版开始,可以从种子初始化随机数生成器。这样,您可以创建随机但幂等的数字:
"{{ 59 |random(seed=inventory_hostname) }} * * * * root /script/from/cron"
我使用此模式生成随机的 cron 启动时间:
- 不同目标服务器上的分钟数不同
- 同一服务器上不同日期的不同分钟数(随机性)
- 同一天同一分钟,服务器重复运行 Ansible(幂等)
需要 Ansible >=2.3:
cron:
name: "{{some_name}}_{{item.day}}"
state: present
job: "{{some_job}}"
weekday: "{{item.day}}"
hour: "{{item.hour}}"
minute: "{{59|random(seed=inventory_hostname + item.dow)}}"
with_items:
- { day: 0, hour: 3, dow: "sunday" }
- { day: 1, hour: 7, dow: "monday" }
- { day: 2, hour: 1, dow: "tuesday" }
- { day: 3, hour: 5, dow: "wednesday" }
- { day: 4, hour: 2, dow: "thursday" }
- { day: 5, hour: 4, dow: "friday" }
- { day: 6, hour: 7, dow: "saturday" }
以防万一您没有可用的 ansible >= 2.3
,使用 jinja2 的散列方法:
{{ (inventory_hostname |hash('md5')|int(0, 16)) % 60 }}