Linux Embedded

Le blog des technologies libres et embarquées

Introduction à Ansible: Gestion des layers Yocto

Introduction

Ansible est un logiciel destiné à la configuration et la gestion de parc informatique.

Il est disponible sur la plupart des distributions Linux.

Il permet de déployer des logiciels, de gérer des configurations et de lancer des tâches sur une ou plusieurs cibles.

Ansible est codé en python et fonctionne avec des fichiers de configuration au format YAML qui décrivent les tâches à accomplir.

L'avantage des fichiers au format YAML est qu'ils sont humainement lisibles et plus faciles à gérer que certains autres formats de fichiers comme par exemple le XML.

Nous présentons dans cet article une utilisation légèrement détournée de l'usage initial de ce logicel.

L'objectif va être d'utiliser Ansible pour installer un environnement Yocto avec ses différentes sources et ses configurations.

Les principes de base d'Ansible

Ansible permet d'effectuer une ou plusieurs actions sur une ou plusieurs machines.

Pour décrire son fonctionnement, nous présentons une utilisation simple comme un ping. Donc une seule action sur une ou plusieurs machines.

Puis nous introduisons le principe de playbook qui permet de lancer plusieurs actions sur une ou plusieurs machines.

Utilisation simple - une seule action

L'objectif de ce cas d'usage est d'effectuer un ping depuis plusieurs machines en une seule action. Nous allons nous connecter sur plusieurs machines simultanément et chacune de ces machines lancera un ping.

Définition des hôtes

Nous commençons par configurer l'environnement Ansible en décrivant les machines visées par l'application, nous construisons une liste de ces machines dans le fichier suivant:

/etc/ansible/hosts

On y inscrit les machines avec leur nom ou leur adresse ip comme ceci:

192.0.2.50
linuxembedded.exemple.fr

Il est possible de lister les hôtes sous forme individuelle ou par groupement d'hôtes.

Ansible va tenter de se connecter aux différents hôtes en utilisant ssh, par conséquent il est nécessaire d'avoir mis votre clé publique dans le fichier authorized_keys de vos hôtes.

Action à distance

Il est maintenant possible de lancer une commande à distance avec le programme ansible.

Ces commandes (qui ne sont pas nécessairement des commandes shell) peuvent être ciblées pour un ou plusieurs hôtes. Par exemple voici une commande permettant de lancer un ping sur tous les hôtes connus puis un ping sur un hôte particulier :

$ ansible all -a "/bin/ping 8.8.8.8 -c1"
$ ansible linuxembedded.exemple.fr -a "/bin/ping 8.8.8.8 -c1"

Ansible fournit un ensemble de modules. Ces modules permettent de lancer des actions avec un comportement prédéfini (une liste non exhaustive sera présentée un peu plus bas). Par exemple, le module ping a pour action de se connecter à un hôte, de tester l'utilisabilité de python puis de renvoyer le résultat pong en cas de succès (donc attention aux "faux-amis", le module ping n'est pas identique à la commande ping shell).

Voici ce qu'ansible affichera pour chacune des machines :

$ ansible all -m ping
<address_ip> | SUCCESS => {
 "changed": false, 
 "ping": "pong"
}

Introduction aux actions multiples - le principe de playbook

Pour effectuer plusieurs actions en une seule commande on peut utiliser ce que l'on appelle un playbook (ou playbook YAML), il permet de lister un ensemble d'actions à effectuer. Comme présenté au dessus, les actions peuvent utiliser les modules prédéfinis d'Ansible. La liste des actions est décrite dans un fichier de type YAML.

La syntaxe YAML va être présentée un peu plus bas. Tout d'abord, regardons comment utiliser un playbook simplement.

Pour lancer un playbook on n'utilise plus la commande simple ansible, mais ansible-playbook avec en paramètre le fichier YAML décrivant vos actions à effectuer.

$ ansible-playbook mon-fichier.yml

Le fichier contient à la fois la liste des hôtes et les actions à executer. Ansible effectuera donc toutes les actions listées sur tous les hôtes listés dans le fichier.

Manipuler son playbook Ansible pour aller plus loin

La syntaxe YAML

Le format YAML est utilisé dans divers projets que l'on peut retrouver sur yaml.org. Le standard YAML a été créé en 2001.

