web-dev-qa-db-fra.com

Comment puis-je obtenir une liste d'hôtes à partir d'un fichier d'inventaire Ansible?

Existe-t-il un moyen d'utiliser l'API Ansible Python pour obtenir une liste d'hôtes à partir d'une combinaison fichier/groupe d'inventaire donnée?

Par exemple, nos fichiers d’inventaire sont répartis par type de service:

[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

Puis-je utiliser d'une manière ou d'une autre ansible.inventory pour transmettre un fichier d'inventaire spécifique et le groupe sur lequel je veux agir, et lui renvoyer une liste d'hôtes correspondants

11
MrDuk

Je me débattais aussi avec cela pendant un certain temps, mais j'ai trouvé une solution par essais et erreurs.

L'un des principaux avantages de l'API est que vous pouvez extraire des variables et des métadonnées, pas seulement des noms d'hôte.

À partir de API Python - Documentation Ansible :

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

Cela vous donne une instance d'inventaire, qui a des méthodes et des propriétés pour fournir des groupes et des hôtes.

Pour développer davantage (et fournir des exemples de classes Group et Host), voici un extrait que j'ai écrit et qui sérialise l'inventaire sous forme de liste de groupes, chaque groupe possédant un attribut 'hosts' qui est une liste d'attributs de chaque hôte.

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

J'ai couru cela contre mon laboratoire de quatre F5 BIG-IP, et voici le résultat (paré):

<!-- 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

Pour moi, la suite a fonctionné

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 () renvoie un dictionnaire que vous pouvez utiliser pour obtenir des hôtes en utilisant le nom_groupe comme clé, comme indiqué dans le code. Vous devrez installer un paquet que vous pouvez faire par pip comme suit

pip install ansible
3
smishra

J'ai eu un problème similaire et je pense que l'approche de nitzmahone consiste à ne pas utiliser d'appels non pris en charge vers l'API Python. Voici une solution qui fonctionne, reposant sur la sortie joliment formatée JSON de la CLI ansible-inventory:

pip install ansible==2.4.0.0 sh==1.12.14

Un exemple de fichier d'inventaire, 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

Une fonction Python 2.7 pour extraire des informations (facilement extensible à 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

Preuve que cela fonctionne (également avec les groupes d'enfants et de petits-enfants):

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