Ansible:如何将受任务影响的所有主机存储在变量中?

Ansible: how to store all hosts affected by a task in a variable?

我有一个针对一小组主机的剧本,还有一个任务可以根据我设置变量的方式更改其中一个或多个主机上的一些配置文件。

运行 此任务的简化示例结果:

TASK [somerole : create config file] *************************************
ok: [server1] => (item=foo.conf)
changed: [server2] => (item=foo.conf)
changed: [server3] => (item=foo.conf)

如果我在此任务上使用 register,然后 debug 它创建的变量,debug: var=varname 的输出将如下所示(大大简化):

TASK [somerole : debug] **************************************************
ok: [server1] => {
    "varname": {
        "changed": false,
        "results": [{...}]
    }
}
ok: [server2] => {
    "varname": {
        "changed": true,
        "results": [{...}]
    }
}
ok: [server3] => {
    "varname": {
        "changed": true,
        "results": [{...}]
    }
}

配置更改需要重新启动服务,目前必须由人工手动完成(有手动目测验证步骤)。为了解决这个问题,我想在剧本末尾使用 pause 模块向用户显示提示,如下所示:

- pause:
    prompt: |-
      The configuration has changed on the following servers: {{ changed_servers|join(', ' }}

      Please restart service X on these servers after validating Y and Z.

那么,如何构建 changed_servers 变量?鉴于上面的例子,它将是这个列表:["server2", "server3"](因为它们是这次任务更改的主机)。

我首先想到我会尝试组合 register 为每个受任务影响的主机生成的 varname 变量,查看每个主机中的 changed 布尔值,但是varname 中的任何地方都不存在主机名称,因此我可以将 changed 属性与相应主机的名称结合起来。

真的有办法做到这一点吗?

问:"将受任务影响的所有主机存储在变量中"

A:用任务的结果注册一个变量。然后使用 extract 收集结果。例如,下面的剧本创建文件 foo.conf 注册结果并创建字典 dict_foo_conf

- hosts: test_11,test_12,test_13
  tasks:
    - command:
        cmd: touch foo.conf
        creates: foo.conf
        warn: false
      register: result_foo_conf
    - set_fact:
        dict_foo_conf: "{{ dict(ansible_play_hosts_all|zip(my_results)) }}"
      vars:
        my_results: "{{ ansible_play_hosts_all|
                        map('extract', hostvars, ['result_foo_conf', 'changed'])|
                        list }}"
      run_once: true

给予


TASK [command] *************************************************************
changed: [test_11]
changed: [test_12]
changed: [test_13]
  dict_foo_conf:
    test_11: true
    test_12: true
    test_13: true

当您再次运行剧本时没有任何变化

TASK [command] ******************************************************************
ok: [test_13]
ok: [test_11]
ok: [test_12]
  dict_foo_conf:
    test_11: false
    test_12: false
    test_13: false

让我们从主机 test_12 和 test_13

中删除文件
shell> ssh admin@test_12 rm foo.conf
shell> ssh admin@test_13 rm foo.conf

剧本给出

TASK [command] ******************************************************************
changed: [test_12]
ok: [test_11]
changed: [test_13]
  dict_foo_conf:
    test_11: false
    test_12: true
    test_13: true

然后 select 发生变化的主机,例如

  - set_fact:
      changed_hosts: "{{ dict_foo_conf|dict2items|json_query('[?value].key') }}"

给予

  changed_hosts:
  - test_12
  - test_13