Un fichier YAML est formé de variables, de dictionnaires (des paires clé/valeur), et de listes. Par ailleurs, Ansible dispose d'un système de modules (plugins) utilisables dans les playbook.

Les variables

Les variables sont déclarées de la façon suivante :

vars:
  base_path: /mon/path

Pour accéder à la valeur il faut utiliser des doubles accolades :

{{ base_path }}

Attention, il faut entourer les variables de guillemets pour la gestion de chemin si ce dernier commence par la variable:

app_path: "{{ base_path }}/app"

Il est également possible de passer des variables en ligne de commande lors de l'exécution d'Ansible. Ainsi la variable peut être définie au moment de l'appel et non dans le fichier YAML  :

--extra-vars "base_path=/mon/path/"

Les dictionnaires

Les dictionnaires sont définis sous la forme clé: valeur.

# Information sur une personne
 martin:
   nom: Martin Dévloper
   travail: Developer
   niveau: Expérimenté

Les listes

Les listes sont définies avec -␣, un tiret suivi d'un espace.

# Une liste de fruits
 - Pomme
 - Orange
 - Framboise
 - Mangue

D'autres choses plus complexes sont possibles en mélangeant les différentes syntaxes:

# Liste de plusieurs employés
- martin:
  nom: Martin D'vloper
  travail: Developer
  compétences:
    - python
    - perl
    - pascal

- tabitha:
  nom: Tabitha Bitumen
  travail: Developer
  compétences:
    - lisp
    - fortran
    - erlang

Il existe d'autres façon de représenter des listes que nous ne détaillerons pas ici. Pour ça, je vous invite à lire la documentation: http://docs.ansible.com/ansible/latest/YAMLSyntax.html

Les modules

Les modules YAML lus par ansible contiennent des actions à exécuter sous forme de liste de paires clé/valeur. La clé est le nom d'un module à utiliser, la valeur est un ensemble de paramètres qui décrivent plus précisément ce que doit faire le module.

Voici une liste non exhaustive de types de modules disponibles :

  • git,
  • patch,
  • get_url,
  • shell,
  • copy,
  • service,
  • apt,
  • yum,
  • lxc_container,
  • make.

La liste complète est disponible sur le site Ansible:

Si nous voulons télécharger un dépôt git et l'installer à un endroit précis, nous pouvons ajouter l'extrait suivant à notre playbook :

# Exemple d'un téléchargement de source git
- git:
  repo: 'https://git.yoctoproject.org/git/poky'
  version: krogoth
  dest: /home/user/poky

