loops - 如何为循环的每次迭代触发 Ansible Play
问题描述
下面注册的变量command_result
从数据库中获取记录,这些记录可能是多行的。
下面帮助我遍历command_result
变量中数据库的每条记录。
- debug:
msg: "This is a database line: {{ item }}"
with_items: "{{ command_result.stdout_lines }}"
我现在需要的是为每个循环迭代以及相应的{{ item }}
.
- hosts: "{{ item.stdout.split('\t')[0] }}"
tasks:
- name: Check if reboot is required
shell: /home/ansible/scripts/check.sh "{{ item.stdout.split('\t')[1] }}"
register: output
- debug: var=output.stdout_lines
- add_host: name={{ item }}
groups=dest_nodes
ansible_user={{ USER }}
with_items: "{{ dest_ip.split(',') }}"
项目值将在每个循环中发生变化,并将被馈送到上面的播放中。
综上所述:如果数据库在{{ command_result.stdout_lines }}
shell 模块中返回三个记录,那么 play 应该被调用三次,每个记录的详细信息{{ item }}
分别在其中。
例如:数据库可以返回任意数量的行,假设它返回三行类型<listofhosts>\t<somearguments>
::
host5,host8\targ1
host6,host2\targ3
host9,host3,host4\targ4
我需要的是循环with_items: {{ command_result.stdout_lines }}
将运行三个播放,每个播放为该运行及其各自的参数构建主机列表的动态主机组。
所以:
- 对于第一次运行,动态主机组将是
host5,host8
并且外壳应该得到arg1
- 对于第二次循环迭代,动态主机组将是
host6,host2
并且 shell 会得到arg3
- 等等。
希望这能让我的要求得到理解。
我正在使用最新版本的 Ansible。
解决方案
您应该能够通过模块创建动态主机组来运行此类任务add_host
。
此外,为了满足每行有多个主机的要求,我们首先在模块的帮助下重新创建一个干净的列表set_fact
。
然后,使用新创建的列表,我们可以使用循环with_subelements
来创建正确的元组(check_arg, host)
。
这是一个示例,我dynamic_hosts
在 play 的变量中伪造了您的数据库输出:
---
- hosts: 127.0.0.1
gather_facts: false
connection: local
vars:
dynamic_hosts:
- "host5,host8\targ1"
- "host6,host2\targ3"
- "host9,host3,host4\targ4"
tasks:
- debug:
msg: "{{ dynamic_hosts }}"
- name: Make a clean list out of the hosts and arguments
set_fact:
hosts: "{{ hosts | default([]) + [ {'hosts': item.split('\t')[0].split(','), 'check_arg': item.split('\t')[1]} ] }}"
with_items: "{{ dynamic_hosts }}"
- debug:
msg: "{{ hosts }}"
- name: Adding hosts to a dynamic group based on the faked database output stored in hosts
add_host:
name: "{{ item.1 }}"
check_arg: "{{ item.0.check_arg }}"
ansible_host: 127.0.0.1
ansible_connection: local
groups: nodes_to_run_on
with_subelements:
- "{{ hosts }}"
- hosts
- hosts: nodes_to_run_on
gather_facts: false
tasks:
- debug:
msg: "Run the shell with the argument `{{ check_arg }}` here"
如您所见,我正在创建一个以nodes_to_run_on
该剧第一部分命名的主机组,并借助add_host
. 稍后,我将使用此主机组在该组中的所有主机上运行一组新任务。
这将是这个剧本的输出:
PLAY [127.0.0.1] **********************************************************************************************************************************
TASK [debug] **************************************************************************************************************************************
ok: [127.0.0.1] => {
"msg": [
"host5,host8\targ1",
"host6,host2\targ3",
"host9,host3,host4\targ4"
]
}
TASK [Make a clean list out of the hosts and arguments] ******************************************************************************************
ok: [127.0.0.1] => (item=host5,host8 arg1)
ok: [127.0.0.1] => (item=host6,host2 arg3)
ok: [127.0.0.1] => (item=host9,host3,host4 arg4)
TASK [debug] **************************************************************************************************************************************
ok: [127.0.0.1] => {
"msg": [
{
"check_arg": "arg1",
"hosts": [
"host5",
"host8"
]
},
{
"check_arg": "arg3",
"hosts": [
"host6",
"host2"
]
},
{
"check_arg": "arg4",
"hosts": [
"host9",
"host3",
"host4"
]
}
]
}
TASK [Adding hosts to a dynamic group based on the faked database output stored in hosts] *********************************************************
changed: [127.0.0.1] => (item=[{'check_arg': 'arg1'}, 'host5'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg1'}, 'host8'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg3'}, 'host6'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg3'}, 'host2'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg4'}, 'host9'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg4'}, 'host3'])
changed: [127.0.0.1] => (item=[{'check_arg': 'arg4'}, 'host4'])
PLAY [nodes_to_run_on] ****************************************************************************************************************************
TASK [debug] **************************************************************************************************************************************
ok: [host5] => {
"msg": "Run the shell with the argument `arg1` here"
}
ok: [host8] => {
"msg": "Run the shell with the argument `arg1` here"
}
ok: [host6] => {
"msg": "Run the shell with the argument `arg3` here"
}
ok: [host2] => {
"msg": "Run the shell with the argument `arg3` here"
}
ok: [host9] => {
"msg": "Run the shell with the argument `arg4` here"
}
ok: [host3] => {
"msg": "Run the shell with the argument `arg4` here"
}
ok: [host4] => {
"msg": "Run the shell with the argument `arg4` here"
}
PLAY RECAP ****************************************************************************************************************************************
127.0.0.1 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host3 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host4 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host5 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host6 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host8 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host9 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
请注意:这不是我们在此处创建的真正DRY主机列表,但它使解决方案保持幼稚,并且更符合KISS原则。
我们最终在这里生成的库存如下所示:
## kiss.yml ## lots of repetition
nodes_to_run_on:
hosts:
host5:
check_arg: arg1
ansible_host: 127.0.0.1
ansible_connection: local
host8:
check_arg: arg1
ansible_host: 127.0.0.1
ansible_connection: local
host6:
check_arg: arg3
ansible_host: 127.0.0.1
ansible_connection: local
host2:
check_arg: arg3
ansible_host: 127.0.0.1
ansible_connection: local
host9:
check_arg: arg4
ansible_host: 127.0.0.1
ansible_connection: local
host3:
check_arg: arg4
ansible_host: 127.0.0.1
ansible_connection: local
host4:
check_arg: arg4
ansible_host: 127.0.0.1
ansible_connection: local
当它绝对可以干燥到
## dry.yaml ## no repetition with the help of group variables
nodes_to_run_on:
vars:
ansible_host: 127.0.0.1
ansible_connection: local
children:
with_arg1:
hosts:
host5:
host8:
vars:
check_arg: arg1
with_arg3:
hosts:
host6:
host2:
vars:
check_arg: arg3
with_arg4:
hosts:
host9:
host3:
host4:
vars:
check_arg: arg4
考虑一下这出戏中的那两个:
---
- hosts: nodes_to_run_on
gather_facts: false
tasks:
- debug:
msg: "Run the shell with the argument `{{ check_arg }}` here"
和kiss.yml
$ ansible-playbook example.yml --inventory=kiss.yml
PLAY [nodes_to_run_on] ****************************************************************************************************************************
TASK [debug] **************************************************************************************************************************************
ok: [host5] => {
"msg": "Run the shell with the argument `arg1` here"
}
ok: [host8] => {
"msg": "Run the shell with the argument `arg1` here"
}
ok: [host6] => {
"msg": "Run the shell with the argument `arg3` here"
}
ok: [host2] => {
"msg": "Run the shell with the argument `arg3` here"
}
ok: [host9] => {
"msg": "Run the shell with the argument `arg4` here"
}
ok: [host3] => {
"msg": "Run the shell with the argument `arg4` here"
}
ok: [host4] => {
"msg": "Run the shell with the argument `arg4` here"
}
PLAY RECAP ****************************************************************************************************************************************
host2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host3 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host4 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host5 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host6 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host8 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host9 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
和dry.yml
$ ansible-playbook example.yml --inventory=dry.yml
PLAY [nodes_to_run_on] ****************************************************************************************************************************
TASK [debug] **************************************************************************************************************************************
ok: [host5] => {
"msg": "Run the shell with the argument `arg1` here"
}
ok: [host8] => {
"msg": "Run the shell with the argument `arg1` here"
}
ok: [host6] => {
"msg": "Run the shell with the argument `arg3` here"
}
ok: [host2] => {
"msg": "Run the shell with the argument `arg3` here"
}
ok: [host9] => {
"msg": "Run the shell with the argument `arg4` here"
}
ok: [host3] => {
"msg": "Run the shell with the argument `arg4` here"
}
ok: [host4] => {
"msg": "Run the shell with the argument `arg4` here"
}
PLAY RECAP ****************************************************************************************************************************************
host2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host3 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host4 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host5 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host6 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host8 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host9 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
因此,您可以看到,当库存为 30行时,我们使用dry.yml
24 行的库存实现了相同的效果。kiss.yml
但最终创造一个 DRY 的发明者的努力并不会真正付出代价,如果来源是,无论哪种方式,来自一个可以生成主机列表的数据库。
推荐阅读
- android - Google Play 政策 - 在应用程序内提供 Webview 以下载 jar 文件
- javascript - 将元素附加到现有元素 React
- openthread - OpenThread - 如何使用 otServerGetNextLeaderService?
- python - 为什么使用带有 Popen 的 preexec 函数对线程很危险
- python - 如何告诉 Python 脚本持续运行,让 Excel 文件保持打开状态并更新其中的输出
- flutter - 当我使用共享首选项时缺少插件
- javascript - 不断等待点击(不管 DOM 的变化或其他点击)
- python - 如何编写代码将日志记录为 argv?
- angular - 如何使用 NX/Nrwl 为 Angular 创建应用程序特定配置?
- ansible - 一个悖论 - 将我的 Ansible 服务器置于 CM 控制之下?