Gestion de configuration avec Rudder sur Android

Magazine
Marque
GNU/Linux Magazine
HS n°
Numéro
61
Mois de parution
juillet 2012
Spécialité(s)


Résumé
La gestion de configuration est de plus en plus à la mode, à cause des problématiques actuelles de scalabilité et de provisioning de machines en masse dans le cloud. Une autre chose qui soit présente en masse dans une entreprise ou même chez Madame Michu, ce sont les terminaux mobiles et les tablettes. C'est de ce constat qu'est née une idée un peu originale : pourquoi ne pas essayer d'associer le meilleur des deux mondes ?

Body

1. Présentation des principes de la gestion de configuration

1.1. Introduction générale

La gestion de configuration est un concept qui essaie de répondre à des problématiques bien connues de tout administrateur système/réseau en charge d’une infrastructure de plus de 4 machines :

- Toutes mes machines sont-elles à jour ?

- Ce petit correctif que j’ai apporté à la configuration de X, est-il bien présent partout ?

- Si une de mes machines explose/prend feu/se transforme en raton-laveur, serai-je à même de tout reconfigurer correctement dessus pour que ça marche comme je veux ? Et aurai-je le temps de tout faire correctement ?

On peut trouver d’autres exemples du même genre, mais une information importante ressort déjà : passé un petit nombre de machines (tout dépend de la personne), il devient impossible de savoir à un instant T « où on en est ». Et le problème empire quand on n’est pas le seul à gérer tout ça, ce qui j’espère, est le cas dans une infrastructure d’entreprise ou d’association.

Le concept de gestion de la configuration tente de répondre à ce problème, en proposant plusieurs approches (différentes selon les outils) afin de garder un parc cohérent.

Bien sûr, la récente mode du cloud computing et de la scalabilité offre une toute nouvelle dimension à ce concept, en en faisant même une des bases incontournables de tous les gros systèmes de cloud provisioning du moment.

En effet, il devient possible, grâce à un outil de gestion de configuration, de faire un provisioning complet d’une VM, en déployant uniquement des images de base intégrant l’outil choisi, qui se charge au premier démarrage d’installer les services qui seront nécessaires, en fonction de son environnement.

