简体   繁体   English

如何使用 Ansible Playbook 遍历主机的 N 级子级?

[英]How to iterate through N level children of hosts using Ansible Playbook?

I know how to achieve this using host_vars but the problem with it is the host files can get convoluted so I'm leaning towards ini files where I can put all the data in one file.我知道如何使用host_vars实现这host_vars但它的问题是主机文件可能会变得复杂,所以我倾向于将所有数据放在一个文件中的ini文件。 This SO post helped me have an idea how to put a collection in a variable for a particular host.这篇SO帖子帮助我了解了如何将集合放入特定主机的变量中。

I have this sample inventory:我有这个样本库存:

;hosts.yml
[web1]
example1.com databases=["example1_com","mysql"]
example2.com databases=["example1_com","mysql"]

[web1:vars]
ansible_host=10.0.16.21

[web2]
example3.com databases=["example3_com"]
example4.com databases=["example4_com","mysql"]

[web2:vars]
ansible_host=10.0.16.22

[web:children]
web1
web2

Now I wanted to loop through each hosts using the the web group and iterate through the databases host var.现在我想使用web组遍历每个主机并遍历databases主机 var。

I did something like this:我做了这样的事情:

---
- debug:
    msg: "{{ item }} - {{ hostvars[item]['databases'] }} "
  with_items:
    - "{{ groups['web'] }}"

and the output is:输出是:

ok: [localhost] => (item=example1.com) => {
    "item": "example1.com", 
    "msg": "example1.com - [example1_com,mysql] "
}
ok: [localhost] => (item=example2.com) => {
    "item": "example2.com", 
    "msg": "example2.com - [example1_com,mysql] "
}
ok: [localhost] => (item=example3.com) => {
    "item": "example3.com", 
    "msg": "example3.com - [example3_com] "
}
ok: [localhost] => (item=example4.com) => {
    "item": "example4.com", 
    "msg": "example4.com - [example4_com,mysql] "
}

I tried achieving this using with_sublements loop but the problem is the 2nd element needs to be dynamic which is not possible with_subelements .我尝试使用with_sublements循环来实现这with_sublements但问题是第二个元素需要是动态的,这在with_subelements中是不可能的。

with_subelements:
    - "{{ groups['web'] }}"
    - {{ hostvars[item]['databases'] }} #item is dynamic, this will cause an undefined host error.

It's not 100% clear to me what your original approach was, and if the code in your question was meant to represent your new approach (since you are still referencing hostvars there).我不是 100% 清楚您的原始方法是什么,以及您问题中的代码是否旨在代表您的新方法(因为您仍在那里引用hostvars )。 I think you need to work more with specifying the groups you want affected within the playbook ( hosts: web ) or on the command line ( -l web ) when running the playbook to run the tasks only for those hosts you want, rather than trying to get the group dynamically within the task itself.我认为您需要在运行 playbook 以仅针对您想要的那些主机运行任务时,在 playbook ( hosts: web ) 或命令行 ( -l web ) 中指定要影响的组,而不是尝试在任务本身内动态获取组。

Regarding the linked question/answer, where a way of defining a list within a variable was discussed: you need to make sure to enclose the list data within single quotes, eg '["example1_com","mysql"]' .关于链接的问题/答案,其中讨论了在变量中定义列表的方法:您需要确保将列表数据括在单引号中,例如'["example1_com","mysql"]'

Given that, if you simply want to iterate over a list from a host variable defined in an inventory file, you can do the following:鉴于此,如果您只想从清单文件中定义的主机变量中迭代列表,您可以执行以下操作:

Inventory File "inv"库存文件“inv”

[web1]
example1.com databases='["example1_com","mysql"]'
example2.com databases='["example1_com","mysql"]'

[web1:vars]
ansible_host=10.0.16.21

[web2]
example3.com databases='["example3_com"]'
example4.com databases='["example4_com","mysql"]'

[web2:vars]
ansible_host=10.0.16.22

[web:children]
web1
web2

Playbook File "test.yml"剧本文件“test.yml”

---
- hosts: web
  gather_facts: no
  tasks:
    - debug: msg="Host is {{ inventory_hostname }}. Database is {{ item }}"
      with_items:
        - "{{ databases }}"

You can then run the playbook:然后你可以运行剧本:

ansible-playbook test.yml -i inv

generating the following output:生成以下输出:

PLAY ***************************************************************************

TASK [debug] *******************************************************************
ok: [example3.com] => (item=example3_com) => {
    "item": "example3_com", 
    "msg": "Host is example3.com. Database is example3_com"
}
ok: [example1.com] => (item=example1_com) => {
    "item": "example1_com", 
    "msg": "Host is example1.com. Database is example1_com"
}
ok: [example1.com] => (item=mysql) => {
    "item": "mysql", 
    "msg": "Host is example1.com. Database is mysql"
}
ok: [example2.com] => (item=example1_com) => {
    "item": "example1_com", 
    "msg": "Host is example2.com. Database is example1_com"
}
ok: [example2.com] => (item=mysql) => {
    "item": "mysql", 
    "msg": "Host is example2.com. Database is mysql"
}
ok: [example4.com] => (item=example4_com) => {
    "item": "example4_com", 
    "msg": "Host is example4.com. Database is example4_com"
}
ok: [example4.com] => (item=mysql) => {
    "item": "mysql", 
    "msg": "Host is example4.com. Database is mysql"
}

PLAY RECAP *********************************************************************
example1.com               : ok=1    changed=0    unreachable=0    failed=0   
example2.com               : ok=1    changed=0    unreachable=0    failed=0   
example3.com               : ok=1    changed=0    unreachable=0    failed=0   
example4.com               : ok=1    changed=0    unreachable=0    failed=0   

If you properly structure your playbook, you can also set it up to run different sets of tasks for different host groups (perhaps including the tasks from an external file so you DRY).如果您正确构建剧本,您还可以将其设置为为不同的主机组运行不同的任务集(可能包括来自外部文件的任务,以便您 DRY)。 Or you could simply specify hosts: all in the playbook, and use command line limiting to only run the tasks against a specific set of hosts.或者您可以简单地指定hosts: all在剧本中,并使用命令行限制仅针对一组特定的主机运行任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM