web-dev-qa-db-de.com

Wie kann ich eine Liste von Hosts aus einer Ansible-Inventardatei erhalten?

Gibt es eine Möglichkeit, die Ansible Python-API zu verwenden, um eine Liste von Hosts aus einer bestimmten Kombination aus Inventardatei und -gruppe abzurufen?

Unsere Bestandsdateien sind beispielsweise nach Servicetyp aufgeteilt:

[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

Kann ich ansible.inventory in irgendeiner Weise verwenden, um eine bestimmte Inventardatei und die Gruppe, in der ich tätig werden möchte, zu übergeben und eine Liste der übereinstimmenden Hosts anzeigen zu lassen?

11
MrDuk

Ich hatte auch eine Weile mit diesem Problem zu kämpfen, fand aber eine Lösung durch Versuch und Irrtum.

Einer der wichtigsten Vorteile der API besteht darin, dass Sie Variablen und Metadaten abrufen können, nicht nur Hostnamen.

Start von Python API - Ansible-Dokumentation :

#!/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
)

Dadurch erhalten Sie eine Inventory-Instanz, die Methoden und Eigenschaften für die Bereitstellung von Gruppen und Hosts enthält.

Um weiter zu erweitern (und Beispiele für Gruppen- und Host-Klassen bereitzustellen), hier ein Auszug, den ich geschrieben habe, der das Inventar als Liste von Gruppen serialisiert, wobei jede Gruppe ein 'hosts'-Attribut hat, das eine Liste der Attribute jedes Hosts ist.

#/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)

Ich habe dies gegen mein Labor mit vier F5-BIG-IPs durchgeführt, und dies ist das Ergebnis (getrimmt):

<!-- 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'}}]
7
Theo

Machen Sie den gleichen Trick wie zuvor, aber übergeben Sie anstelle von all den Gruppennamen, den Sie auflisten möchten:

ansible (group name here) -i (inventory file here) --list-hosts

14
nitzmahone

Für mich hat folgendes gearbeitet

from ansible.parsing.dataloader import DataLoader
from ansible.inventory.manager import InventoryManager

if __== '__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 () gibt ein Wörterbuch zurück, das Sie zum Abrufen von Hosts verwenden können, indem Sie den Gruppennamen als Schlüssel verwenden, wie im Code gezeigt. Sie müssen ein anpassbares Paket installieren, das Sie mit pip wie folgt ausführen können

pip install ansible
3
smishra

Ich hatte ein ähnliches Problem und denke, dass Nitzmahone nicht unterstützte Aufrufe der Python-API verwendet. Hier ist eine funktionierende Lösung, die sich auf die JSON-formatierte Ausgabe von ansible-inventory CLI stützt:

pip install ansible==2.4.0.0 sh==1.12.14

Eine Beispielinventardatei 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

Eine Python 2.7-Funktion zum Extrahieren von Informationen (leicht erweiterbar auf Hostvars usw.):

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

Beweis, dass es funktioniert (auch mit Kinder- und Enkelgruppen):

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]:
1
mblomdahl

Seit der genehmigten Antwort wurden Änderungen an der Ansible-API vorgenommen:

Dies funktioniert für Ansible 2.8 (und möglicherweise mehr)

So konnte ich auf die meisten Daten zugreifen:

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]
    })

Beispiel:

Eingang:

[all:vars]
x=hello
y=world

[group_1]
youtube
google

[group_2]
stack
overflow

Ausgabe:

{"x":"hello","y":"world","group_1":["youtube","google"],"group_2":["stack","overflow"]}

Auch hier kann Ihr Anwendungsfall von meinem abweichen, sodass Sie den Code leicht an Ihre Anforderungen anpassen müssen.

1
NinjaKitty