git 如何让 Ansible 检查在剧本中只运行一次?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22070232/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 17:48:56  来源:igfitidea点击:

How to get an Ansible check to run only once in a playbook?

gitansible

提问by Dag H?idahl

As a safeguard against using an outdated playbook, I'd like to ensure that I have an updated copy of the git checkout before Ansible is allowed to modify anything on the servers.

为了防止使用过时的剧本,我想确保在 Ansible 被允许修改服务器上的任何内容之前,我有一个更新的 git checkout 副本。

This is how I've attempted to do it. This action is located in a file included by all play books:

这就是我尝试这样做的方式。此操作位于所有剧本都包含的文件中:

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

The problem is that this command is run once for each node Ansible connects to, instead of only once for each playbook run. How can I avoid that?

问题是这个命令为 Ansible 连接的每个节点运行一次,而不是每个 playbook 运行只运行一次。我怎样才能避免这种情况?

采纳答案by Martin Thorsen Ranang

Updated

更新

When I fist wrote my answer (2014-02-27), Ansible had no built-in support for running a task only onceper playbook, notonce per affected host that the playbook was run on. However, as tlo writes, support for this was introduced with run_once: truein Ansible version 1.7.0 (released on 2014-08-06). With this feature, the example task definition from the question should be changed to

当我开始写我的答案 (2014-02-27) 时,Ansible 没有内置支持每个剧本运行一次任务,而不是每个运行剧本的受影响主机一次。但是,正如tlo 所写run_once: trueAnsible 1.7.0 版(发布于 2014-08-06)中引入了对此的支持。使用此功能,问题中的示例任务定义应更改为

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

to accomplish what is asked for.

完成所要求的。

Original Answer

原答案

[The following answer was my suggested solution for the particular problem of making sure that the local git branch is updated before Ansible runs the tasks of a playbook.]

[对于确保在 Ansible 运行剧本任务之前更新本地 git 分支的特定问题,以下答案是我建议的解决方案。]

I wrote the following Ansible callback plugin that will avoid playbook execution if the current git branch is out of sync (is either behind or has diverged) with the remote branch. To use it, place the following code in a file like callback_plugins/require_updated_git_branch.pyin your top-level Ansible playbook directory:

我编写了以下 Ansible 回调插件,如果当前 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)

For example, when the local branch is behind the remote branch, the command ansible-playbook site.ymlhalts early with the following output:

例如,当本地分支在远程分支后面时,命令会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 |
                ||     ||

And, as the cow suggests, to turn off this check you can run the command like:

而且,正如牛建议的那样,要关闭此检查,您可以运行以下命令:

$ IGNORE_OUTDATED_GIT_BRANCH=yes ansible-playbook site.yml

This solution does not solve the general problem of avoiding to run any Ansible task more than once regardless of the number of hosts involved, but it ensures that outdated playbooks are not executed, and it handles the concern that you mentioned regarding my alias-based suggestion.

此解决方案不能解决避免多次运行任何 Ansible 任务而不管所涉及的主机数量如何的一般问题,但它确保不执行过时的剧本,并且它处理了您提到的关于我的基于别名的建议的问题.

回答by tlo

Since version 1.7 of Ansible you can use run_once: trueto only run a task one time and only on one host.

从 Ansible 1.7 版开始,您run_once: true只能在一台主机上仅运行一次任务