Ansible-如何仅在每个库存组的第一台主机上启动剧本



我只想在每个库存组的第一台主机上启动我的剧本。

[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移除数组元素

最新更新