Задача
Задача — одна запись списка tasks: в Destiny или сценарии: module: с его params: и ключами вокруг (register:, when:, loop:, …). Полная грамматика — на странице Destiny. Здесь — что происходит со входом задачи, её отрендеренными params:, когда одна задача идёт на много хостов.
Вход по хостам
Заголовок раздела «Вход по хостам»Задачи рендерит Keeper; Soul получает значения, а не выражения. Когда задача идёт на несколько хостов, вход у хостов может различаться: ${ soulprint.self.sid }, vars самого хоста, loop: по фактам хоста. Правило — четыре шага.
1. Рендер — для каждого хоста
Заголовок раздела «1. Рендер — для каждого хоста»Keeper рендерит params: задачи отдельно для каждого хоста, в контексте этого хоста: soulprint.self.*, vars хоста, переменные цикла. Так для каждой задачи, в том числе для той, в чьих params нет ни одного выражения.
2. Сравнение — целиком
Заголовок раздела «2. Сравнение — целиком»После рендера Keeper сравнивает params каждого хоста с params первого (хосты упорядочены по SID):
- все совпали — у задачи один вход на всех хостов. Это обычный случай, и ничего по хостам не хранится;
- не совпал хотя бы один — у задачи полный вход для каждого хоста, включая совпавшие. Частичная карта отправила бы пропущенным хостам значения первого — ровно та молчаливая подмена, от которой это правило защищает.
Ключ, который есть у одного хоста и отсутствует у другого, — тоже расхождение. Одно исключение: у core.file.rendered render_context шаблона (факты, которые шаблон читает через .self) едет по хостам отдельно и в сравнении не участвует.
3. Отправка — по хосту
Заголовок раздела «3. Отправка — по хосту»Каждый хост получает своё сообщение, поэтому каждая машина получает ровно свой вход. На проводе ничего не склеивается.
4. Показ — один раз, с <per-host>
Заголовок раздела «4. Показ — один раз, с <per-host>»План прогона — то, что показывают деталь прогона в веб-UI и GET /v1/incarnations/{id}/runs/{apply_id}/tasks, — хранит одну карту params на задачу: вход первого хоста. Перед записью идут два прохода, в таком порядке:
- маскирование — каждое запечатанное значение (
vault(), секретный input, …) заменяется маской; - пометка — каждый ключ верхнего уровня, значение которого у хостов различается, заменяется на
<per-host>.
Значит, <per-host> — пометка показа, а не маска: она говорит «значений несколько», а не «значение секретное». Ключи, совпавшие у всех хостов, видны как есть. Замаскированное остаётся маской — маска важнее пометки. Сравнение только по верхнему уровню: если внутри вложенной карты различается одно поле, помечается весь ключ верхнего уровня.
Пример — задача write marker на трёх хостах:
- name: write marker module: core.file.present params: path: /tmp/demo-marker content: '${ soulprint.self.sid }'хост soul-1 получает: {path: /tmp/demo-marker, content: soul-1}хост soul-2 получает: {path: /tmp/demo-marker, content: soul-2}хост soul-3 получает: {path: /tmp/demo-marker, content: soul-3}деталь прогона: {path: /tmp/demo-marker, content: <per-host>}Задача вроде cmd: hostname имеет одинаковый вход на всех хостах и показывается как есть. Различается её вывод, и деталь прогона показывает вывод каждого хоста (stdout, stderr, exit_code) в его собственной строке.
Что не хранится
Заголовок раздела «Что не хранится»Входы по хостам не сохраняются: после отправки в плане прогона остаётся только помеченная карта, и фактический вход хоста из прогона не прочитать. Смотрите результат на самом хосте или его вывод. Показ входа каждого хоста в детали прогона запланирован.