【问题标题】:Run ansible task only once per each unique fact value每个唯一的事实值只运行一次 ansible 任务
【发布时间】:2019-02-21 03:14:45
【问题描述】:

我有一个动态清单,它为每个主机分配一个“事实”,称为“集群编号”。

事先不知道集群编号,但有一台或多台主机分配了相同的编号。该清单有数百台主机和 2-3 打唯一的集群编号。

我想为清单中的所有主机运行一个任务,但是我只想为每组共享相同“cluster_number”值的主机执行一次。为每个组选择哪个特定主机无关紧要。

我觉得应该有一个相对直接的方法来用 ansible 做到这一点,但不知道如何。我查看了 group_by、when、loop、delegate_to 等。但还没有成功。

【问题讨论】:

  • 感谢您查看 group_bywhen 等,但您如何分享这些尝试,以便我们可以调试代码而不是推测您是什么试图做。请务必包含您收到的实际错误消息,或该代码的不良结果

标签: ansible ansible-facts


【解决方案1】:

一个选项是

  • group_bycluster_number
  • run_once 簇号循环
  • 并从每个组中选择第一个主机。

例如给定 hosts

[test]
test01 cluster_number='1'
test02 cluster_number='1'
test03 cluster_number='1'
test04 cluster_number='1'
test05 cluster_number='1'
test06 cluster_number='2'
test07 cluster_number='2'
test08 cluster_number='2'
test09 cluster_number='3'
test10 cluster_number='3'
[test:vars]
cluster_numbers=['1','2','3']

下面的剧本

- hosts: all
  gather_facts: no
  tasks:
    - group_by: key=cluster_{{ cluster_number }}
    - debug: var=groups['cluster_{{ item }}'][0]
      loop:  "{{ cluster_numbers }}"
      run_once: true

给予

> ansible-playbook test.yml | grep groups
"groups['cluster_1'][0]": "test01", 
"groups['cluster_2'][0]": "test06", 
"groups['cluster_3'][0]": "test09",

在目标include_tasks(而不是在上面的循环中调试)和目标delegate_to执行任务

- set_fact:
    my_group: "cluster_{{ item }}"
- command: hostname
  delegate_to: "{{ groups[my_group][0] }}"

注意:从库存中收集列表cluster_numbers

cluster_numbers: "{{ hostvars|json_query('*.cluster_number')|unique }}"

【讨论】:

  • 您的解决方案需要使用 cluster_numbers 列表更新库存。我进一步考虑了这个想法,并添加了一个变量,该变量指定主机是否是其集群编号的“主”。这允许使用简短的“何时:”语句来限制任务范围。 tnx
  • 它没有。为简单起见,我将 cluster_numbers 放在库存中。获取列表很简单。
  • 我看到您使用 json_query 进行的更新。作为 ansible 的新手,我不会轻易想出那条线:)。我在动态清单中使用了类似的逻辑来挑选一个 cluster_controller。有了那个 var,剧本看起来更干净了。 Ansible 可能需要内置抽象来完成此类任务,例如run_once:。
  • “内置抽象... run_once: ”的用例可能是什么?恕我直言,它无助于解决您的问题。建议的剧本相当有效。 1) group_by 遍历所有主机和 2) 仅遍历 cluster-masters。
  • 在少数情况下,任务需要为一组共享相同特征的主机运行一次。集群、负载均衡器、分布式数据库节点通常由单个成员节点控制。另一种情况:为环境中存在的每个操作系统版本级别查询一次漏洞数据库。
【解决方案2】:

如果您不介意播放日志混乱,这里有一个方法:

- hosts: all
  gather_facts: no
  serial: 1
  tasks:
    - group_by:
        key: "single_{{ cluster_number }}"
      when: groups['single_'+cluster_number] | default([]) | count == 0

- hosts: single_*
  gather_facts: no
  tasks:
    - debug:
        msg: "{{ inventory_hostname }}"

serial: 1 对于重新评估每个主机的when 声明在第一场比赛中至关重要。

第一次玩后,每个集群都有 N 个组,其中只有一个主机。

【讨论】:

  • 这个剧本确实有效,但是它确实产生了大量的 PLAY 输出,并且 group_by 的串行执行对于大量主机来说有点慢。结合您和 Vladimir 的想法,我决定在动态清单中添加一个额外的 hostvar 以指定主机是否为“cluster_controller”。我确保每个集群编号只有一个主机具有 cluster_controller=true。对于少量库存,您的解决方案可以正常工作。 Благодарю за помощь, Константин。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-12
  • 2013-01-12
  • 2011-09-21
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多