Как сделать так, чтобы проверка Ansible запускалась только один раз в playbook?

В качестве меры предосторожности от использования устаревшего playbook я хотел бы убедиться, что у меня есть обновленная копия git checkout, прежде чем Ansible сможет что-либо изменить на серверах.

Вот как я пытался это сделать. Это действие находится в файле, включенном во все игровые книги:

- name: Ensure local git repository is up-to-date
  local_action: git pull
  register: command_result
  failed_when: "'Updating' in command_result.stdout"

Проблема в том, что эта команда запускается один раз для каждого узла, к которому подключается Ansible, а не только один раз для каждого запуска playbook. Как мне этого избежать?


person Dag Høidahl    schedule 27.02.2014    source источник


Ответы (2)


Обновлено

Когда я написал свой ответ (27 февраля 2014 г.), в Ansible не было встроенной поддержки для запуска задачи только один раз для каждой книги, не один раз для каждого затронутого хоста, который сценарий был запущен. Однако, как пишет tlo, поддержка для этого была введена с помощью _ 1_ в Ansible версии 1.7.0 (выпущен 6 августа 2014 г.). С помощью этой функции пример определения задачи из вопроса следует изменить на

- name: Ensure local git repository is up-to-date
  local_action: git pull
  run_once: true
  register: command_result
  failed_when: "'Updating' in command_result.stdout"

выполнить то, о чем просят.

Оригинальный ответ

[Следующий ответ был моим предложенным решением конкретной проблемы, заключающейся в том, чтобы убедиться, что локальная ветка git обновляется до того, как Ansible выполнит задачи playbook.]

Я написал следующий плагин обратного вызова Ansible, который позволит избежать выполнения playbook, если текущая ветка git не синхронизирована (либо отстает, либо расходится) с удаленной веткой. Чтобы использовать его, поместите следующий код в файл, подобный callback_plugins/require_updated_git_branch.py, в каталоге Ansible playbook верхнего уровня:

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import os
import re
import subprocess
import sys

from ansible.callbacks import display, banner


class CallbackModule(object):
    """Makes Ansible require that the current git branch is up to date.
    """
    env_var_name = 'IGNORE_OUTDATED_GIT_BRANCH'

    msg = 'OUTDATED GIT BRANCH: Your git branch is out of sync with the ' \
          'remote branch.  Please update your branch (git pull) before ' \
          'continuing, or skip this test by setting the environment ' \
          'variable {0}=yes.'.format(env_var_name)

    out_of_sync_re = re.compile(r'Your branch (is behind|and .* have diverged)',
                                re.MULTILINE)

    def __init__(self, *args, **kwargs):
        if os.getenv(self.env_var_name, 'no') == 'yes':
            self.disabled = True

    def playbook_on_start(self):
        subprocess.call(['git', 'fetch'])

        if self.out_of_sync_re.search(subprocess.check_output([
            'git', 'status', '--untracked-files=no'])):
            display(banner(self.msg), color='bright purple')
            sys.exit(1)

Например, когда локальная ветвь находится за удаленной ветвью, команда ansible-playbook site.yml прерывается раньше со следующим выводом:

 __________________________________________________________
/ OUTDATED GIT BRANCH: Your git branch is out of sync with \
| the remote branch. Please update your branch (git pull)  |
| before continuing, or skip this test by setting the      |
\ environment variable IGNORE_OUTDATED_GIT_BRANCH=yes.     /
 ----------------------------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

И, как подсказывает корова, чтобы отключить эту проверку, вы можете запустить такую ​​команду:

$ IGNORE_OUTDATED_GIT_BRANCH=yes ansible-playbook site.yml

Это решение не решает общую проблему предотвращения запуска любой задачи Ansible более одного раза, независимо от количества задействованных хостов, но оно гарантирует, что устаревшие playbooks не выполняются, и решает проблему, о которой вы упомянули относительно my предложение на основе псевдонима.

person Martin Thorsen Ranang    schedule 27.02.2014
comment
Технически run_once предназначен для каждой игры, а не для каждой пьесы. Если ваша книга содержит несколько пьес, например все включают одну и ту же роль, которая содержит задачу с run_once, эта задача будет запускаться один раз за каждую игру. - person Illya Moskvin; 05.05.2021

Начиная с версии 1.7 Ansible вы можете использовать run_once: true только для однократного выполнения задачи один хост.

person tlo    schedule 30.12.2015