Il est aussi possible, grâce à des outils comme Vagrant (http://www.vagrantup.org) de faire ceci à l’échelle d’un poste de travail, permettant par exemple à un développeur de redéployer des environnements de test propres à volonté.

1.2. CFEngine 3

Différents outils existent pour faire de la gestion de configuration, et ils ont presque tous déjà été couverts par un article dans GLMF ou GLMF hors-série : Puppet, CFEngine 2, Chef...

CFEngine 3 (http://www.cfengine.com) est une réécriture à partir de zéro de CFEngine 2 (vu dans GLMF n° 95), suite aux nombreux retours de la communauté et à ce qui a été appris pendant et après la création de Puppet par un contributeur de CFEngine 2.

cfengine_history

Fig. 1 : Historique de l'évolution de CFEngine dans le temps

CFEngine 3 est donc un outil de gestion de configuration moderne, entièrement réécrit récemment, qui se base sur la théorie des promesses (http://en.wikipedia.org/wiki/Promise_theory), nom donné aux configurations à appliquer par l’outil.
Voici un exemple simple d’utilisation de CFEngine 3 :

#############################
# Promesse de création de fichier #
#############################
# Le body common control définit ce qui doit être fait par l’agent CFEngine.
body common control
 # J’inclus ces fichiers de promesses
 inputs => { "/var/cfengine/inputs/cfengine_stdlib.cf" };

 # J’exécute ces bundles
 bundlesequence => { "create_foobar_in_tmp" };
}
# Ce bundle va servir à définir le contenu d’un fichier
bundle agent create_foobar_in_tmp {
# Les promesses qui suivent agissent sur un fichier
 "/tmp/foobar"
 create => “true”,

 # Si le fichier n’existe pas, je le crée
 # Je crée des classes en fonction de la tenue de la promesse:

 # file_ok si la promesse est tenue, file_nok si ce n’est pas le cas.

 # Note: Il est possible d’utiliser trois types d’états en pratique:

 # Promesse tenue, réparée ou non tenue. On considère ici par simplicité

 # qu’une promesse réparée est tenue.

classes => if_else("file_ok", "file_nok");

files_ok::

 "The file is present";
 files_failed::
 "The file has NOT been created.";

}

1.3. Rudder

CFEngine 3 est un outil très puissant ; il permet à peu près de tout faire avec sa machine, du moment où on est capable de décrire l’état voulu en une promesse du langage CFEngine. Seulement, cette puissance a un prix : il est difficile pour un débutant de pouvoir maîtriser CFEngine rapidement, la courbe d’apprentissage étant assez longue. C’est là que Rudder entre en jeu !

Le projet Rudder (http://www.rudder-project.org) permet une accessibilité simplifiée à la gestion de configuration, via une interface web disposant de promesses déjà pré-conçues. Cette interface vient se poser en tant qu’intermédiaire entre l’utilisateur et CFEngine 3 et lui permet, par exemple, de configurer le serveur OpenSSH sur un groupe de machines simplement en remplissant un formulaire web et en associant la définition ainsi créée à un groupe de serveurs. Rudder se charge ensuite de remonter des informations sur l’application de ces promesses (« Compliance »).

rudder_android_snapshot

Fig. 2 : Écran principal de Rudder, qui permet de gérer les associations entre une directive (une instance configurée d'une technique) et un groupe de machines.

Rudder utilise en fond plusieurs technologies : Scala, PostgreSQL, OpenLDAP, FusionInventory... Bref, Rudder est bien, Rudder est beau, Rudder fait revenir l’être aimé et donne un poil doux et soyeux. Mais soyons sérieux. Gérer ses machines, c’est bien, tout le monde sait le faire. Ton Rudder, là, il fait quoi de mieux ?

Eh bien, voilà : Rudder utilise CFEngine, et CFEngine a très peu de dépendances. Une bibliothèque Tokyo Cabinet, OpenSSL, PCRE et une libc et il est heureux. Et ça tombe bien, Android possède tout ça ! Sans compter que de par son ascendance libre et sa relative ouverture, on l'aime bien Android par chez nous. Maintenant, imagine-toi, gérer un smartphone (voire un parc de smartphones) ou une tablette avec une interface web à distance, de manière conviviale, et avoir tous les avantages de la gestion de configuration ?
Avec un peu d’huile de coude, c’est devenu possible ! Voyons de quelle manière... À toi, Cédric !

2. Gestion de configuration sur Android

2.1. Environnement

Pour intégrer CFEngine, et donc Rudder, dans Android, nous avons choisi de créer une ROM complète personnalisée. Cette approche permet d’avoir une plus grande flexibilité de développement. En effet, toutes les en-têtes et bibliothèques du projet Android sont directement accessibles, ce qui n’est pas forcément le cas avec le NDK.

Pour nos tests, nous avons utilisé le projet Buildroid (http://www.buildroid.org) qui permet de créer une image pour VirtualBox / x86. Buildroid utilise les sources d’Android en version 4.0.3_r1. Il est aussi possible d’utiliser l’émulateur fourni en standard avec les sources.

2.2. Compilation de CFEngine

L’Android Open Source Project assemble le code source de différents projets. Certains sont spécifiques à Android et ont été intégralement écrits par Google (la libc Bionic, la machine virtuelle Dalvik, le framework Android). D’autres proviennent de projets open source externes (SQLite, zlib, kernel Linux, …). Tous ces projets sont mis en commun, à la manière d’une distribution Linux, pour créer la ROM qui tourne sur votre téléphone. Il est bien sûr possible d’ajouter des projets externes pour personnaliser cette ROM. Cela se fait en 3 étapes :

1) Ajout des sources du projet dans l’arbre des sources existant (typiquement dans le dossier external) ;

2) Écriture d’un fichier Android.mk pour décrire les étapes de compilation et de liens des différents éléments (bibliothèque, binaire, …). Il est possible de séparer le travail dans plusieurs fichiers Android.mk (par exemple, un par dossier) ;

3) Modification du code pour l’adapter à Android.

L’écriture d’un fichier Android.mk n’est pas très compliquée, il suffit souvent de s’inspirer des nombreux autres exemples présents dans AOSP. Vous pouvez aussi consulter le précèdent GLMF hors-série sur Android (n°60), qui contient un article avec un cas concret. Pour résumer, un fichier Android.mk est constitué de blocs qui ressemblent à ça :

include $(CLEAR_VARS)
LOCAL_SRC_FILES:= foo.c bar.c
LOCAL_C_INCLUDES:= external/otherproject/include
LOCAL_SHARED_LIBRARIES:=libotherproject
LOCAL_MODULE:= awesomebinary

include $(BUILD_EXECUTABLE)

Ce qui se lit : compile les fichiers foo.c et bar.c avec les en-têtes que tu trouveras dans external/otherproject/include, fais l’édition des liens avec la bibliothèque partagée libotherproject et produis l'exécutable awesomebinary.

Nous allons maintenant voir en quoi tout cela nous permet de construire un binaire pour CFEngine et donc, de faire tourner l’application tant attendue.

2.2.1. OpenSSL

La bibliothèque OpenSSL (http://www.openssl.org) est utilisée afin de générer les clés nécessaires à la communication entre l’agent et le serveur CFEngine. On a de la chance, OpenSSL (libcrypto.so) est déjà présente dans AOSP, il suffit donc d’ajouter les directives suivantes pour tous les modules qui en ont besoin :

LOCAL_C_INCLUDES += external/openssl/include

LOCAL_SHARED_LIBRARIES := libcrypto

2.2.2. Tokyo Cabinet

Tokyo Cabinet est une base de données clé/valeur. Ce projet n’existe pas dans AOSP, cependant on trouve sur Github quelqu’un qui a fait le travail de portage (https://github.com/white-gecko/TokyoCabinet). Merci à lui, il a juste suffit de mettre à jour le fichier Android.mk qui n’était pas compatible ICS.

2.2.3. PCRE

La bibliothèque PCRE est une bibliothèque d’expressions régulières. Le code est présent dans AOSP, cependant, il fait partie des quelques projets qui sont compilés pour l’hôte et non pour la cible (il est utilisé dans un outil de développement du SDK). On peut s’en sortir avec une astuce qui consiste à compiler (une deuxième fois) les sources de PCRE avec un Android.mk situé dans les sources de CFEngine. Pour cela, on crée un fichier Android.mk, qui contient la même chose que celui de PCRE, à la seule différence qu’on fait une compilation pour la cible.

C’est-à-dire que l’on remplace :

include $(BUILD_HOST_STATIC_LIBRARY)

par :

include $(BUILD_STATIC_LIBRARY)

Ici, le fichier Android.mk n’est pas situé dans le même répertoire que ses sources, il faut donc changer la variable LOCAL_PATH qui indique l’emplacement des sources. Un fichier de build classique commence toujours par :

LOCAL_PATH:= $(call my-dir)

Pour dire que les sources sont dans le même dossier que le fichier Android.mk, ici on va le remplacer par :

LOCAL_PATH := external/pcre

Mais ce n’est pas fini, on ne peut pas avoir deux modules avec le même nom :

LOCAL_MODULE := libpcre

En fait, ce nom correspond à une cible dans un grand Makefile constitué de tous les fichiers Android.mk concaténés. On le change, par exemple :

LOCAL_MODULE := libpcre_target

Comme on compile une bibliothèque statique (i.e. un fichier « .a », car on a précisé BUILD_STATIC_LIBRARY), le nom a peu d’importance, car il ne sera jamais sur la machine cible. Il suffira juste d’être cohérent dans les autres Android.mk.

2.2.4. CFEngine

Le code se compile presque tout seul ! Il y a juste un changement à faire dans l’utilisation d'OpenSSL, CFEngine utilise une fonction dépréciée d’OpenSSL, qui n’est pas présente dans la version Android (rsa_generate_key que l’on remplacera par rsa_generate_key_ex). Le plus dur est l’écriture du Android.mk. La compilation de CFEngine se base sur les autotools. Le processus est classique : l’appel au script configure produit un fichier conf.h spécifique à la cible, ainsi que plusieurs Makefiles.
Les Makefiles permettent de compiler les différents binaires et bibliothèques utilisés par CFEngine.

Le processus de construction d’Android n’est pas compatible avec les autotools. Il faut donc générer le fichier conf.h, puis écrire le(s) fichier(s) Android.mk en se basant sur les Makefiles du projet. Pour générer le fichier conf.h, nous allons lancer le script de configuration en mode cross compilation.

On commence par ajouter le chemin du compilateur Android au PATH. Le SDK fournit un compilateur pour chaque plateforme cible (ici, on compile pour Buildroid, c’est-à-dire en x86) :

export PATH=$PATH:/path/to/android/prebuilt/linux-x86/toolchain/i686-unknown-linux-gnu-4.2.1/bin

Puis, on ajoute le chemin vers les bibliothèques déjà compilées, ainsi que les chemins vers les en-têtes. L’option -nostdlib est nécessaire pour ne pas être « pollué » avec les ressources de la machine de développement.

export LDFLAGS="-L/path/to/android/prebuilt/ndk/android-ndk-r6/platforms/android-9/arch-x86/usr/lib -L/path/to/android/out/target/product/vbox86tp/system/lib -lz -lc -lstdc++ -lm -ldl -lcrypto -lpcre"
export CFLAGS="-nostdlib -I/path/to/android/prebuilt/ndk/android-ndk-r6/platforms/android-9/arch-x86/usr/include -I/path/to/android/external/tokyocabinet

...”

On peut lancer le script en précisant l’hôte et la racine du système.

./configure --prefix=/tmp/cf --with-sysroot=/path/to/android/src/prebuilt/linux-x86/toolchain/i686-linux-glibc2.7-4.4.3/sysroot/ --host=i686-unknown-linux-gnu

Pour arriver au bon résultat, il faut le passer par une phase d’essai/erreur avant de trouver le bon jeu d’options. Si on connaît bien sa plateforme, il toujours possible de créer le fichier conf.h à la main (à partir du template conf.h.in). Cette étape est faite une seule fois, il n’est pas possible (du moins pas simplement) de l’intégrer à la phase de compilation du projet. On va donc ajouter le fichier conf.h au gestionnaire de sources...

Normalement, les personnes encore réveillées doivent crier… Oui, ce type de fichier doit être généré pour chaque cible et ne doit pas être distribué avec le code. Pour ma défense, je peux citer des exemples dans AOSP. Plus sérieusement, il faut se méfier de cette méthode, car on peut avoir des surprises en cas de changement de version d’Android et/ou de plateforme.

L’étape de configuration nous a aussi créé une collection de makefiles, reste à les convertir en Android.mk. Les Makefiles générés par les autotools ne sont pas toujours lisibles, mais il existe un outil qui fait une partie du travail automatiquement : androigenizer (http://cgit.collabora.com/git/user/derek/androgenizer.git/, http://blogs.igalia.com/eocanha/2012/01/30/from-source-code-to-ndk-build-using-autotools-and-androgenizer/). Le principe est d’ajouter une règle dans les fichiers Makefile.am, qui va appeler l’outil androigenizer pour générer les fichiers Android.mk. Il est toujours possible de les modifier à la main, mais on a déjà une partie du travail de fait. Une fois cela fait, CFEngine doit compiler pour votre Android ! Il suffit de lancer la compilation de l’image complète.

2.3. Outils pour Rudder

Nous venons de voir les dépendances de compilation, mais les règles CFEngine utilisées par Rudder ont besoin de divers outils sur la plateforme pour bien fonctionner.

2.3.1. FusionInventory

Solution bien connue des administrateurs de grand parc, FusionInventory est un outil d’inventaire, réécriture de l’agent OCS Inventory, qui permet de remonter diverses informations sur les machines (matériel, paquets installés, …).

Il existe un agent Android disponible sur Google Play. L’agent est constitué d’un service et d’une activité pour le configurer. Par défaut, le service envoie ses résultats vers un serveur Fusion de manière autonome avec une fréquence configurable. Ici, on souhaite que CFEngine se charge de cette tâche, il suffit de modifier le code Java pour ajouter une option d’enregistrement des résultats sur carte SD. CFEngine ira chercher le fichier XML généré par FusionInventory et l’enverra grâce à curl.

2.3.2. curl

Curl est utilisé pour envoyer les résultats de FusionInventory vers le serveur Rudder. Le package upstream propose un Android.mk, il faut un peu le modifier pour l’adapter à ICS. Les développeurs de curl n’ont pas pris le risque de fournir un curl_config.h généré par le script configure, mais ils expliquent comment le générer (de façon similaire à ce que nous avons fait pour CFEngine).

2.3.3. syslog

Les agents Rudder utilisent syslog afin de permettre au serveur de savoir si une tâche est terminée et permettre de remonter des informations d’exécution au serveur. La libc d’Android (Bionic) implémente la fonction syslog(3), mais il n’y a pas d’implémentation du serveur syslogd(8). Heureusement, Busybox en propose une. Le plus simple est de prendre la version de Cyanogenmod ( https://github.com/CyanogenMod/android_external_busybox) qui est déjà prête pour Android. Busybox nous servira aussi pour fournir différents outils de scripting au niveau des règles CFEngine.

Il faut ensuite activer syslog qui ne l’est pas par défaut, puis compiler Busybox. La compilation va échouer, car le fichier syslog.h est très peu fourni dans AOSP (il manque la définition des facilities et des priorities). On peut définir ses structures du côté Busybox (en fait, elles le sont déjà, mais commentées). Il faut aussi changer le chemin vers la socket syslog, qui est codée en dur sur /dev/log. Sur Android, ce chemin correspond à un dossier, il faut donc trouver un autre nom. Le changement est aussi à faire dans Bionic.

2.4. Portage de Rudder sur Android

La partie la plus dure étant faite, il a fallu tester le fonctionnement de l’agent Rudder existant sur Android. Et il a fallu une armée entière d’au moins... deux hommes pour y parvenir.

Android étant considéré comme une machine Linux au niveau de CFEngine, une grande partie des définitions existantes dans les promesses de Rudder ont pu être conservées. Il a fallu ajuster une partie des chemins utilisés par Rudder (/opt/rudder et /var/rudder) dans la promesse qui les définit (site.st), et des commandes, mais aucune modification majeure des promesses n’a dû être effectuée ! Bien sûr, il faut maintenant adapter toute la librairie de « Techniques », qui sert de référence pour toutes les tâches que peut accomplir Rudder, mais le plus dur est fait.

Il suffit de savoir utiliser les possibilités du shell d’Android, par exemple la commande pm permet de manipuler les paquets, la commande am d’envoyer des intents arbitraires, etc. Si on ajoute quelques outils comme busybox et curl, on a presque l’impression d’administrer un GNU/Linux standard !

Pour les personnes intéressées, tout le travail effectué pour rendre les promesses compatibles est disponible sur GitHub (https://github.com/Normation/rudder-techniques/tree/branches/rudder/android_support_2.4).

rudder_snapshot

Fig. 3 : Et pour prouver que tout cet article n'est pas que du vent, voici la capture d'écran réglementaire de l'outil en fonctionnement !

« Tiens, pourquoi cette machine ne répond plus ? »

N'oublions surtout pas : la gestion de configuration c'est vachement bien, certes, mais cela induit aussi des responsabilités. Comme on dit souvent dans le jargon :  « Casser une seule machine, c'est humain. Mais pour réussir à casser un parc entier, il te faut un outil de gestion de configuration ». Sans exagérer, il est important de suivre des procédures strictes de tests avant de déployer de nouvelles instructions de configuration, au risque non pas de « casser le parc » (ce qui serait tout de même un manque gravissime de chance), mais de bloquer certains services ou d'impacter la sacro-sainte production.

Conclusion

L’installation de Rudder, et par extension CFEngine, sur un OS Android s’est révélée à la fois une expérience très stimulante mais aussi, et c’est surprenant, relativement facile. Les outils proposés sont fonctionnels, et pour une fois on n’a pas affaire à une toolchain proposée par un éditeur qui est toute cassée, dont il manque des includes de partout et qui finit par ramasser un rm -rf et de vertes insultes dans la figure.

Bien qu’à la base ce portage ait eu comme but de créer une démonstration technologique (« On peut le faire »), elle a permis d’aller bien plus loin et de se dire que « bah oui, c’est faisable, et c’est même largement envisageable !!! ».

Bien sûr, il reste encore pas mal d’étapes à faire, notamment du packaging et des ajustements pour rendre tout ça totalement Android-friendly, mais on peut aujourd'hui envisager que Rudder soit un jour installable directement via le Play Store. Et ça, ça serait vraiment bien !




Article rédigé par

Par le(s) même(s) auteur(s)

Les derniers articles Premiums

Les derniers articles Premium

La place de l’Intelligence Artificielle dans les entreprises

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

L’intelligence artificielle est en train de redéfinir le paysage professionnel. De l’automatisation des tâches répétitives à la cybersécurité, en passant par l’analyse des données, l’IA s’immisce dans tous les aspects de l’entreprise moderne. Toutefois, cette révolution technologique soulève des questions éthiques et sociétales, notamment sur l’avenir des emplois. Cet article se penche sur l’évolution de l’IA, ses applications variées, et les enjeux qu’elle engendre dans le monde du travail.

Petit guide d’outils open source pour le télétravail

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Ah le Covid ! Si en cette période de nombreux cas resurgissent, ce n’est rien comparé aux vagues que nous avons connues en 2020 et 2021. Ce fléau a contraint une large partie de la population à faire ce que tout le monde connaît sous le nom de télétravail. Nous avons dû changer nos habitudes et avons dû apprendre à utiliser de nombreux outils collaboratifs, de visioconférence, etc., dont tout le monde n’était pas habitué. Dans cet article, nous passons en revue quelques outils open source utiles pour le travail à la maison. En effet, pour les adeptes du costume en haut et du pyjama en bas, la communauté open source s’est démenée pour proposer des alternatives aux outils propriétaires et payants.

Sécurisez vos applications web : comment Symfony vous protège des menaces courantes

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Les frameworks tels que Symfony ont bouleversé le développement web en apportant une structure solide et des outils performants. Malgré ces qualités, nous pouvons découvrir d’innombrables vulnérabilités. Cet article met le doigt sur les failles de sécurité les plus fréquentes qui affectent même les environnements les plus robustes. De l’injection de requêtes à distance à l’exécution de scripts malveillants, découvrez comment ces failles peuvent mettre en péril vos applications et, surtout, comment vous en prémunir.

Bash des temps modernes

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Les scripts Shell, et Bash spécifiquement, demeurent un standard, de facto, de notre industrie. Ils forment un composant primordial de toute distribution Linux, mais c’est aussi un outil de prédilection pour implémenter de nombreuses tâches d’automatisation, en particulier dans le « Cloud », par eux-mêmes ou conjointement à des solutions telles que Ansible. Pour toutes ces raisons et bien d’autres encore, savoir les concevoir de manière robuste et idempotente est crucial.

Les listes de lecture

9 article(s) - ajoutée le 01/07/2020
Vous désirez apprendre le langage Python, mais ne savez pas trop par où commencer ? Cette liste de lecture vous permettra de faire vos premiers pas en découvrant l'écosystème de Python et en écrivant de petits scripts.
11 article(s) - ajoutée le 01/07/2020
La base de tout programme effectuant une tâche un tant soit peu complexe est un algorithme, une méthode permettant de manipuler des données pour obtenir un résultat attendu. Dans cette liste, vous pourrez découvrir quelques spécimens d'algorithmes.
10 article(s) - ajoutée le 01/07/2020
À quoi bon se targuer de posséder des pétaoctets de données si l'on est incapable d'analyser ces dernières ? Cette liste vous aidera à "faire parler" vos données.
Voir les 65 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous