CARE (Comprehensive Archiver for Reproducible Execution) vient de sortir en version 2.1.
CARE est un outil permettant d'observer l'exécution d'une commande Linux (ls, gcc, vlc, …) et de créer une archive contenant l'intégralité des fichiers utilisés lors de l'exécution de cette commande. Il est alors possible d'extraire cette archive sur une autre machine afin de relancer la commande dans le système de fichiers d'origine.
Lors de la ré-exécution, la commande sera entièrement isolée dans l'archive et ne pourra accéder qu'aux fichiers et à l'environnement présent dans cette archive. Il est important de noter que les événements extérieurs (comme les entrées clavier, réseau, …) ne sont pas archivés et doivent, si nécessaire, être recréés par l'utilisateur.
Cas d'usage
CARE peut être utile dans de nombreux cas :
- reproduire chez vous un bug provenant d'un utilisateur ;
- archiver les fichiers nécessaires à une démonstration technique ;
- archiver les fichiers nécessaires à la construction d'une release ;
- créer un système de fichiers minimal permettant d'exécuter une application ;
- créer une application portable.
Reproduire le bug d'un utilisateur
Il est souvent difficile de reproduire les bugs reportés par les utilisateurs du fait de différences dans les versions des bibliothèques installées sur les deux machines.
Grâce à CARE, il est possible pour l'utilisateur d'archiver l'ensemble des bibliothèques (et autre ressources du système de fichiers) utilisées par une application et d'envoyer cette archive au développeur. Celui-ci peut alors plus facilement reproduire l'environnement d'exécution de l'utilisateur.
Usage
La documentation du projet contient un exemple d'utilisation et un manuel assez complet que je vous invite à consulter.
Prenons l'exemple d'un hypothétique problème avec un script Python 3.3
user# care python3.3 foo.py
Hello world!
care info - run `./care-140204124406.bin` or `care -x care-140204124406.bin` to extract the output archive.
CARE a donc lancé le programme (python3.3 foo.py dans notre exemple) et archivé l'ensemble de fichiers accédés dans l'archive auto-extractible care-140204124406.bin
Pour ré-exécuter le programme dans le même environnement mais sur une autre machine n'ayant pas cette version de Python, il suffit de télécharger l'archive sur cette machine et de l'extraire (l'archive est auto-extractible par défaut, mais CARE peut produire d'autres formats au besoin).
user-bis# ./care-140204124406.bin
info: archive found: offset = 1332056, size = 6510234
[...]
info: extracted: care-140204124406/rootfs/usr/bin/python3.3
[...]
user-bis#./care-140204124406/re-execute.sh
Hello world!
Technique
CARE est basé sur PRoot, un moteur d'instrumentation des processus au niveau des syscalls Linux.
Vous trouverez un exemple du fonctionnement de PRoot et de ses cas d'usage sur le site officiel et sur mon blog. J'écrirai probablement une dépêche sur PRoot prochainement.
Aller plus loin
- CARE (460 clics)
- PRoot (135 clics)
- GitHub (110 clics)
- Changelog v2.1 (76 clics)
# Gestion de la liste des fichiers
Posté par Bruno Coudoin (site web personnel) . Évalué à 3.
Dans le cas d'une utilisation pour faire une version portable, est-t-il possible de force l'ajout d'un répertoire ou il faut vraiment aller dans tous les menus de l'application pour accéder et ainsi ajouter tous les fichiers ?
[^] # Re: Gestion de la liste des fichiers
Posté par cedric-vincent . Évalué à 7.
Pour le moment seuls les fichiers et répertoires utilisés sont archivés. Afin de répondre à ton besoin, je viens d'ajouter une tâche dans le tracker. En attendant, il faut que tu accèdes aux fichiers explicitement, par exemple:
à la place de:
# statifier un programme?
Posté par cyberic99 (site web personnel) . Évalué à 2.
Ca a l'air sympa!
Est-il possible, avec cet outil, de 'statifier' un programme utilisant des libs dynamiques?
Cela permet-il d'empaqueter toutes les libs nécessaires, et de lancer le programme sur une autre machine voire une autre distrib?
http://theotherdays.net
[^] # Re: statifier un programme?
Posté par Rémi Duraffort (site web personnel) . Évalué à 8.
C'est exactement cela.
CARE va archiver l'ensemble des fichiers (et donc aussi le loader ELF et les librairies dynamiques) que le programme aura accédé. Donc si lors de la premier exécution, les librairies dynamique en question sont utilisées, elles seront présente dans l'archive.
Lors de la re-exécution, le programme n'aura accès qu'à ces fichiers. Il utilisera donc le même loader ELF et les même librairies dynamiques.
[^] # Re: statifier un programme?
Posté par cyberic99 (site web personnel) . Évalué à 6.
c'est génial! Du coup ca permet de faire des 'bundles' pour distribuer une appli, par exemple?
et au niveau des libs 32 et 64 bits par exemple?
http://theotherdays.net
[^] # Re: statifier un programme?
Posté par cedric-vincent . Évalué à 4.
Exactement.
Les libs nécessaires sont forcément archivées lors de l'exécution originale. Du coup, ce sont celles-ci qui seront ré-utilisées lors de la re-exécution, peu-importe quelles soient 32 ou 64 bits.
[^] # Re: statifier un programme?
Posté par Alex . Évalué à 8.
Ca me parait tout de même joueur
il faut que tu sois sur, lors de la première exécution, d'avoir couvert les cas qui peuvent charger dynamiquement une lib
[^] # Re: statifier un programme?
Posté par Rémi Duraffort (site web personnel) . Évalué à 6.
Le but de CARE est de permettre la re-exécution d'une première exécution de l'application.
Il faut donc effectivement que lors de la première exécution, l'ensemble des actions que tu souhaite être capable de re-exécutées soit au moins exécutées une fois. Permettant à CARE de voir passer les fichiers correspondant.
CARE est un outils d'analyser dynamique (raison pour laquelle il marche sur un large panel de cas d'usage) et comme pour valgrind, il faut que la première exécution couvre les cas d'usage de la re-exécution.
Je m'en suis par exemple servie pour archiver un serveur web (le serveur de test de django). Celui-ci n'est alors capable, lors de la re-exécution, que de servir les pages déjà servies lors de la première exécution.
[^] # Re: statifier un programme?
Posté par Anonyme . Évalué à 6.
ha génial ! nous allons enfin avoir des applications de plusieurs Go comme sous windows :)
[^] # Re: statifier un programme?
Posté par cedric-vincent . Évalué à 6.
Les archives produites par CARE sont relativement petites car elles contiennent uniquement les fichiers nécessaires et sont compressées à la volée (par défaut). Par exemple, l'archive CARE sur le script suivant est de seulement 42 Mo:
Dans ces 42Mo sont compris : les sources de Perl, les programmes Bash, GNU Make, GCC, ainsi que tous les autres programmes et fichiers qui ont été utilisés.
[^] # Re: statifier un programme?
Posté par Krunch (site web personnel) . Évalué à 3.
Pour ce qui est de statifier un programme ELF, il y a déjà http://statifier.sourceforge.net/
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: statifier un programme?
Posté par PolePosition . Évalué à 2.
Bonjour,
Si l'application à "stratifier" accède dynamiquement à des fichiers de lib, selon l'utilisation, et que lors de la "stratification", on utilise qu'un nombre restreint de fonctionnalité de l'application, alors certains fichiers non "stratifiés" pourront être nécessaires lors de l'utilisation ultérieure alors que certains de ces fichiers n'ont pas été ajoutés à l'application "stratifiées" ?
Exemple : si je lance mon application :
Et que, du fait que je ne créé pas de contact (dans la liste doublement chaînée), alors les fonctions d'allocation dynamique de mémoire C ne sont pas appelées, et je serai embêté lors de l'exécution ultérieure ?
L'exemple est peut être mauvais car ces fonctions sont peut être dans un gros fichier .so utilisé pour les autres fonctions accédées genre printf, mais je pense que ça permet d'illustrer ma question.
[^] # Re: statifier un programme?
Posté par Rémi Duraffort (site web personnel) . Évalué à 4.
C'est exactement cela.
CARE a pour but de permettre de re-exécuter une application de la même manière sur plusieurs systèmes différents.
Si je reprends l'exemple de mon application django. Si je fait une archive CARE du serveur servant l'application, je ne pourrais accéder qu'aux pages auxquelles j'ai accédé lors de la première exécution.
CARE n'est pas magique, il ne fait qu'observer le programme afin de détecter les fichiers utilisés et de les archiver. Si les fichiers ne sont pas accédés lors de la première exécution, CARE ne pourra donc pas les archiver. En même temps cela veux dire que tu n'en as pas eu besoin lors de la première exécution et donc que tu n'en aura pas besoin lors de la re-exécution.
Cela permet donc de ne pas créer une archive inutilement volumineuse.
Si tu veux statifier un programme, il faut prendre le temps de faire tous les cas d'utilisations dont tu as besoin après. Souvent ça ne demande pas beaucoup de travail (en tout cas pour les cas que nous avons essayé).
# Génial
Posté par JoeltheLion (site web personnel) . Évalué à 9.
C'est génial. Merci de m'avoir fait connaitre ce projet.
# Nombre aléatoires, Heisenbugs ...
Posté par Thomas Douillard . Évalué à 6.
C'est poussé jusqu'ou ? si on capte un vilain bug mémoire aléatoire ou si on utilises la génération de nombre aléatoire système, ça sera reproduit par exemple ?
[^] # Re: Nombre aléatoires, Heisenbugs ...
Posté par Rémi Duraffort (site web personnel) . Évalué à 10.
CARE va uniquement archiver les fichier accédés et relancer le programme en l'isolant dans l'archive ainsi crée. CARE n'enregistre ni ne rejoue les syscalls de l'application mais laisse l'application s'exécuter normalement (hormis l'isolation dans l'archive).
CARE ne garantit donc pas la reproduction d'un événement purement aléatoire.
Si l'application utilise un élément présent dans /dev, CARE laissera l'application y accéder (afin que celle-ci fonctionner correctement). Le générateur de nombre aléatoire sera donc celui de la machine faisant tourner l'application.
Est-ce que cela réponds à ta question ?
[^] # Re: Nombre aléatoires, Heisenbugs ...
Posté par Thomas Douillard . Évalué à 3.
Tout à fait.
# Yarn, a scenario testing tool
Posté par Sytoka Modon (site web personnel) . Évalué à 3.
Pas tout à fait la même chose mais est aussi utile dans un domaine proche. Yarn permet de faire des tests automatique sur les outils en ligne de commande.
http://blog.liw.fi/posts/yarn/
# CDE: Automatically create portable Linux applications
Posté par JGO . Évalué à 8. Dernière modification le 05 février 2014 à 21:27.
C'est bien d'avoir le choix ! Je pense que c'est similaire à cet outil : http://www.pgbovine.net/cde.html (et pour mémoire, la dépêche correspondante de 2010 : https://linuxfr.org/news/cde%C2%A0-un-outil-pour-le-d%C3%A9ploiement-de-binaires-sans-installation)
[^] # Re: CDE: Automatically create portable Linux applications
Posté par Rémi Duraffort (site web personnel) . Évalué à 5.
Effectivement CDE permet de faire à peu près la même chose que CARE (pour être honnête, CARE est arrivé après CDE).
Par contre (et c'est très important), CDE a 2 gros inconvénients par rapport à CARE :
- CDE n'est plus vraiment maintenu
- CED est plus un prototype qu'un programme bullet proof
Ce qui veux dire que :
- sur un noyaux/glibc récent, CED ne fonctionne pas à cause de certains sycalls non pris en charge
- nous avons beaucoup d'exemple sur lesquels CDE ne marche pas (re-exécution non fonctionnelle), alors que CARE fonctionne correctement
- CDE est beaucoup moins portable que CARE
Sur la portabilité de CARE il sera possible d'écrire un article entier. Pour faire simple :
- CARE est compilé statiquement afin de ne dépendre d'aucune libraires externe (facile à faire avec CDE)
- CARE n'utilise aucun syscall qui n'était pas présent sur le noyaux 2.6.0 (un peu plus technique à faire avec CDE)
- Si le noyaux sur lequel est tourné la re-exécution ne supporte pas certains sycalls demandé par l'application re-exécuté, CARE émulera les syscalls en question, suivant ce qui est disponible sur le noyaux de la machine effectuant la re-exécution (beaucoup plus difficile)
[^] # Re: CDE: Automatically create portable Linux applications
Posté par JGO . Évalué à 3.
Merci pour la réponse. J'ai d'autres questions :
[^] # Re: CDE: Automatically create portable Linux applications
Posté par cedric-vincent . Évalué à 2.
Salut JGO,
CARE n'est pas écrit depuis rien, il se base massivement sur PRoot: techniquement seulement 15% du code de CARE est exclusif, tout le reste provient de PRoot. Ce dernier était initialement une implémentation en mode utilisateur de quelques fonctionnalités noyau, mais au fil du temps il est devenu une base pour d'autres outils souhaitant aussi observer et/ou manipuler des processus sous Linux (CARE en est un exemple typique). En fait, c'est une personne à qui nous étions en train de présenter PRoot qui nous demandé comment celui-ci se comparait à CDE, et ce malentendu c'est transformé en CARE :)
Il est aussi possible de produire des archives au format .tar.gz directement, il suffit de le préciser:
En ce qui concerne le choix du format auto-extractible, comme cela est expliqué dans ce commentaire, l'une des raisons principales est justement que GNU tar contient des bugs. Cependant, afin de rassurer les utilisateurs sur la pérennité de leurs archives auto-extractibles, il existe une documentation sur comment arracher l'archive interne—au format .tar.lzo par défaut—de son enveloppe exécutable.
# Jusqu'où aller ?
Posté par rycks . Évalué à 2.
Bonsoir,
en bref, ça va jusqu'ou ? ça embarque la libc ? ça s'arrête à quel niveau de dépendances ? je suis curieux et éventuellement intéressé mais je n'ai pas le temps (bouuu) de faire des tests … un firefox passé dans care "pèse" combien ? 50 Mo ? 100 Mo ? 500 Mo ?
pour une application qui fait appel à des boites de dialogue gnome ou kde, ça aspire tout gnome/kde ?
merci d'avance,
Éric
eric.linuxfr@sud-ouest.org
[^] # Re: Jusqu'où aller ?
Posté par Rémi Duraffort (site web personnel) . Évalué à 5.
CARE va créer une archive contenant l'intégralité des fichiers accédé, donc y compris :
- ld-linux.so (dans lib/x86_64-linux-gnu pour moi)
- libc.so.6
- tous les fichiers de conf
- les scripts lancés par l'application (par exemple python pour gimp)
- les fichiers de cache utilisés (par exemple /var/cache/fontconfig/…)
Je viens de tester avec Gimp et j'ai une archive de 101Mo.
A propos du temps pour faire un test, il suffit de faire
[^] # Re: Jusqu'où aller ?
Posté par rycks . Évalué à 2.
SUPER !
merci beaucoup pour la réponse, oui ça ne demande pas beaucoup de temps pour tester mais hum, avec 100Ko/s de bande passante et aucun outils de build sur ma machine hier soir j'étais un peu désarmé :)
merci pour la réponse, ça me semble être vraiment un cran au dessus de makeself !
Éric
eric.linuxfr@sud-ouest.org
[^] # Re: Jusqu'où aller ?
Posté par cedric-vincent . Évalué à 5.
Afin de compléter la réponse de Rémi,
Réponse courte: entre 50 et 100 Mo.
Réponse longue: sur ma Slackware64-14.1, l'archive de Firefox 24.2.0 pèse 94 Mo par défaut:
Il est possible d'avoir une archive encore plus petite en demandant à CARE de compresser avec l'algo. de "gzip" plutôt que celui de "lzo":
Et si cela est encore trop gros, il suffit de dire à CARE de ne pas compresser à la volée, et d'utiliser un compresseur plus puissant a posteriori:
Dans ce dernier cas, un outil externe (unxz) sera nécessaire pour décomprésser l'archive avant la re-exécution, ce qui n'est pas le cas lorsqu'on laisse CARE faire la compression (moins performante en taille, mais aussi moins gourmande en temps).
Pour cet exemple, CARE va aspirer les bibliothèques graphiques (libgtk.so ou libqt.so) mais il n'aspirera pas les programmes qui ont été lancés avant lui (gnome ou kde). Il est cependant possible de démarrer gnome ou kde (et même X) sous le contrôle de CARE.
[^] # Re: Jusqu'où aller ?
Posté par Philippe F (site web personnel) . Évalué à 4.
Pour une appli KDE ou Gnome, ca peut poser des problèmes car les applications dépendent d'autres services lancées par le desktop (dbus, …), qui sont accédés via un mécanisme d'IPC. Donc ça ne sera pas embarqué dans l'archive.
La bonne manière de faire est probablement de démarrer carrément KDE avec CARE, mais bonjour la taille de l'archive ! Et encore, est-ce que CARE gère les forks et continue à suivre les deux processus ?
[^] # Re: Jusqu'où aller ?
Posté par cedric-vincent . Évalué à 7.
Pour résoudre ce problème de dépendance à des services "externes", la notion de chemins et variables d'environnement "volatiles" a été introduite dans CARE. Ceux-ci ne sont pas archivés, mais comme "ré-injecté" dynamiquement dans l'archive depuis le système où l'on ré-exécute. Par défaut (on peut les enlever ou en ajouter) les chemins volatiles sont:
et les variables d'environnement volatiles sont:
Cela implique que le système où l'on ré-exécute possède un service "compatible", ou bien d'archiver le service avec. Par exemple en démarrant KDE sous CARE, comme tu l'as suggèré.
Je viens de tester "care startkde" en laissant bien le temps à KDE d'accéder à toutes ses ressources (icons, .desktop, …): le .bin fait 203Mo et le .tar.xz fait 95Mo. À noter qu'il n'y a pas le serveur X dans cette archive.
Oui, il n'y a vraiment aucun soucis avec les applications multi-processus et/ou multi-threadées.
# Le format du fichier de sortie
Posté par jben . Évalué à 5.
Tout d’abord, je suis fan, et je trouve cela génial.
Par contre il y a des points qui me dérangent dans le format du fichier de sortie.
Déjà, le choix de binaire auto-extractible, je trouve cela inutile, et non usuel, mais soit. Tu propose le format tar, et je t'en remercie. Par contre, ce qui est mal c'est que tu fais le choix du format avec le nom de fichier.
Par exemple, si je veux faire une compression xz à la volée, je hais les fichier temporaires, je suis obligé de faire un:
et
Si tu supportais une option du genre format, ayant priorité sur l'extension pour choisir le format, je pourrais faire un truc du genre
C'est quand même plus élégant !
En plus en travaillant de cette manière (et en documentant) tu n'as même plus à gérer la compression, il faut juste que les utilisateurs apprennent à utiliser leur shell.
Tu pourrais me répondre que procéder ainsi rajoute de la latence et c'est inutilisable, mais c'est juste pour l'exemple. Car en vrai j'utiliserai plutôt un truc du genre
avec
bufcat
un truc qui envoie stdin sur stdout (énorme!) mais en mettant en cache quand stdin est plus rapide que stdout pour ne pas bloquer le processus émetteur. Je viens de tester avec la méthode fifo et bufcat, ça fonctionne au poil sans latence, xz tourne juste avec un décalage.On pourrait directement imaginer aussi des truc du genre
Oui, je sais, ma haine des fichiers temporaires est maladive. Mais globalement je trouve ton programme absolument génial à ce détail près (et aussi à mon incompréhension des autoextractibles, mais ça ne doit pas correspondre à mon usage).
[^] # Re: Le format du fichier de sortie
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 2.
Qu'est-ce que c'est que cette syntaxe-là
>( … )
? Je doute que ce soit du shell POSIX ça, et j'ai peur que ça ne fonctionne exactement comme ce que tu cherches à éviter de faire : en créant un tube nommé et en l'utilisant comme entrée standard de la commande entre parenthèses. En effet, le shell va devoir passer quelque chose en argument de cette option-o
, et ce quelque chose, à part un tube nommé, je ne vois pas ce que ça pourrait être de sensé…Il me semblerait plus simple d'écrire :
[^] # Re: Le format du fichier de sortie
Posté par jben . Évalué à 3.
/dev/stdout
doit être laissé au programme lancé.Les syntaxes
>( )
(respectivement<( )
) créent un sous-shell et un déscripteur de fichier, et lestdin
(respectivement lestdout
) du sous-shell correspond au file descriptor. Je confirme ça marche ce genre de syntaxe fonctionne avecbash
etzsh
, mais en effet c'est pas POSIX à ma connaissance.Par exemple si tu tape un
echo <(true)
, tu verra le fd créé (ou plus exactement attribué) par le shell.En utilisant ce genre de syntaxe, tu peux faire des truc sympa, genre rajouter ça dans le
~/.bashrc
de quelqu'un qui a laissé sa session ouverte :Autre exemple assez marrant, et utile. Pour calculer un condensat sha1 en plein milieu d'un pipeline :
[^] # Re: Le format du fichier de sortie
Posté par cedric-vincent . Évalué à 8.
J'aime bien l'idée du compresseur "quelconque" qui tourne à l'extérieur de CARE, ainsi que le transfert réseau à la volé ; c'est très utile sur des plates-formes où l'espace disque est très faible. Même si c'est faisable avec un tube nommé, l'option -f est bien plus élégante ; j'achète donc ton idée avec plaisir :D Ce sera disponible certainement dans la prochaine version.
Dans le cas de CARE, il y a deux raisons pour l'usage par défaut du format auto-extractible. La première est une volonté forte de ne dépendre de rien lors de la ré-exécution, c'est pour cela que proot est intégré dans l'archive par exemple: il n'y a pas besoin de récupérer un "player" comme on peut le voir avec des VMs. La seconde raison est plus technique, il s'agit d'éviter des bugs connus dans des outils tels que GNU tar ou GNU cpio (on ne peut pas faire l'hypothèse que l'utilisateur aura une version corrigée, d'autant plus qu'elle n'existe pas aujourd'hui). Pour faire court, ces bugs sont très facilement exposés avec CARE (de part sa nature "dynamique") mais ils peuvent être reproduit avec GNU tar aussi. Par exemple:
C'est un problème qui n'est pas corrigé dans GNU tar, qui est corrigé que partiellement dans GNU cpio, mais complétement dans libarchive. CARE se base donc sur ce dernier pour fournir l'option -x et le format auto-extractible.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.