简体   繁体   English

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

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

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.问题是这个命令为 Ansible 连接的每个节点运行一次,而不是每个 playbook 运行只运行一次。 How can I avoid that?我怎样才能避免这种情况?

Updated更新

When I fist wrote my answer (2014-02-27), Ansible had no built-in support for running a task only once per playbook, not once per affected host that the playbook was run on.当我开始写我的答案 (2014-02-27) 时,Ansible 没有内置支持每个剧本运行一次任务,而不是每个运行剧本的受影响主机一次。 However, as tlo writes , support for this was introduced with run_once: true in Ansible version 1.7.0 (released on 2014-08-06).然而,正如tlo 所写,在 Ansible 1.7.0 版(2014 年 8 月 6 日发布)中通过run_once: true引入了run_once: true支持。 With this feature, the example task definition from the question should be changed to使用此功能,问题中的示例任务定义应更改为

- 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.我编写了以下 Ansible 回调插件,如果当前 git 分支与远程分支不同步(落后于或已经发散),它将避免剧本执行。 To use it, place the following code in a file like callback_plugins/require_updated_git_branch.py in your top-level Ansible playbook directory:要使用它,请将以下代码放入顶级 Ansible 剧本目录中的callback_plugins/require_updated_git_branch.py文件中:

#! /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.yml halts 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 任务而不管所涉及的主机数量如何的一般问题,但它确保不执行过时的剧本,并且它处理了您提到的关于我的基于别名的建议的问题.

从 Ansible 1.7 版开始,您可以使用run_once: true 仅在一台主机上运行一次任务

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM