Идемпотенция и случайные величины в Ansible

есть ли способ гарантировать идемпотентность для playbooks, которые используют случайно сгенерированные переменные?

например, я хочу настроить мои crontabs для запуска писем на нескольких серверах в разное время, поэтому я создаю случайные целые числа с помощью модуля set_fact ansible:

  tasks:
  - set_fact:
      first_run_30="{{ 30 | random }}"
    run_once: yes

затем примените эти сгенерированные переменные к моему crontab, используя ansible следующим образом:

   - 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'

Это очень хорошо работает, однако, принцип indempotence анзибль, я верю, разбито используя эту стратегию, потому что каждый раз, когда игра сделана, вы видите изменения:

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

если есть обходной путь, или, возможно, беспомощность просто не будет возможно в моем сценарии, я хотел бы знать.

3 ответов


вместо случайного значения вы можете получить что-то, связанное с узлом, например хэш имени хоста или последний байт 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 с:

  1. разные минуты на разных целевых серверах
  2. разные минуты для разных часов на одном сервере (случайность)
  3. в та же минута в тот же день и сервер при многократном запуске Ansible (idempotence)

Требуется 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 }}