【问题标题】:How to delegate facts to localhost from a play targeting remote hosts如何从针对远程主机的游戏中将事实委托给 localhost
【发布时间】:2021-03-08 06:41:42
【问题描述】:

ansible 版本:2.9.16 在 RHEL 7.9 python ver = 2.7.5 上运行,目标是 windows 2016 服务器。 (对于 linux 目标服务器也应该表现相同)

编辑:切换到在清单中使用主机特定变量以避免混淆,我只是试图打印组的主机名。即使在这里,它也很简单。假设 var1 是为每个服务器动态获取的,而不是在清单文件中声明。

我的剧本有两个剧本。一个针对 3 个远程服务器(注意:串行:0 即并发),另一个仅针对本地主机。在 play1 中,我尝试使用 delegate_facts 和 delegate_to 将从每个主机获得的事实委托给 localhost。目的是将这些事实委托给单个主机( localhost ),以便稍后在以 localhost 为目标的 play2(使用 hostvars)中使用它。但奇怪的是那不起作用。它只有来自 Play1 的最后一个主机的信息。

任何帮助将不胜感激。

我的库存文件 inventory/test.ini 如下所示:

[my_servers]
svr1 var1='abc'
svr2 var1='xyz'
svr3 var1='pqr'

我的代码:

## Play1
- name: Main play  that runs against multiple remote servers and builds a list.
  hosts: 'my_servers'  # my inventory group that contains 3 servers svr1,svr2,svr3
  any_errors_fatal: false
  ignore_unreachable: true
  gather_facts: true
  serial: 0

  tasks:

      - name: initialize my_server_list as a list and delegate to localhost 
        set_fact:
          my_server_list: []
        delegate_facts: yes
        delegate_to: localhost

      - command: /root/complex_script.sh
        register: result

      - set_fact:
        my_server_list: "{{ my_server_list + hostvars[inventory_hostname]['result.stdout'] }}"
        # run_once: true  ## Commented as I need to query the hostvars for each host where this executes.
  delegate_to: localhost
  delegate_facts: true





      - name: "Print list - 1"
        debug:
          msg: 
            - "{{ hostvars['localhost']['my_server_list']  | default(['NotFound']) | to_nice_yaml }}" 
        # run_once: true

      - name: "Print list - 2"
        debug:
          msg: 
            - "{{ my_server_list | default(['NA']) }}" 


## Play2
- name: Print my_server_list which was built in Play1
  hosts: localhost
  gather_facts: true
  serial: 0

  tasks:

      - name: "Print my_server_list without hostvars "
        debug:
          msg: 
            - "{{ my_server_list  | to_nice_json }}" 
        # delegate_to: localhost


      - name: "Print my_server_list using hostvars"
        debug:
          msg: 
            - "{{ hostvars['localhost']['my_server_list']  | to_nice_yaml }}" 
        # delegate_to: localhost

###输出###

$ ansible-playbook -i inventory/test.ini delegate_facts.yml

PLAY [Main playbook that runs against multiple remote servers and builds a list.] ***********************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************************************************************
ok: [svr3]
ok: [svr1]
ok: [svr2]

TASK [initialize] ***************************************************************************************************************************************************************************
ok: [svr1]
ok: [svr2]
ok: [svr3]

TASK [Build a list of servers] **************************************************************************************************************************************************************
ok: [svr1]
ok: [svr2]
ok: [svr3]

TASK [Print list - 1] ***********************************************************************************************************************************************************************
ok: [svr1] =>
  msg:
  - |-
    - pqr
ok: [svr2] =>
  msg:
  - |-
    - pqr
ok: [svr3] =>
  msg:
  - |-
    - pqr

TASK [Print list - 2] ***********************************************************************************************************************************************************************
ok: [svr1] =>
  msg:
  - - NA
ok: [svr2] =>
  msg:
  - - NA
ok: [svr3] =>
  msg:
  - - NA

PLAY [Print my_server_list] *****************************************************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************************************************************
ok: [localhost]

TASK [Print my_server_list without hostvars] ************************************************************************************************************************************************
ok: [localhost] =>
  msg:
  - |-
    [
        "pqr"
    ]

TASK [Print my_server_list using hostvars] **************************************************************************************************************************************************
ok: [localhost] =>
  msg:
  - |-
    - pqr

PLAY RECAP **********************************************************************************************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
svr1                       : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
svr2                       : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
svr3                       : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Playbook run took 0 days, 0 hours, 0 minutes, 13 seconds

