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

问题描述

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

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

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"](因为它们是这次任务改变的主机)。

我首先想尝试组合 varname 为受任务影响的每个主机生成的 register 变量,查看每个中的 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

然后选择改变的主机,例如

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

给予

  changed_hosts:
  - test_12
  - test_13

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...