使用Ansible的playbook将set_fact任务委托给所有主机应用

ansible.builtin.set_fact – 设置主机变量和事实。 — Ansible文档

在ansible-playbook中,有一个名为set_fact的模块,可以设置新的变量。

模块的概述如下。

・在这个模块中,你可以设置新的变量。
・变量会根据每个主机的设置模块检测到的事实来设置。
・这些变量可以在ansible-playbook执行期间的随后的play中使用。
・要使用事实缓存在执行之间保存变量,请将cacheable设置为yes。
・通过set_fact创建的变量的优先级取决于是否被缓存。
・根据标准Ansible变量的优先级规则,由于其他许多类型的变量的优先级更高,所以这个值有可能被覆盖。
・该模块也支持Windows目标。

我认为在ansible运行时获取的输出并后续将其保存为变量的情况是相当常见的。

正如摘要中所述,这些变量是针对每个主机进行设置的。

如果想要在另一台主机上使用设置在特定主机上的set_fact,需要使用delegate_to指定并将其传递给其他主机。

delegate_to 的含义

任务运行控制:委派和本地操作的控制 – Ansible文档

使用delegated_to可以在不同的主机上执行指定的任务。通常情况下,Playbook会在与hosts匹配的主机上执行任务,但使用delegated_to可以在hosts之外或特定的主机上执行任务。

游戏规则的例子 de

我将尝试对属于Ubuntu组的Ubuntu01和Ubuntu02使用set_fact。

    • ホストがubuntu01 → ubuntu01: definedのみ

 

    ホストがubuntu02 → ubuntu02: definedのみ

设定。

库存

all:
  children:
    ubuntu:
      hosts:
        ubuntu01:
        ubuntu02:

如果不使用delegate_to(委托给)Playbook的话

我們將創建一個Playbook,其中使用set_fact為變量進行定義,已定義的變量將被標記為defined,未定義的變量將被標記為undefined。

---
- hosts: ubuntu
  tasks:
    - name: set_fact to ubuntu01
      set_fact:
        ubuntu01: defined
      when: inventory_hostname == "ubuntu01"
    - name: set_fact to ubuntu02
      set_fact:
        ubuntu02: defined
      when: inventory_hostname == "ubuntu02"
    - name: debug set_fact
      debug:
        msg: |
          "ubuntu01 is {{ ubuntu01 | default('undefined') }}"
          "ubuntu02 is {{ ubuntu02 | default('undefined') }}"

执行结果

$ ansible-playbook set_fact.yml -i inventory.yml -v

PLAY [ubuntu] *******************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************
ok: [ubuntu02]
ok: [ubuntu01]

TASK [set_fact to ubuntu01] *****************************************************************************************************************
ok: [ubuntu01] => {"ansible_facts": {"ubuntu01": "defined"}, "changed": false}
skipping: [ubuntu02] => {"changed": false, "skip_reason": "Conditional result was False"}

TASK [set_fact to ubuntu02] *****************************************************************************************************************
skipping: [ubuntu01] => {"changed": false, "skip_reason": "Conditional result was False"}
ok: [ubuntu02] => {"ansible_facts": {"ubuntu02": "defined"}, "changed": false}

TASK [debug set_fact] **************************************************************************************************************
ok: [ubuntu01] => {
    "msg": "\"ubuntu01 is defined\"\n\"ubuntu02 is undefined\"\n"
}
ok: [ubuntu02] => {
    "msg": "\"ubuntu01 is undefined\"\n\"ubuntu02 is defined\"\n"
}

PLAY RECAP **********************************************************************************************************************************
ubuntu01                   : ok=3    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
ubuntu02                   : ok=3    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

在ubuntu01中,我们发现以下是正确的(ubuntu02则相反)。

    • ubuntu01: defined

 

    ubuntu02: undefined

使用委派给(delegate_to)的场景

让我们尝试使用 delegate_to 在所有主机之间传递变量。

