Python 如何从 Ansible 清单文件中获取主机列表?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37623849/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I get a list of hosts from an Ansible inventory file?
提问by MrDuk
Is there a way to use the Ansible Python API to get a list of hosts from a given inventory file / group combination?
有没有办法使用 Ansible Python API 从给定的清单文件/组组合中获取主机列表?
For example, our inventory files are split up by service type:
例如,我们的库存文件按服务类型拆分:
[dev:children]
dev_a
dev_b
[dev_a]
my.host.int.abc.com
[dev_b]
my.host.int.xyz.com
[prod:children]
prod_a
prod_b
[prod_a]
my.host.abc.com
[prod_b]
my.host.xyz.com
Can I use ansible.inventory
in some way to pass in a specific inventory file, and the group I want to act on, and have it return a list of hosts that match?
我可以ansible.inventory
以某种方式使用来传递特定的清单文件和我想要操作的组,并让它返回匹配的主机列表吗?
采纳答案by Theo
I was struggling with this as well for awhile, but found a solution through trial & error.
我也为此苦苦挣扎了一段时间,但通过反复试验找到了解决方案。
One of the key advantages to the API is that you can pull variables and metadata, not just hostnames.
API 的主要优势之一是您可以提取变量和元数据,而不仅仅是主机名。
Starting from Python API - Ansible Documentation:
#!/usr/bin/env python
# Ansible: initialize needed objects
variable_manager = VariableManager()
loader = DataLoader()
# Ansible: Load inventory
inventory = Inventory(
loader = loader,
variable_manager = variable_manager,
host_list = 'hosts', # Substitute your filename here
)
This gives you an Inventory instance, which has methods and properties to provide groups and hosts.
这为您提供了一个 Inventory 实例,该实例具有提供组和主机的方法和属性。
To expand further (and provide examples of Group and Host classes), here's a snippet I wrote which serializes the inventory as a list of groups, with each group having a 'hosts' attribute that is a list of each host's attributes.
为了进一步扩展(并提供 Group 和 Host 类的示例),这是我编写的一个片段,它将库存序列化为一个组列表,每个组都有一个“hosts”属性,它是每个主机属性的列表。
#/usr/bin/env python
def serialize(inventory):
if not isinstance(inventory, Inventory):
return dict()
data = list()
for group in inventory.get_groups():
if group != 'all':
group_data = inventory.get_group(group).serialize()
# Seed host data for group
host_data = list()
for host in inventory.get_group(group).hosts:
host_data.append(host.serialize())
group_data['hosts'] = host_data
data.append(group_data)
return data
# Continuing from above
serialized_inventory = serialize(inventory)
I ran this against my lab of four F5 BIG-IP's, and this is the result (trimmed):
我对我的四个 F5 BIG-IP 实验室运行了这个,这是结果(修剪):
<!-- language: lang-json -->
[{'depth': 1,
'hosts': [{'address': u'bigip-ve-03',
'name': u'bigip-ve-03',
'uuid': UUID('b5e2180b-964f-41d9-9f5a-08a0d7dd133c'),
'vars': {u'hostname': u'bigip-ve-03.local',
u'ip': u'10.128.1.130'}}],
'name': 'ungrouped',
'vars': {}},
{'depth': 1,
'hosts': [{'address': u'bigip-ve-01',
'name': u'bigip-ve-01',
'uuid': UUID('3d7daa57-9d98-4fa6-afe1-5f1e03db4107'),
'vars': {u'hostname': u'bigip-ve-01.local',
u'ip': u'10.128.1.128'}},
{'address': u'bigip-ve-02',
'name': u'bigip-ve-02',
'uuid': UUID('72f35cd8-6f9b-4c11-b4e0-5dc5ece30007'),
'vars': {u'hostname': u'bigip-ve-02.local',
u'ip': u'10.128.1.129'}},
{'address': u'bigip-ve-04',
'name': u'bigip-ve-04',
'uuid': UUID('255526d0-087e-44ae-85b1-4ce9192e03c1'),
'vars': {}}],
'name': u'bigip',
'vars': {u'password': u'admin', u'username': u'admin'}}]
回答by nitzmahone
Do the same trick from before, but instead of all
, pass the group name you want to list:
执行与之前相同的技巧,但不是all
传递您要列出的组名:
ansible (group name here) -i (inventory file here) --list-hosts
ansible (group name here) -i (inventory file here) --list-hosts
回答by smishra
For me following worked
对我来说,以下工作
from ansible.parsing.dataloader import DataLoader
from ansible.inventory.manager import InventoryManager
if __name__ == '__main__':
inventory_file_name = 'my.inventory'
data_loader = DataLoader()
inventory = InventoryManager(loader = data_loader,
sources=[inventory_file_name])
print(inventory.get_groups_dict()['spark-workers'])
inventory.get_groups_dict()
returns a dictionary that you can use to get hosts by using the group_name as key as shown in the code.
You will have to install ansible package you can do by pip as follows
inventory.get_groups_dict()
返回一个字典,您可以使用该字典通过使用 group_name 作为键来获取主机,如代码所示。您将必须安装可以通过 pip 执行的 ansible 包,如下所示
pip install ansible
回答by NinjaKitty
There has been changes to Ansible API since the approved answer:
自批准的答案以来,Ansible API 发生了变化:
This works for Ansible 2.8 (and maybe more)
这适用于 Ansible 2.8(也许更多)
Here's the way I was able to access most of the data:
这是我能够访问大部分数据的方式:
from ansible.parsing.dataloader import DataLoader
from ansible.inventory.manager import InventoryManager
loader = DataLoader()
# Sources can be a single path or comma separated paths
inventory = InventoryManager(loader=loader, sources='path/to/file')
# My use case was to have all:vars as the 1st level keys, and have groups as key: list pairs.
# I also don't have anything ungrouped, so there might be a slightly better solution to this.
# Your use case may be different, so you can customize this to how you need it.
x = {}
ignore = ('all', 'ungrouped')
x.update(inventory.groups['all'].serialize()['vars'])
group_dict = inventory.get_groups_dict()
for group in inventory.groups:
if group in ignore:
continue
x.update({
group: group_dict[group]
})
Example:
例子:
Input:
输入:
[all:vars]
x=hello
y=world
[group_1]
youtube
google
[group_2]
stack
overflow
Output:
输出:
{"x":"hello","y":"world","group_1":["youtube","google"],"group_2":["stack","overflow"]}
Again, your use case might be different than mine, so you'll have to slightly change the code to how you want it to be.
同样,您的用例可能与我的不同,因此您必须将代码稍微更改为您想要的方式。
回答by mblomdahl
I had a similar problem and I think nitzmahone's approach of not using unsupported calls to the Python API. Here's a working solution, relying on the nicely JSON-formatted output of ansible-inventory
CLI:
我有一个类似的问题,我认为 nitzmahone 的方法是不使用不受支持的 Python API 调用。这是一个有效的解决方案,依赖于ansible-inventory
CLI 的JSON 格式的输出:
pip install ansible==2.4.0.0 sh==1.12.14
An example inventory file, inventory/qa.ini
:
一个示例清单文件,inventory/qa.ini
:
[lxlviewer-server]
id-qa.kb.se
[xl_auth-server]
login.libris.kb.se
[export-server]
export-qa.libris.kb.se
[import-server]
import-vcopy-qa.libris.kb.se
[rest-api-server]
api-qa.libris.kb.se
[postgres-server]
pgsql01-qa.libris.kb.se
[elasticsearch-servers]
es01-qa.libris.kb.se
es02-qa.libris.kb.se
es03-qa.libris.kb.se
[tomcat-servers:children]
export-server
import-server
rest-api-server
[flask-servers:children]
lxlviewer-server
xl_auth-server
[apache-servers:children]
lxlviewer-server
[nginx-servers:children]
xl_auth-server
A Python 2.7 function to extract info (easily extendable to hostvars et cetera):
用于提取信息的 Python 2.7 函数(可轻松扩展到主机变量等):
import json
from sh import Command
def _get_hosts_from(inventory_path, group_name):
"""Return list of hosts from `group_name` in Ansible `inventory_path`."""
ansible_inventory = Command('ansible-inventory')
json_inventory = json.loads(
ansible_inventory('-i', inventory_path, '--list').stdout)
if group_name not in json_inventory:
raise AssertionError('Group %r not found.' % group_name)
hosts = []
if 'hosts' in json_inventory[group_name]:
return json_inventory[group_name]['hosts']
else:
children = json_inventory[group_name]['children']
for child in children:
if 'hosts' in json_inventory[child]:
for host in json_inventory[child]['hosts']:
if host not in hosts:
hosts.append(host)
else:
grandchildren = json_inventory[child]['children']
for grandchild in grandchildren:
if 'hosts' not in json_inventory[grandchild]:
raise AssertionError('Group nesting cap exceeded.')
for host in json_inventory[grandchild]['hosts']:
if host not in hosts:
hosts.append(host)
return hosts
Proof that it works (also with child and grandchild groups):
证明它有效(也适用于子孙组):
In [1]: from fabfile.conf import _get_hosts_from
In [2]: _get_hosts_from('inventory/qa.ini', 'elasticsearch-servers')
Out[2]: [u'es01-qa.libris.kb.se', u'es02-qa.libris.kb.se', u'es03-qa.libris.kb.se']
In [3]: _get_hosts_from('inventory/qa.ini', 'flask-servers')
Out[3]: [u'id-qa.kb.se', u'login.libris.kb.se']
In [4]: