Par Gauvain Pocentek, Expert OpenStack @ Objectif Libre

GauvainOLN&B

 

Le cloud et l’automatisation vont de pair.

Pour le déploiement d’infrastructures virtuelles sur OpenStack, deux outils peuvent être utilisés conjointement :

  • Heat pour l’infrastructure (réseau, stockage, instances)
  • Ansible pour l’applicatif

 

Pour pousser l’automatisation jusqu’au bout, ansible doit être capable d’utiliser un inventaire correspondant à l’infrastructure déployée par Heat, et évoluant avec elle.

La fonctionnalité d’inventaire dynamique d’ansible permet de gérer cette problématique, à condition d’avoir prévu son utilisation.

 

Les instances déployées par Heat doivent être associées à un rôle spécifique, utilisable par ansible pour la gestion dynamique des groupes de son inventaire. Les metadata associées à une instance peuvent fournir cette information. Le template suivant illustre l’utilisation des metadatas :

 

resources:
  sql_server:
    type: OS::Nova::Server
    properties:
      # propriétés habituelles (flavor, image...)
      metadata:
        services: sql

  web_server:
    type: OS::Nova::Server
    properties:
      # propriétés habituelles (flavor, image...)
      metadata:
        services: web

 

Une fois la stack déployée, le script (un peu naïf) suivant permet à ansible de découvrir les instances :

#!/usr/bin/env python
# -*- encoding: utf8 -*-

import json
import os
import sys

import novaclient.v2.client as nclient

def list_vms():
    # Création du client nova
    nova = nclient.Client(auth_url=os.environ['OS_AUTH_URL'],
                          username=os.environ['OS_USERNAME'],
                          api_key=os.environ['OS_PASSWORD'],
                          project_id=os.environ['OS_TENANT_NAME'],
                          region_name=os.environ['OS_REGION_NAME'])

    # Parcours de la liste d'instances
    inventory = {}
    for server in nova.servers.list():
        # Utilisation de la première IP v4 disponible comme nom d'hôte (pas de
        # configuration DNS)
        host = None
        for network, data in server.addresses.items():
            if data[0]['version'] == 4:
                host = data[0]['addr']
                break

        if host is not None:
            services = server.metadata['services'].split(',')
            # Ajout de la vm dans chaque groupe
            for service in services:
                inventory.setdefault(service, {'hosts': []})
                inventory[service]['hosts'].append(host)

    return inventory


if __name__ == '__main__':
    if sys.argv[1] == '--list':
        inventory = list_vms()
        # Ajout de variables pour chaque groupe
        for v in inventory.values():
            v['vars'] = {'ansible_ssh_user': 'cloud'}
        print json.dumps(inventory, separators=(',', ': '), indent=2)

Le script peut être testé directement :

$ chmod +x inventory
$ ./inventory --list
  "web": {
    "hosts": [
      "10.98.140.2"
    ],
    "vars": {
      "ansible_ssh_user": "cloud"
    }
  },
...

Et avec ansible :

$ ansible -i inventory all -m ping