---
- hosts: ubuntu
  tasks:
    - name: set_fact to ubuntu01
      set_fact:
        ubuntu01: defined
      delegate_to: "{{ item }}" # 変数を渡すホスト
      delegate_facts: true # fact変数の更新する場合trueにする必要がある
      with_items: "{{ groups['all'] }}" # 全ホストに受け渡す
      when: inventory_hostname == "ubuntu01"
    - name: set_fact to ubuntu02
      set_fact:
        ubuntu02: defined
      delegate_to: "{{ item }}" # 
      delegate_facts: true
      with_items: "{{ groups['all'] }}"
      when: inventory_hostname == "ubuntu02"
    - name: debug set_fact
      debug:
        msg: |
          "ubuntu01 is {{ ubuntu01 | default('undefined') }}"
          "ubuntu02 is {{ ubuntu02 | default('undefined') }}"

执行结果

ansible-playbook set_fact.yml -i inventory.yml -v
Using /Users/yukihisa/.ghq/github.com/ymmmtym/terraform-cloud-oci/ansible.cfg as config file

PLAY [ubuntu] *******************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************
ok: [ubuntu02]
ok: [ubuntu01]

TASK [set_fact to ubuntu01] *****************************************************************************************************************
ok: [ubuntu01 -> ubuntu01] => (item=ubuntu01) => {"ansible_facts": {"ubuntu01": "defined"}, "ansible_loop_var": "item", "changed": false, "item": "ubuntu01"}
ok: [ubuntu01 -> ubuntu02] => (item=ubuntu02) => {"ansible_facts": {"ubuntu01": "defined"}, "ansible_loop_var": "item", "changed": false, "item": "ubuntu02"}
skipping: [ubuntu02] => (item=ubuntu01)  => {"ansible_loop_var": "item", "changed": false, "item": "ubuntu01", "skip_reason": "Conditional result was False"}
skipping: [ubuntu02] => (item=ubuntu02)  => {"ansible_loop_var": "item", "changed": false, "item": "ubuntu02", "skip_reason": "Conditional result was False"}

TASK [set_fact to ubuntu02] *****************************************************************************************************************
skipping: [ubuntu01] => (item=ubuntu01)  => {"ansible_loop_var": "item", "changed": false, "item": "ubuntu01", "skip_reason": "Conditional result was False"}
skipping: [ubuntu01] => (item=ubuntu02)  => {"ansible_loop_var": "item", "changed": false, "item": "ubuntu02", "skip_reason": "Conditional result was False"}
ok: [ubuntu02 -> ubuntu01] => (item=ubuntu01) => {"ansible_facts": {"ubuntu02": "defined"}, "ansible_loop_var": "item", "changed": false, "item": "ubuntu01"}
ok: [ubuntu02 -> ubuntu02] => (item=ubuntu02) => {"ansible_facts": {"ubuntu02": "defined"}, "ansible_loop_var": "item", "changed": false, "item": "ubuntu02"}

TASK [debug set_fact] ***********************************************************************************************************************
ok: [ubuntu01] => {
    "msg": "\"ubuntu01 is defined\"\n\"ubuntu02 is defined\"\n"
}
ok: [ubuntu02] => {
    "msg": "\"ubuntu01 is defined\"\n\"ubuntu02 is defined\"\n"
}

PLAY RECAP **********************************************************************************************************************************
ubuntu01                   : ok=3    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
ubuntu02                   : ok=3    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

根据set_fact任务的内容,可以看出ubuntu01和ubuntu02都已经定义了这两个变量。

这次通过 group[‘all’] 将数据传递给了所有主机,但也可以通过 IP (主机名) 来指定单个主机。此外,不仅可以在 set_fact 中使用,当然也可以在其他模块中使用。

参考来源

    • <Ansible>「delegate_to」ディレクティブの使い方 – Qiita

 

    [Ansible] playをまたいだ変数保持をdelegate_toとfact変数で行う (Ansibleでkubeadmのworkerノード追加) – zaki work log
bannerAds