Как я могу получить список хостов из файла инвентаризации Ansible?
Есть ли способ использовать Ansible Python API для получения списка хостов из данной комбинации файлов/групп инвентаря?
Например, наши файлы инвентаризации разделяются по типу службы:
[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
Можно ли каким-либо образом использовать ansible.inventory
для передачи в конкретном файле инвентаря и группе, в которой я хочу действовать, и вернуть ли она список хостов, которые соответствуют?
Ответы
Ответ 1
Я слишком долго боролся с этим, но нашел решение путем проб и ошибок.
Одним из ключевых преимуществ API является то, что вы можете вытаскивать переменные и метаданные, а не только имена хостов.
Начиная с API-интерфейс Python - Несанкционированная документация:
#!/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
)
Это дает вам экземпляр Inventory, который имеет методы и свойства для предоставления групп и хостов.
Далее, чтобы расширить (и предоставить примеры классов групп и хостов), вот фрагмент, который я написал, который сериализует инвентарь в виде списка групп, причем каждая группа имеет атрибут "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)
Я провел это против моей лаборатории из четырех 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'}}]
Ответ 2
Выполняйте тот же трюк раньше, но вместо all
передайте имя группы, которое вы хотите перечислить:
ansible (group name here) -i (inventory file here) --list-hosts
Ответ 3
У меня работает следующее
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()
возвращает словарь, который вы можете использовать для получения хостов, используя имя_группы в качестве ключа, как показано в коде. Вам нужно будет установить пакет ansible, который вы можете сделать с помощью pip следующим образом
pip install ansible
Ответ 4
У меня была аналогичная проблема, и я думаю, что подход nitzmahone не использует неподдерживаемые вызовы API Python. Здесь рабочее решение, основанное на хорошо отформатированном JSON-выходе ansible-inventory
CLI:
pip install ansible==2.4.0.0 sh==1.12.14
Пример файла инвентаризации 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
Функция Python 2.7 для извлечения информации (легко расширяемая до hostvars et cetera):
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
Доказательство того, что он работает (также с дочерними и внуками):
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]:
Ответ 5
После одобренного ответа в Ansible API произошли изменения:
Это работает для Ansible 2.8 (а может и больше)
Вот как я смог получить доступ к большинству данных:
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]
})
Пример:
Входные данные:
[all:vars]
x=hello
y=world
[group_1]
youtube
google
[group_2]
stack
overflow
Выход:
{"x":"hello","y":"world","group_1":["youtube","google"],"group_2":["stack","overflow"]}
Опять же, ваш вариант использования может отличаться от моего, поэтому вам придется немного изменить код так, как вы хотите.
Ответ 6
Команда, которую отправил @nitzmahone, фактически дала мне необходимую информацию (набор хостов из определенной группы).
Я пытался выяснить, как это сделать, используя "ansible-инвентарь". Я смог заставить эту команду отобразить все хосты, но не смог получить конкретный набор хостов для показа группы. Еще собираюсь попробовать