###预期输出### 我期待 Play2 中的最后两个调试语句包含所有服务器的 var1 值,如下所示:

    TASK [Print my_server_list using hostvars] **************************************************************************************************************************************************
    ok: [localhost] =>
      msg:
      - |-
        - abc
        - xyz
        - pqr
    

【问题讨论】:

  • 如果您想获取my_servers 组中的服务器列表,为什么不使用groups['my_servers'] ansible 事实呢?这将自动为您提供 3 个服务器的列表 [svr1, svr2, svr3]
  • 这只是演示问题的示例代码。真正的剧本要复杂得多。
  • 所以您希望my_server_list 包含您的my_servers 组的3 台主机?
  • 累加器如何同时工作?最好在没有任何委托的情况下将事实存储在每个主机上,这样就不会出现并发或累加器问题,然后在 localhost 上,将来自其他主机的数据与 groups.my_servers | map('extract', hostvars, 'my_server_list') | flatten 之类的数据结合起来
  • 是的,但在真正的剧本中,我不知道要循环的主机列表。此示例是为了演示该问题而进行的简化。

标签: ansible


【解决方案1】:

使用Special Variables,例如

- hosts: all
  gather_facts: false
  tasks:
    - set_fact:
        my_server_list: "{{ ansible_play_hosts_all }}"
      run_once: true
      delegate_to: localhost
      delegate_facts: true

- hosts: localhost
  gather_facts: false
  tasks:
    - debug:
        var: my_server_list

给予

ok: [localhost] => 
  my_server_list:
  - svr1
  - svr2
  - svr3

还有很多其他方法可以创建列表,例如

- hosts: all
  gather_facts: false
  tasks:
    - debug:
        msg: "{{ groups.my_servers }}"
      run_once: true
- hosts: all
  gather_facts: false
  tasks:
    - debug:
        msg: "{{ hostvars|json_query('*.inventory_hostname') }}"
      run_once: true

问:用运行复杂命令收集的输出填充列表。

A:上面的最后一个例子展示了如何从 hostvars 创建一个列表。注册复杂命令的结果,例如

shell> ssh admin@srv1 cat /root/complex_script.sh
#!/bin/sh
ifconfig wlan0 | grep inet | cut -w -f3

剧本

- hosts: all
  gather_facts: false
  tasks:
    - command: /root/complex_script.sh
      register: result
    - set_fact:
        my_server_list: "{{ hostvars|json_query('*.result.stdout') }}"
      run_once: true
      delegate_to: localhost
      delegate_facts: true

- hosts: localhost
  gather_facts: false
  tasks:
    - debug:
        var: my_server_list

给予

  my_server_list:
  - 10.1.0.61
  - 10.1.0.62
  - 10.1.0.63

问:为什么将事实委托给 localhost 并继续将它们附加到该列表的逻辑不起作用?

A:下面的代码(简化)无法工作,因为右侧的 msl 值仍然来自 inventory_hosthostvars /em> 尽管事实上delegate_facts: true。这只是将创建的变量 msl 放入 localhost 的 hostvars

- hosts: my_servers
  tasks:
    - set_fact:
        msl: "{{ msl|default([]) + [inventory_hostname] }}"
      delegate_to: localhost
      delegate_facts: true

引用Delegating facts

要将收集到的事实分配给委托主机而不是当前主机,请将 delegate_facts 设置为 true

由于这样的代码,变量 msl 将只保留最后分配的值。

【讨论】:

  • 也许我不清楚......在我的示例剧本中,我使用 inventory_hostname 来说明。在我真正的剧本中,我打算用通过运行复杂的 powershell/bash 命令收集的输出来填充列表,而不仅仅是简单地将主机名附加到列表中。感谢您抽出宝贵时间帮助我!
  • 我修改了我的问题以避免混淆。请看一下。谢谢!
  • 如果你想清楚并避免混淆edit你的问题并提出minimal reproducible example
  • 谢谢。那行得通,但我不明白为什么..您能否解释一下 hostvars|json_query('*.result.stdout') 在设置为运行一次时如何能够从所有主机捕获结果?它如何知道查询正确的主机列表?另外,也许您能说出我的方法出了什么问题。非常感谢。非常感谢。
  • 好的,我想我知道你的技术是如何工作的。但我不确定为什么我不能从 hostvars 中获取结果,例如:hostvars[inventory_hostname]['result.stdout'] 它一直说变量未定义。我将编辑我的问题,以便您了解我在尝试什么
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
相关资源
最近更新 更多