想为你的Ansible剧本取一个随机数?还想在接下来的运行中保持系统的等幂性?这里有一个答案。
假如,你要为一大批服务器设置cron任务,却不想让它们同时启动,你可以这样设置分钟数:
minutes: "{{ 60 | random }}"
但是,如此生成的随机(分钟)数在运行之后,会产生许多不必要的任务变化。到了Ansbile 2.3,事情有了改观。
Ansible 2.3的改进
在Ansible的2.3版本中,可以从一个“种子”里获取随机。这样就可以得到一个随机但等幂的数值:
"{{ 59 |random(seed=inventory_hostname) }} * * * * root /script/from/cron"
以前版本的Ansible怎么办?
你可以根据任何一个变量或真值(Ansible从主机上采集到的FACT数据)来编造一个伪随机数。如,你可以用inventory_hostname来在各不同的主机上生成“随机数”,还能保证剧本的运行等幂。在剧本中,这样写:
minutes: "{{ ( inventory_hostname | hash | list | map('int',0,16) | sum ) % 60 }}"
魔术可以这样解释:
第1步:获取主机名 inventory_hostname,如:myserver
第2步:将其序列化,取得一个哈希数,如"c3a7a35a28dcce27daad3a7a90caad99b967a904"
第3步:将其拆分为单字数组[["c","3","a",...]
第4步:每个单字实际上是一个16进制数字
第5步:把这些数字转成十进制
第6步:将所有的数字加起来
第7步:总和除以60之后的余数,就是最终的“随机数”
于是,Ansible的剧本中,你的cron任务可能会这样写:
cron:
name: myjob
job: myscript.sh
minute: "{{ ( inventory_hostname | hash | list | map('int',0,16) | sum ) % 60 }}"
hour: "{{ (( inventory_hostname | hash | list | map('int',0,16) | sum ) % 2) + 6 }}"
这样,就可以在6:00 - 7:59之间随机一个分钟点运行myscript.sh程序,还能保证剧本运行结果的等幂性。
这篇文章是本人翻译过来的,原作请见链接。