Pour l'exemple de git, des options utiles sont:

  • Pour mettre à jour le repo à chaque exécution update: yes.
    (attention si le dépôt n'est pas propre, Ansible refusera la mise  à jour)
  • Pour créer directement un "git archive" utilisez archive: /path/to/archive.zip

Il est aussi possible de créer soi-même des modules.

Vous trouverez plus d'informations sur la page git_module.

Un module particulier : le module "hosts"

Ce module est obligatoire et doit être instancié en début de fichier YAML, il fait référence aux hôtes configurés précédemment dans le fichier :

/etc/ansible/hosts

Il permet de définir les différents hôtes (nommés Hosts dans le fichier YAML) pour lesquels certaines instructions vont être exécutées.

- hosts: all
  remote_user: root

 

Notre cas d'usage - Ansible et Yocto

Nous avons choisi de détourner l'usage habituel de Ansible pour créer un environnement pour un projet Yocto.

Lorsque l'on utilise Yocto on a souvent plusieurs layers à télécharger, que ce soit sous forme de dépot git ou bien d'archives. Il peut être parfois nécessaire d'appliquer des patchs sur des repos communautaires qui ne sont plus maintenus activement, oui bien d'ajouter des fichiers de configuration; dans ce cas, Ansible peut nous faciliter la vie.

L'hôte

Ansible étant fait pour gérer un parc informatique, il va falloir modifier le contenu de Hosts afin que les actions soient faites localement.
Pour ça il suffit de mettre en début de fichier YAML:

- hosts: 127.0.0.1
  connection: local

Le répertoire de travail

Afin d'avoir le projet construit avec toutes les sources au même endroit, nous allons utiliser une variable externe appelée "TOP_SRCDIR".

Ainsi avec l'option --extra-vars "TOP_SRCDIR=<path_to_top_srcdir> vous pouvez spécifier le répertoire où installer votre projet Yocto :

- name: "Get poky"
  git:
    repo: https://git.yoctoproject.org/git/poky
    version: krogoth
    dest: "{{TOP_SRCDIR}}"

En cas de besoin, il est possible d'appliquer un patch après le clonage du dépôt :

- name: "Patch poky krogoth"
  patch:
    src: /path/to/patch/0001-qemu-Add-space-to-fix-concatenated-SRC_URI.patch
    basedir: "{{TOP_SRCDIR}}"
    strip: 1

Pour les personnes qui souhaitent mettre des règles de commit, il est tout à fait possible d'ajouter un hook local après installation d'un repo git:

- name: "Copy hooks into layer"
  copy:
    src: /path/to/hooks/commit-msg
    dest: "{{TOP_SRCDIR}}/meta-projet/.git/hooks/commit-msg"
    mode: 755

Un exemple complet

Voici un exemple d'un fichier YAML plus complet (nommé mon-fichier.yml) :

- name: "Mon Projet"
  hosts: 127.0.0.1
  connection: local

  tasks:

  - name: "Get poky"
    git:
      repo: https://git.yoctoproject.org/git/poky
      version: krogoth
      dest: "{{TOP_SRCDIR}}"
      update: no

  - name: "Patch poky krogoth"
    patch:
      src: ../0001-qemu-Add-space-to-fix-concatenated-SRC_URI.patch
      basedir: "{{TOP_SRCDIR}}"
      strip: 1

  - name: "Copy hooks into poky"
    copy:
      src: /path/to/hooks/commit-msg
      dest: "{{TOP_SRCDIR}}/.git/hooks/commit-msg"
      mode: 755
  - name: "Get meta-openembedded"
    git:
      repo: http://git.openembedded.org/meta-openembedded
      version: krogoth
      dest: "{{TOP_SRCDIR}}/meta-openembedded"
      update: yes

  - name: "Get meta-linaro"
    git:
      repo: http://git.linaro.org/openembedded/meta-linaro.git
      version: krogoth
      dest: "{{TOP_SRCDIR}}/meta-linaro"
      update: yes

  - name: "Get toolchain"
    get_url:
      url: http://192.168.2.200/src/toolchain/toolchain-M2.1.tgz
      checksum: md5:31a70bd7f7b74724af915a88fbe64f3d
      dest: "{{TOP_SRCDIR}}"

  - name: "Untar toolchain"
    shell: tar xzf {{TOP_SRCDIR}}/toolchain-M2.1.tgz -C {{TOP_SRCDIR}}/sdk/prebuilts/gcc/

Il suffit ensuite de lancer la commande :

$ ansible-playbook mon-fichier.yml --extra-vars "TOP_SRCDIR=/home/user/mon-projet/"

À l'issue de la procédure vous aurez une arborescence du type:

$ tree poky
poky/
├── bitbake
├── build
├── documentation
├── LICENSE
├── meta
├── meta-linaro
├── meta-openembedded
├── meta-poky
├── meta-selftest
├── meta-skeleton
├── meta-yocto
├── meta-yocto-bsp
├── oe-init-build-env
├── oe-init-build-env-memres
├── README
├── README.hardware
├── sdk
├── scripts
└── toolchain-M2.1.tgz

Votre environnement de travail est maintenant prêt à l'utilisation !

Conclusion

Ansible est un logiciel qui peut être détourné pour différentes tâches grâce à ses nombreux modules.

Ceci permet donc de paramétrer la mise en place d'un environnement de build Yocto qui serait décrit dans un seul fichier YAML.

Ainsi, il suffit d'une machine avec Ansible et de partager le fichier de description YAML pour permettre l'initialisation d'un environnement de travail sans intervention manuelle des utilisateurs.

Les liens utiles

Dépôt git:
https://github.com/ansible/ansible

La documentation Ansible est très complète:
http://docs.ansible.com/ansible/latest/index.html

Des exemples de fichier YAML sont disponibles sur le github d'Ansible:
https://github.com/ansible/ansible-examples

Vous pouvez tester la syntaxe vos fichiers YAML sur www.yamllint.com

Il est possible de discuter via IRC sur le chanel #ansible de Freenode.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.