我只想在每个库存组的第一台主机上启动我的剧本。
[ego]
server1
server2
[asp]
server1
server2
[bre]
server1
server2
我看到有一个指定group_name
的选项,但这只是针对1group_name
hosts: group_name[0]
此选项通常只在1台主机上运行,不考虑组。
The run_once:True
有没有一种方法可以在所有组的第一个主机上运行剧本或任务,而无需定义剧本中的哪些组。
因此,在执行剧本时,我希望能够选择不同的组作为限制,并且只对每个组的第一个主机运行剧本。
您可以使用add_host模块来构建一个新的组,该组仅包含库存中每个组的第一个主机。
- hosts: all
gather_facts: no
tasks:
# groups.keys() gets all groups names. I will exclude 'all' and 'ungrouped'
# solutions to do that in a better way are welcomed
- set_fact:
groups_names: "{{ groups.keys() | difference(['all'])| difference(['ungrouped']) }}"
run_once: true
# Add first host from every group to new_group
- add_host:
name: "{{ groups[item][0] }}"
groups: new_group
loop: "{{ groups_names }}"
changed_when: false
- debug:
msg: "{{ inventory_hostname }}"
when: inventory_hostname in groups['new_group']
我的库存:
[test]
test-001
test-002
[staging]
staging-001
staging-002
staging-003
[prod]
prod-001
prod-002
输出:
PLAY [all] *************************************************
TASK [set_fact] ********************************************
ok: [test-001]
TASK [add_host] ********************************************
ok: [test-001] => (item=test)
ok: [test-001] => (item=staging)
ok: [test-001] => (item=prod)
TASK [debug] ***********************************************
skipping: [test-002]
ok: [test-001] => {
"msg": "test-001"
}
skipping: [staging-002]
ok: [staging-001] => {
"msg": "staging-001"
}
skipping: [staging-003]
skipping: [prod-002]
ok: [prod-001] => {
"msg": "prod-001"
}
PLAY RECAP ***************************************************
prod-001 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
prod-002 : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
staging-001 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
staging-002 : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
staging-003 : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
test-001 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test-002 : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
如何仅在每个库存组的第一台主机上启动剧本。。。我不能";硬编码";前面的小组。。。由150个或更多主机组组成的完整库存
从您提供的问题和描述中,我了解到您喜欢将剧本的执行动态限制在某些主机和组。由于(对我来说(还不清楚您到底想实现什么以及在哪里实现,我将提供一种使用CLI工具的可能方法。在剧本和任务中,还有其他可用的选项。
类似的hosts
库存示例
[tomcat]
tomcat1.example.com
tomcat2.example.com
tomcat3.example.com
[apache]
apache1.example.com
apache2.example.com
apache3.example.com
[sql]
sql1.example.com
sql2.example.com
sql3.example.com
ansible-inventory -i hosts --graph
@all:
|--@apache:
| |--apache1.example.com
| |--apache2.example.com
| |--apache3.example.com
|--@sql:
| |--sql1.example.com
| |--sql2.example.com
| |--sql3.example.com
|--@tomcat:
| |--tomcat1.example.com
| |--tomcat2.example.com
| |--tomcat3.example.com
|--@ungrouped:
带有组列表
ansible-inventory -i hosts --list | jq --raw-output '.all.children[]'
apache
sql
tomcat
ungrouped
以及类似的示例剧本CCD_ 4
---
- hosts: '*'
become: false
gather_facts: false
tasks:
- name: Show Facts
debug:
msg: "{{ item }}"
when: item == inventory_hostname
loop: "{{ ansible_play_hosts }}"
通过调用
LIMIT=$(ansible-inventory -i hosts --list | jq --raw-output '.all.children[]' | head -n -1 | sed s/$/[0]/ | tr 'n' ',' | rev | cut -c2- | rev)
echo ${LIMIT}
apache[0],sql[0],tomcat[0]
ansible-playbook -i hosts groups.yml --limit="${LIMIT}"
将导致的输出
TASK [Show Facts] ****************************************
ok: [apache1.example.com] => (item=apache1.example.com) =>
msg: apache1.example.com
ok: [tomcat1.example.com] => (item=tomcat1.example.com) =>
msg: tomcat1.example.com
ok: [sql1.example.com] => (item=sql1.example.com) =>
msg: sql1.example.com
可以看到,它只在每个库存组的第一台主机上执行。
该方法使用
- 环境变量
LIMIT
,用于存储为--limit
生成的列表 ansible-iventory
列出all
组- 从输出中删除默认组
ungrouped
- 通过添加
[0]
定义一个列表元素 - 通过将换行符
n
与,
交换,从输出创建CSV - 并删除最后一个CCD_ 13
类似的问答;A
- 是否有在Ansible中列出组的选项
- Ansible:临时限制主机
进一步阅读并在研究期间使用
- 特殊变量
- 删除Bash中文件的最后一行
- 在每行末尾添加文本
- 如何删除Bash中字符串的最后n个字符
由于可能有其他或更好的解决方案。。。
后续
- Regex任意ASCII字符
jq
:排除指定的嵌入密钥- 如何使用
jq
移除数组元素