如何从针对远程主机的游戏中将事实委托给本地主机

obj*_*und 2 ansible

Ansible 版本:2.9.16,在 RHEL 7.9 上运行,python ver = 2.7.5,针对 Windows 2016 服务器。(Linux 目标服务器的行为也应该相同)

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

任何帮助将不胜感激。

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

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

    [my_servers]
    svr1 var1='abc'
    svr2 var1='xyz'
    svr3 var1='pqr'
Run Code Online (Sandbox Code Playgroud)

我的代码:

    ## 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']) }}" 
Run Code Online (Sandbox Code Playgroud)
    ## 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
Run Code Online (Sandbox Code Playgroud)

###Output###

$ 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

###**Expected Output**###
I was expecting the last two debug statements in Play2 to contain the values of var1 for all the servers something like this:


    
        TASK [Print my_server_list using hostvars] **************************************************************************************************************************************************
        ok: [localhost] =>
          msg:
          - |-
            - abc
            - xyz
            - pqr
Run Code Online (Sandbox Code Playgroud)

Vla*_*tka 6

使用特殊变量,例如

- 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
Run Code Online (Sandbox Code Playgroud)

给出

ok: [localhost] => 
  my_server_list:
  - svr1
  - svr2
  - svr3
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

shell> ssh admin@srv1 cat /root/complex_script.sh
#!/bin/sh
ifconfig wlan0 | grep inet | cut -w -f3
Run Code Online (Sandbox Code Playgroud)

剧本

- 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
Run Code Online (Sandbox Code Playgroud)

给出

  my_server_list:
  - 10.1.0.61
  - 10.1.0.62
  - 10.1.0.63
Run Code Online (Sandbox Code Playgroud)

问:为什么将事实委托给本地主机并不断将它们附加到该列表的逻辑不起作用?

答:下面的代码(简化版)无法工作,因为尽管如此,右侧的msl值仍然来自inventory_host主机变量。这只是将创建的变量msl放入本地主机的主机变量中delegate_facts: true

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

引用委托事实

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

由于此类代码,变量msl将仅保留最后分配的值。