Git pre-commit hook : Vérification de fichiers PHP et Shell avant de les commiter

Quand on utilise un gestionnaire de sources comme Git ou Subversion (si vous n’en utilisez pas pour vos développements, vous connaissez la priorité n°1 sur votre liste de tâches), il est très facile de faire en sorte que les fichiers que l’on cherche à commiter sur le serveur soient vérifiés avant d’être effectivement acceptés.
Cela permet d’éviter de propager du code incorrect, qui ne compile pas, avant même qu’il ne se retrouve sur le dépôt de sources (et donc chez les autres développeurs voire dans un processus d’intégration continue).

J’utilise Git avec un fournisseur de service SaaS (Github, mais j’ai aussi utilisé Bitbucket), et je suis donc obligé de mettre en place le script de pre-commit sur le poste de développement local. À la racine d’un repository Git, il y a un sous-répertoire “.git/hooks” qui sert à contenir les hooks, c’est-à-dire les programmes à exécuter en fonction de l’action effectuée. Par défaut, ce répertoire contient des exemples de scripts dont vous pouvez vous inspirer pour créer les vôtres (en shell).

Idéalement, il faudrait vérifier la syntaxe des fichiers quand on les ajoute avec “git add” ; malheureusement, il n’y a pas de hook sur cette étape. On est donc obligé d’attendre le moment où on tente de commiter les fichiers, mais cela implique qu’en cas d’erreur il faudra ajouter de nouveau la version corrigée du fichier, puis de retenter le commit.

Pour prendre la main juste avant que le commit ne soit effectué, il faut écrire un script nommé “pre-commit”, et le déposer dans le répertoire “.git/hooks” de votre repository. Ce script doit retourner une valeur égale à zéro si tout s’est bien passé, et une valeur supérieure à zéro si on a rencontré une erreur dans un fichier qui s’apprête à être commité.

Mon hook a pour but de vérifier que les fichiers PHP que je commite sont corrects du point de vue syntaxique (testé avec la commande “php -l ”), ainsi que les scripts shell (en utilisant l’outil shellcheck). Si des erreurs sont trouvées dans certains fichiers, elles sont affichées et le commit est interrompu.

Le hook est codé en PHP. Avant j’utilisais des scripts shell, mais je suis passé au PHP pour deux raisons : certains traitements sont plus simples en PHP qu’en shell (gestion des tableaux, manipulation de chaînes…) ; et j’ai ajouté la vérification de syntaxe pour des templates Smarty (le seul moyen de vérifier la syntaxe d’un template Smarty est d’interpréter le template, et ça ne peut être fait qu’avec du code PHP).

Version sans vérification Smarty

Pour commencer, je vais vous donner le code de mon script de pre-commit sans la vérification des fichiers Smarty (tout le monde n’en a pas besoin).

Vous pourrez remarquer que ce script utilise l’objet ANSI de ma bibliothèque FineBase, afin d’écrire dans la console en utilisant les directives ANSI (pour afficher des messages en gras, en couleur, etc.).
Vous pouvez aussi voir que ce script s’attend à ce que le programme shellcheck soit installé dans le répertoire /usr/bin (répertoire d’installation par défaut sur Ubuntu, mais aussi sur la plupart des distributions Linux).

#!/usr/bin/php
<?php

require_once('finebase/Ansi.php');

// repo root path
$rootPath = exec('git rev-parse --show-toplevel', $res, $ret);
if ($ret) {
        exit(0);
}
unset($res);

// get list of files
exec('git diff --cached --name-only --diff-filter=ACMR', $files);
if (!is_array($files)) {
        exit(0);
}
// array of errors
$errors = [
        'php' => [],
        'tpl' => [],
        'sh'  => [],
];
// process all files
$smarty = $compileDir = $cacheDir = null;
foreach ($files as $file) {
        if (substr($file, -4) == '.php') {
                // check PHP file syntax
                exec("git show :$file | php -l > /dev/null", $errors['php'], $ret);
        } else {
                // check inside the file
                $fp = fopen("$rootPath/$file", 'r');
                $shebang = trim(fgets($fp));
                fclose($fp);
                if ($shebang != '#!/bin/bash' && $shebang != '#!/bin/sh')
                        continue;
                // check shell file syntax
                if (!file_exists('/usr/bin/shellcheck')) {
                        print(Ansi::color('yellow', "⚠ Can't check shell script. You should install 'shellcheck'."));
                        continue;
                }
                exec("/usr/bin/shellcheck -s bash -f gcc $rootPath/$file", $checklines, $ret);
                if (!$ret)
                        continue;
                foreach ($checklines as $checkline) {
                        $check = explode(':', $checkline);
                        if (trim($check[4]) == 'error') {
                                $errors['sh'][] = $checkline;
                        }
                }
        }
}
// display errors
$return = 0;
if (!empty($errors['php'])) {
        print(Ansi::color('red', "⛔ ERRORS IN PHP FILE(S)\n"));
        foreach ($errors['php'] as $err) {
                print(" $err\n");
        }
        $return = 1;
}
if (!empty($errors['sh'])) {
        print(Ansi::color('red', "⛔ ERRORS IN SHELL FILE(S)\n"));
        foreach ($errors['sh'] as $err) {
                print(" $err\n");
        }
        $return = 2;
}
exit($return);

 

Version avec vérification Smarty

Cette version est juste un peu plus complète. Elle remonte toutes les erreurs de syntaxe que pourraient contenir les fichiers PHP, Shell et Smarty qu’on s’apprête à commiter.

#!/usr/bin/php
<?php

require_once('finebase/Ansi.php');
require_once('smarty3/Smarty.class.php');

// repo root path
$rootPath = exec('git rev-parse --show-toplevel', $res, $ret);
if ($ret) {
        exit(0);
}
unset($res);

// get list of files
exec('git diff --cached --name-only --diff-filter=ACMR', $files);
if (!is_array($files)) {
        exit(0);
}
// array of errors
$errors = [ 
        'php' => [], 
        'tpl' => [], 
        'sh'  => [], 
];
// process all files
$smarty = $compileDir = $cacheDir = null;
foreach ($files as $file) {
        if (substr($file, -4) == '.php') {
                // check PHP file syntax
                exec("git show :$file | php -l > /dev/null", $errors['php'], $ret);
        } else if (substr($file, -4) == '.tpl') {
                // check Smarty file syntax
                if (!$smarty) {
                        $compileDir = sys_get_temp_dir() . '/git_commit_smarty_compile';
                        $cacheDir = sys_get_temp_dir() . '/git_commit_smarty_cache';
                        if (!is_dir($compileDir)) {
                                mkdir($compileDir);
                        }
                        if (!is_dir($cacheDir)) {
                                mkdir($cacheDir);
                        }
                        $smarty = new \Smarty();
                        $smarty->compile_dir = $compileDir;
                        $smarty->cache_dir = $cacheDir;
                        $smarty->error_reporting = E_ALL & ~E_NOTICE;
                        // add here your list of Smarty plugin path
                        $pluginPathList = ['/path/to/lib/smarty'];
                        $pluginPathList = array_merge($smarty->getPluginsDir(), $pluginPathList);
                        $smarty->setPluginsDir($pluginPathList);
                }
                try {
                        // define the root dir of your templates, which should be a sub-directory of your git repository
                        $smarty->template_dir = "$rootPath/templates/";
                        $smarty->fetch("$rootPath/$file");
                } catch (\Exception $e) {
                        $errors['tpl'][] = ">> '$rootPath/$file' ($file)";
                        $errors['tpl'][] = $e->getMessage();
                }
        } else {
                // check inside the file
                $fp = fopen("$rootPath/$file", 'r');
                $shebang = trim(fgets($fp));
                fclose($fp);
                if ($shebang != '#!/bin/bash' && $shebang != '#!/bin/sh') {
                        continue;
                }
                // check shell file syntax
                if (!file_exists('/usr/bin/shellcheck')) {
                        print(Ansi::color('yellow', "⚠ Can't check shell script. You should install 'shellcheck'."));
                        continue;
                }
                exec("/usr/bin/shellcheck -s bash -f gcc $rootPath/$file", $checklines, $ret);
                if (!$ret) {
                        continue;
                }
                foreach ($checklines as $checkline) {
                        $check = explode(':', $checkline);
                        if (trim($check[4]) == 'error') {
                                $errors['sh'][] = $checkline;
                        }
                }
        }
}
// remove temporary files
if ($compileDir) {
        shell_exec("rm -rf $compileDir $cacheDir");
}
// display errors
$return = 0;
if (!empty($errors['php'])) {
        print(Ansi::color('red', "⛔ ERRORS IN PHP FILE(S)\n"));
        foreach ($errors['php'] as $err) {
                print(" $err\n");
        }
        $return = 1;
}
if (!empty($errors['sh'])) {
        print(Ansi::color('red', "⛔ ERRORS IN SHELL FILE(S)\n"));
        foreach ($errors['sh'] as $err) {
                print(" $err\n");
        }
        $return = 2;
}
if (!empty($errors['tpl'])) {
        print(Ansi::color('red', "⛔ ERRORS IN SMARTY FILE(S)\n"));
        foreach ($errors['tpl'] as $err) {
                print(" $err\n");
        }
        $return = 3;
}
exit($return);

 

Pensez à adapter la variable $pluginPathList en y mettant la liste des répertoires contenant vos plugins Smarty. Adaptez aussi $smarty->template_dir pour y indiquer le chemin vers le répertoire racine de vos templates Smarty (c’est utile lorsque vous faite des inclusions de fichiers en mettant des chemins relatifs à cette racine).

J’utilise ce hook depuis un certain temps maintenant. J’espère qu’il pourra aussi être utile à d’autres personnes.
En cherchant un peu sur le web, vous pourrez trouver plein de contributions du même type, qui pourront remplir vos besoins. Personnellement, je n’ai rien trouvé qui fasse les vérifications exactes dont j’avais besoin (PHP, Smarty et Shell). Donc voilà 😉

Dernière précision : Dans la mesure où ce script de pre-commit s’exécute en local sur le poste de développement, il est toujours possible de demander git à ne pas l’utiliser et donc forcer le commit des fichiers. Seuls des hook côté serveur peuvent éviter cela. Mais franchement, il n’y a strictement aucun intérêt à vouloir contourner ce type de sécurité.

L’innovation que j’attends concernant les ordinateurs portables

Il y a presque 20 ans, j’étais tombé sur un site créé par un collège américain, et dont le sujet était l’ordinateur portable idéal pour les étudiants. La définition était : une puissance infinie, une mémoire (de stockage) infinie et une autonomie infinie.

Derrière ces définitions utopistes se cachait une réflexion sur les besoins réels des étudiants. Par exemple, l’autonomie infinie se traduisait par une journée entière de travail bureautique. La mémoire infinie était vue par rapport à l’espace nécessaire pour stocker tous les documents de travail (devoirs, supports de cours, etc.) dont un étudiant aura besoin durant une année scolaire. Et ainsi de suite.

Il est intéressant de se pencher de nouveau aujourd’hui sur ces notions.

Stockage infini : Grâce au cloud, c’est quelque chose qui fait maintenant partie de notre quotidien. Suivant les solutions (Google Drive, Dropbox…) il est possible d’avoir des téra-octets à portée de clic pour un tarif raisonnable, et avec une fiabilité supérieure à n’importe quel stockage local.

Puissance infinie : Là c’est un peu différent. La logique du client-serveur a longtemps été de déporter la puissance sur les serveurs ; mais avec d’un côté des clients (ordinateurs, puis tablettes et même maintenant des téléphones) de plus en plus puissants, et de l’autre côté des interfaces de plus en plus demandeuses, nous avons pris l’habitude d’avoir des applications réparties de manière plus équilibrée entre les deux composants. Néanmoins, on voit apparaître des solutions d’informatique dans le cloud offrant une puissance délocalisée (Shadow, Amazon Workspaces), ce qui laisse augurer d’un avenir où la puissance de calcul sera effectivement infinie − avec la possibilité de la moduler en fonction des besoins.

Autonomie infinie : La technologie des batteries s’est grandement améliorée. Il y a 20 ans, les PC portables tenaient 2 à 3 heures maximum loin d’une prise de courant. Vous me direz que c’est encore l’autonomie moyenne de la plupart des portables modernes, mais on peut aussi trouver des machines qui tiennent 8 à 12 heures. Pourtant, est-ce que cela suffit pour considérer cela comme une autonomie infinie ? Oh que non ; parce que l’autonomie chute rapidement en cas d’utilisation intensive, et qu’on reste tributaire d’une prise électrique au bout d’une petite (demi-)journée de travail.

Mais alors, comment faire pour avoir un ordinateur portable qui soit toujours utilisable, même sans être branché sur le secteur ?

On pourrait imaginer des panneaux solaires au dos de l’écran. Mais cela manquerait d’efficacité ; non seulement un panneau solaire de cette taille produit peu d’électricité en l’état actuel de la technologie, mais en plus il serait quasi inutile une fois l’écran ouvert. On peut remarquer que l’entreprise canadienne WeWi avait proposé en 2013 un ordinateur portable alimenté par des panneaux solaires. Les panneaux se déployaient sur une surface incompatible avec ce qui est envisageable au quotidien.

© ZDNet / WeWi

Malgré la taille imposante des panneaux, l’autonomie annoncée atteignait péniblement les 10 heures. Je ne sais pas si cet ordinateur a vraiment été proposé à la vente, mais l’entreprise en question semble avoir mis la clé sous la porte.

Cette solution n’est donc pas envisageable.

Non, je pense qu’il faut regarder du côté des technologies de recharge sans fil utilisées par certains téléphones portables.

Google Nexus 5

J’avais acheté en 2013 un téléphone Nexus 5 de Google, qui embarquait la technologie Qi. Au travail, j’avais sur mon bureau une plaque sur laquelle je n’avais qu’à poser le téléphone pour qu’il se recharge. Quelque part, on se dit que le temps de brancher un câble est assez court pour que ça ne fasse pas de réelle différence, mais en pratique c’est le jour et la nuit. Il me suffisait de poser le téléphone sur la table pour qu’il se recharge, sans avoir à réfléchir plus que ça ; du coup, mon téléphone était toujours rechargé, je n’avais plus de mauvaise surprise en fin de journée.

Dans l’année qui avait suivi, Ikea avait sorti une gamme de meubles intégrant un dispositif de recharge sans fil (compatible avec la technologie Qi, devenu le standard de fait), identifiable au signe « + » gravé dans le bois pour indiquer où placer l’appareil à recharger. Ils proposaient même un kit pour ajouter ce dispositif sur la tablette ou le plateau d’un meuble existant.

© Ikea

J’étais séduit par l’idée, et imaginais un avenir où il deviendrait habituel de voir des signes « + » sur les bureaux, les étagères et les tables de chevet. Un avenir où nous n’aurions plus à nous soucier du taux de charge de nos téléphones, à moins de passer la journée entière en pleine nature…

Si on se projette un tout petit peu plus loin, on peut imaginer l’ajout de récepteurs Qi dans les ordinateurs portables. J’imagine bien que la puissance transmise ne serait pas suffisante pour recharger un ordinateur avec autant d’efficacité qu’un téléphone ; mais cela suffirait pour ralentir la décharge. Ce serait parfait pour travailler deux fois plus longtemps avec un ordinateur sans l’alourdir avec une batterie plus grosse.

Je pousse le rêve encore plus loin : J’imagine qu’on prenne l’habitude d’avoir des chargeurs intégrés dans tous les mobiliers de bureau ; dans les tables de restaurants et de cafés ; dans les accoudoirs des fauteuils des salles d’attente dans les gares et dans les salles d’embarquement des aéroports. On tiendra pour acquis le fait de pouvoir charger facilement et gratuitement nos téléphones, tablettes et ordinateurs portables, de la même manière qu’on s’est habitué à avoir du wifi à peu près partout (enfin, c’est vrai en Amérique du Nord plus qu’en Europe, mais on s’y dirige).

Le jour où ce sera une réalité, on pourra réellement imaginer des machines offrant une puissance, une mémoire et une autonomie quasi infinies.

Ajout de dernière minute : Alors que je terminais tranquillement cet article, je suis tombé sur une info intéressante. Apple a déposé un brevet pour intégrer la recharge sans fil dans les MacBook… mais on dirait que c’est juste pour que l’ordinateur puisse être utilisé comme une batterie externe pour recharger les iPad et iPhone ; pas pour que l’ordinateur puisse être rechargé sans fil. Dommage !
Par contre, il n’existe pas de tablette rechargeable sans fil à ma connaissance. Apple innoverait en ajoutant cette fonctionnalité à l’iPad ; j’espère que ça fera des émules chez les autres constructeurs !

L’innovation que j’attends concernant les téléphones portables

Au fil des ans, les smartphones ont vu leurs écrans grandir de plus en plus. Et incidemment, ils sont devenus de plus en plus encombrants.
Je suis le premier à reconnaître qu’un écran plus grand est plus confortable à tous points de vue : on affiche plus de choses à la fois, les textes sont plus lisibles, le clavier virtuel est plus facile d’utilisation…

Je n’ai pas succombé à la tentation des phablettes (je veux pouvoir tenir et manipuler mon téléphone d’une seule main, et il doit tenir dans la poche de mon pantalon), et j’en suis arrivé actuellement à utiliser un OnePlus 5 dont l’écran offre une diagonale de 5,5 pouces.
C’est assez gigantesque si on compare avec mon premier smartphone Android, un HTC Hero dont l’écran faisait juste 3,2 pouces, ce qui semblait très grand à l’époque (en 2008).

HTC Hero

Si on regarde la progression des iPhone, on peut remarquer que le premier modèle avait un écran de 3,5 pouces, et que l’iPhone 8 existe aujourd’hui en modèles 4,7 et 5,5 pouces.

Sauf que je connais des gens qui trouvent que l’inflation galopante de la taille des smartphones n’est pas une chose positive, pour qui la qualité première d’un téléphone reste sa compacité (rappelez-vous, c’était un critère majeur au début des années 2000).

Pour l’anecdote, on peut se souvenir qu’en 2009, Palm avait sorti le Palm Pre, téléphone tournant sous le système maison webOS. Il s’agissait à l’époque d’un concurrent sérieux aux iPhone et aux téléphones Android. Deux ans plus tard, HP (qui avait racheté Palm) sorti le Veer en même temps que le Pre 3. Là où le Pre 3 avait un écran de 3,6 pouces, le Veer était beaucoup plus compact avec un écran de 2,6 pouces (il avait une taille de carte de crédit, et sa forme arrondie l’avait fait comparer à un petit galet lisse).

© tested.com

L’arrêt brutal des terminaux webOS par HP a empêché de savoir si le marché était prêt pour un terminal plus petit, mais il avait l’avantage de proposer une alternative qui ne soit pas un sous-produit.

Plus récemment, les fabricants de matériel électronique se sont engouffrés dans la voie des montres intelligentes (ou montres connectées, ou smartwatches, appelez-les comme vous voulez).

© boomspeaker.com

On comprend bien qu’ils cherchent à ouvrir de nouveaux marchés pour entretenir leur croissance, poussés par le ralentissement des courbes de ventes de leur catalogue (des ordinateurs, puis des ordinateurs portables, puis des tablettes, puis des téléphones). Résultat, on a pour le moment des appareils bancals dont le plus gros défaut est certainement l’autonomie.
(Sérieusement, une montre qu’il faut recharger tous les jours ? Quels que soient les services qu’elle propose, ce n’est pas viable. Par le passé, j’ai jeté une montre parce qu’elle bouffait sa pile en 3 mois, ça m’a gonflé)

Bref, vous devez sentir où je veux en venir. On a d’un côté des téléphones dont la technologie est très mature, mais qui deviennent de plus en plus imposants, au point de devenir inconfortables ; mais qui seraient quasiment inutilisables si on les ramenait à des dimensions plus compactes. De l’autre côté, on a des montres dont l’ergonomie fonctionne correctement sur des écrans minuscules (à peine 1,5 pouce), dont la petitesse est compensée à grand renfort de commandes vocales ; mais dont le confort est limité par ces petits écrans et surtout une autonomie ridicule.

Il semblerait juste logique de voir apparaître des appareils hybrides, sortes de téléphones tournant sous Wear OS (le système d’exploitation de Google pour les montres connectées, qui s’appelait initialement Android Wear). On pourrait imaginer qu’ils auraient un écran de petite taille − disons entre 2,5 et 3,2 pouces − et seraient donc très compacts et légers. Ils auraient une ergonomie générale similaire à celle des smartwatches, et seraient donc plus simples à utiliser que les smartphones récents qui peuvent parfois être déroutants pour les gens qui ne sont pas férus de high-tech. Et les interactions qui sont trop complexes pour fonctionner correctement sur un écran aussi petit (comme saisir du texte, par exemple) se feraient via une interface vocale.

On pourrait objecter qu’un tel appareil pourrait ressembler au Microsoft Kin One, grand échec commercial qui n’aura vécu que quelques mois en 2010.

© Windows Central

Mais Microsoft avait cumulé les bourdes : système d’exploitation basé sur un Windows CE déjà obsolète, impossibilité d’ajouter des applications, importation de liste de contacts uniquement faisable par un expert en boutique, fonctionnalités centrées sur les réseaux sociaux mais délai de mise-à-jour de 15 minutes non configurable, aucun jeu, pas de calendrier, pas de messagerie instantanée, pas de correcteur orthographique…

Toutefois, le form factor du Kin One était intéressant, au même titre que celui du Veer, et je pense que ça pourrait valoir la peine de proposer un appareil innovant qui se démarque des téléphones portables actuels, en s’inspirant des montres intelligentes tout en s’affranchissant de leurs défauts et de leurs limites.

Qu’en pensez-vous ?

Lancement de Skriv, le logiciel de gestion de projets orienté workflow

J’ai déjà parlé plusieurs fois sur ce blog de Skriv, la startup que j’ai créée pour éditer un logiciel de gestion de projets.

Pendant mes années en tant que directeur technique,  j’avais développé l’outil qui nous servait à gérer nos projets. Cet outil implémentait le workflow que nous utilisions pour gérer nos projets, ce qui avait permis d’automatiser des tâches qui sont normalement dévolues aux chefs de projets, augmentant de fait la productivité de toute l’équipe. Et comme tout le monde devait pouvoir utiliser l’outil − même les personnes qui n’étaient pas formées à la gestion de projet ou dont le travail n’avait rien à voir avec l’informatique − j’ai dû réinventer les recettes que suivent tous les outils du marché.

Fort de cette expérience, j’ai voulu créer un logiciel que tout le monde pourrait utiliser :

  • À qui on peut enseigner la manière dont on gère nos projets, pour qu’il nous décharge des tâches répétitives.
  • Qui soit vraiment simple à prendre en main, non seulement dans son ergonomie, mais aussi par sa capacité à s’adapter à notre terminologie plutôt que d’imposer la sienne.
  • Qu’on puisse utiliser sur toutes les étapes d’un projet, depuis la première ébauche jusqu’à son déploiement (au contraire des outils qui se focalisent sur le delivery, sans gérer correctement les phases de conception).

Mieux que des mots, voici une petite vidéo de présentation :

Bref, un outil fait pour devenir indispensable pour ses utilisateurs, tout en étant le plus transparent possible : le but est d’aider les gens à travailler efficacement.

Après plusieurs mois de développement et de bêta-test, Skriv est maintenant prêt à être utilisé par tous. N’hésitez pas à vous inscrire à la période d’essai gratuit pour le tester.

L’offre tarifaire se veut la plus claire possible : le prix de lancement est de 4 € HT par utilisateur et par mois en paiement annuel, 6 € HT par utilisateur et par mois en paiement mensuel. C’est un tarif très compétitif par rapport aux concurrents.
Pour ce prix, tout est inclus : Vous pouvez créer autant de projets et stocker autant de pièces-jointes que nécessaire. Vous avez des notifications envoyées par email ou sur Slack. Vous bénéficiez d’un support par email et d’un niveau de service professionnel.

Plus d’informations sur www.skriv.com

Architectures distribuées et traitements asynchrones

Cela fait quelque temps que je réfléchis à l’idée d’écrire un article sur les architectures distribuées, et plus particulièrement sur les traitements asynchrones. J’en parlais déjà au Forum PHP en 2013, dans de ma conférence intitulée «De 0 à 10 millions de visiteurs uniques avec les moyens d’une startup» mais je vais entrer plus en profondeur dans le sujet.

Pour quoi faire ?

On peut vouloir faire des traitements asynchrones pour différentes raisons. Si on s’en tient au développement web, la principale raison est de répondre plus vite aux requêtes des visiteurs, en exécutant certaines actions de manière différée. L’exemple classique est lorsqu’une action sur votre site doit déclencher un appel sur l’API d’un service tiers : Cet appel d’API peut prendre plusieurs secondes, et il peut même échouer en cas de problème momentané du service en question ; dans ce cas, plutôt que de faire attendre notre internaute, il vaut mieux lui répondre immédiatement et traiter cet appel d’API de manière asynchrone. Pareil pour des envois d’emails (même si les serveurs SMTP opèrent déjà de cette manière), des traitements sur des fichiers audio/vidéo, des calculs lourds, etc.

Si on élargit le débat au-delà du web, c’est un bon moyen pour découpler les différentes briques qui composent un logiciel afin de mettre en place une architecture distribuée. C’est souvent un élément essentiel lorsqu’on a besoin de scalabilité et même de rapidité. Un système monolithique atteindra tôt ou tard ses limites, là où un système composé de plusieurs entités qui communiquent ensemble sera plus facile à faire évoluer − au prix d’une complexité initiale plus grande.
En éclatant le code applicatif en plusieurs morceaux, on peut distribuer son exécution sur plusieurs machines assez facilement, facilitant ainsi l’évolutivité de la plate-forme.

Concrètement, l’idée est d’avoir des entités qui s’envoient des messages au lieu de discuter entre elles directement. Quand un message est envoyé, on n’attend pas une réponse immédiate ; une fois que le message aura été traité, un autre message sera éventuellement envoyé en retour pour le notifier, à moins que le résultat ne soit par exemple stocké dans une base de données où il sera disponible pour de futurs besoins.

Le sujet des architectures distribuées n’est pas nouveau. L’idée de RPC (appel à procédure distante) a été décrite dès 1976. Dans les années 90, quand les langages orientés objet étaient à la mode, beaucoup d’énergie a été déployée dans les systèmes servant à exécuter des objets à distance. C’est dans ce contexte que sont apparus des ORB (object request brokers) comme CORBA dès 1991 et RMI (Remote Method Invocation) intégré à Java dès la version 1.1 en 1997.
D’ailleurs, la complexité de CORBA a facilité l’émergence de normes plus simples et basées sur des technos web, comme XML-RPC et SOAP (Simple Object Access Protocol) en 1998, elles-mêmes simplifiées avec l’apparition du REST en 2000 (qui s’est développé d’autant plus avec l’usage du JSON, sérialisation plus simple à manipuler que le XML).

Mais comme on va le voir, il ne suffit pas de considérer qu’il y a des procédures/méthodes/objets à appeler pour que le système soit robuste en toutes circonstances. On peut d’ailleurs remarquer que les illusions de l’informatique distribuée sont bien connues et listées depuis les années 90 :

  1. Le réseau est fiable.
  2. Le temps de latence est nul.
  3. La bande passante est infinie.
  4. Le réseau est sûr.
  5. La topologie du réseau ne change pas.
  6. Il y a un et un seul administrateur réseau.
  7. Le coût de transport est nul.
  8. Le réseau est homogène.

Effectivement, rien de tout cela n’est vrai. Découpler une application apporte beaucoup d’avantages, mais comporte aussi des contraintes et des risques qu’il faut connaître et évaluer.

Comment faire ?

Pour mettre en place ce type d’architecture, il existe un certain nombre de moyens techniques, depuis les plus simples jusqu’aux plus complexes. Je vais passer en revue quelques notions et solutions.

Quand on parle de traitements asynchrones, on a habituellement trois composants à mettre en place :

  • Une partie qui permet de donner des ordres de traitements, avec éventuellement des informations complémentaires (de quel type d’ordre il s’agit, avec parfois des données additionnelles, etc.). Cela prend habituellement la forme d’une simple bibliothèque logicielle, mais certaines technos imposent plus de contraintes − comment les ORB qui obligeaient à créer des stubs.
  • La pièce centrale du système, qui gère les messages qui sont envoyés, en les classant éventuellement par priorité ou en les rangeant dans différentes files. Cette partie peut être basée sur des technologies variées (bases de données, files de messages, tables de hachage, ou autre).
    Les technos utilisées, que ce soit pour gérer les messages ou pour communiquer entre les différentes briques de l’architecture, ont une influence directe sur les performances du système.
  • La dernière partie est constituée par des «workers», c’est-à-dire du code qui traite les messages et effectue le travail demandé. Là encore, il existe plusieurs manières de faire : soit les workers sont des programmes indépendants (qu’il faut alors gérer correctement), soit ils sont lancés par la brique centrale (au prix d’un coût d’instanciation qui ajoute de la latence dans les traitements).

Dans les notions qui me semblent importantes à avoir en tête, il y en a principalement deux :

  • La scalabilité : Est-ce que la solution retenue peut soutenir un très grand nombre de messages échangés, et est-il possible de répartir leur traitement sur plusieurs ordinateurs ?
  • La persistance : Si la partie centrale de l’architecture venait à tomber en panne, est-ce que les messages qui étaient en attente de traitement sont perdus ou bien sont-ils conservés pour être traités au redémarrage du système ?

Pour la mise en œuvre, je vais explorer 2 manières de faire, chacune avec 2 technos différentes :

  • L’utilisation d’une base de données dans laquelle on écrit les messages, avec un système de polling (“attente active” ou “scrutation” en français) pour instancier leurs traitements.
    1. De manière artisanale, avec l’utilisation de la crontab.
    2. Avec l’outil Resque.
  • L’utilisation d’un système intégrant une file de messages.
    1. Avec l’outil Gearman.
    2. Avec l’outil Beanstalkd.

Base de données ou file de messages ?

Parmi les quatre méthodes que je vais détailler, trois d’entre elles reposent d’une manière ou d’une autre sur l’utilisation d’une base de données. Continuer la lecture de « Architectures distribuées et traitements asynchrones »

OVH, je t’aime moi non plus

Je m’apprêtais à écrire un article sur l’utilisation que je fais de l’offre Public Cloud d’OVH. Mais ce matin (nous sommes le 29 janvier 2018 au moment où je commence à écrire ces lignes), l’hébergeur rencontre de gros soucis qui empêchent de se connecter à son interface utilisateur, et donc de gérer les machines. Je me suis dit que ça pourrait être une bonne occasion de revenir sur les récents problèmes techniques qui ont entaché la réputation de la licorne française de l’hébergement (la dernière fois que j’en avais parlé, c’était il y a presque 7 ans maintenant).

Pour faire un tour d’horizon un peu complet, je vais remonter au 29 juin 2017, il y a 7 mois exactement. Ce jour-là, OVH subissait une très grosse panne, qualifiée par son président comme étant le «pire incident depuis 2006».

29 juin 2017

Je vous invite à lire le ticket de travaux qui a été écrit par Octave Klaba, ainsi que le post-mortem publié sur le blog d’OVH, qui récapitule ce qu’il s’est passé à ce moment. En résumé, il y a eu une fuite de liquide dans le refroidissement liquide d’un serveur, qui a coulé sur une baie de disque qui s’est éteinte après avoir détecté un problème électrique. Cette baie n’aurait pas dû se trouver à côté d’équipements refroidis par eau. De plus, le système de détection de fuites d’eau n’a pas pu alerter les techniciens, car il avait été mis à jour le même jour, et cette mise-à-jour était boguée ; du coup, les techniciens sont intervenus tardivement.

Ce qui n’est pas dit clairement dans le post-mortem, mais qui était dit dans les premières communications effectuées par OVH ce jour-là (et depuis modifiées), c’est que les techniciens semblaient ne pas avoir conscience du problème hydraulique. Ils ont essayé de redémarrer la baie de disque, et ont incriminé le matériel.

L’impact de ce problème technique est la mise hors ligne d’un très grand nombre de sites web. La baie de disques était utilisée pour le stockage des bases de données de l’offre d’hébergement mutualisé ; sans base de données, la plupart des sites ne sont plus fonctionnels. On parle de cinquante mille sites impactés (cf. cet article sur ZDNet), qui plus est en période de soldes.

En urgence, une baie de secours a été acheminée de Roubaix à Paris pour tenter de réinstaller les disques durs, et en parallèle les sauvegardes quotidiennes ont été restaurées sur un autre système. La deuxième baie n’a semble-t-il pas fonctionné, et la restauration des données a duré jusqu’à la fin du jour suivant.

Au passage, la manière dont OVH a communiqué a été largement critiquée (le post-mortem tente d’expliquer tout ça).

Mon analyse tient en 4 points :
1) Le geste commercial est plutôt symbolique (2 mois d’hébergement offerts aux clients impactés), mais c’est un symbole fort. À 4 euros par mois d’hébergement mutualisé en moyenne, cela fait un réel manque à gagner pour OVH, mais qui reste une goutte d’eau pour une entreprise de cette taille.

2) Les clients qui font tourner leurs sites de e-commerce sur de l’hébergement mutualisé devraient avoir honte et ne pas trop s’étonner de rencontrer des problèmes. Faire tourner leur business sur une offre à 4€/mois sans garantie de service, c’est comme construire une boutique physique avec des murs en carton : on n’est pas stupéfait lorsque ça s’écroule sous la pluie.

3) Un système de monitoring et d’alerte en datacenter qui est mis à jour mais qui n’est pas testé, vérifié, validé ? Vraiment ?

4) Passons sur le fait que la baie n’aurait pas dû rester à côté du refroidissement liquide, ça a été bien expliqué par OVH. Mais les données ont été restaurées sur un système qui a été mis en place en une nuit ? Soit ça veut dire qu’ils auraient pu le faire bien plus tôt, soit ça implique qu’ils ont reconstruit un truc à la va-vite, qui ne respecte pas leur niveau de qualité habituel ; sauf que je crains que les sites mutualisés tournent encore sur ce système « temporaire »… Est-ce que ça pétera encore un de ces jours ?

État des lieux avant l’incident : Une installation temporaire (baie posée à côté de serveurs refroidis par eau) qui a été oubliée en l’état, même si elle n’était pas « au standard ».
État des lieux après l’incident : Une installation réalisée en quatrième vitesse, sans qu’on ait plus d’information sur le fait qu’elle soit « au standard ».

9 novembre 2017

Donc, l’incident de juin était censé être le pire vécu par OVH depuis plus de 10 ans. Manque de chance, 4 mois plus tard a lieu un incident dont l’ampleur est bien plus importante. En fait il s’agissait de deux incidents arrivés en même temps, dans deux datacenters différents. Résultat, il y a pas mal de littérature officielle sur le sujet :

À Strasbourg, le câble d’alimentation électrique a été endommagé, et les groupes électrogènes n’ont pas démarré, et donc tous les serveurs se sont éteints. Voilà, c’est aussi simple que ça. Ah oui, il faut savoir que la dernière fois que les groupes électrogènes avaient été testés, c’était au mois de mai. Soit 6 mois auparavant ! Enfin, pour être plus précis, les groupes électrogènes sont (censés être) testés « à vide » tous les mois ; ce qui datait du mois de mai, c’est le test d’alimentation des datacenters par l’alimentation de secours en conditions réelles. Après investigations, il s’avère que l’automate de démarrage des groupes électrogènes était bloqué en position verrouillée ; pas plus d’explication, mais on peut imaginer que cela datait du test du mois de mai (comme quoi il faut tester plus souvent en conditions réelles).

Il faut aussi savoir que la manière dont les datacenters de Strasbourg ont été construits n’est pas « au standard » d’un point de vue électrique. Certains datacenters ont une arrivée électrique simple (non redondée), d’autres encore ont été chaînés (entraînant un effet domino si le premier datacenter de la chaîne rencontre un souci).

À Roubaix, siège historique de l’entreprise qui représente un nœud d’interconnexion majeur, les 6 fibres optiques sont tombées d’un coup. La raison tient du fait que ces fibres sont gérées par deux équipements réseau identiques, qui ont perdu simultanément leurs configurations. Même en expliquant qu’il y a eu une cascade de bugs, démarrée par une surcharge CPU, je pense qu’on ne saura jamais le fin mot réel de l’histoire.

On peut toutefois remarquer qu’OVH avait initié deux semaines auparavant le remplacement des cartes contrôleurs, les nouvelles ayant deux fois plus de puissance CPU et deux fois plus de RAM que celles en place. Cela laisse penser que la surcharge CPU de ces cartes n’était pas un phénomène nouveau. Dans le ticket d’incident en date du 10 novembre, il est écrit «Nous avons reçu les 2 premières hier pour Roubaix»… Donc ils les ont reçues le jour de l’incident ; c’est dommage que ce remplacement n’ait pas eu lieu juste quelques jours plus tôt.

Le souci avec ces deux incidents est qu’en arrivant en même temps, ils ont créé le pire des scénarii. Si vous avez des serveurs dédiés et que vous redoutez qu’une panne survienne dans le datacenter où ils sont hébergés, vous pouvez louer des serveurs dans plusieurs datacenters différents − éventuellement chez plusieurs hébergeurs différents. Mais pour rediriger le trafic, vous allez avoir besoin de pouvoir configurer certaines choses : soit modifier les IP fail-over/load-balancing (dans le cas où vous avez des serveurs dans des datacenters OVH), soit modifier les DNS pour faire pointer sur des serveurs différents (dans le cas où vous passez par des hébergeurs différents).
Le bug ayant affecté Strasbourg a fait tomber des serveurs. Mais celui de Roubaix a rendu indisponible l’interface client d’OVH. Il était alors impossible de modifier la moindre configuration. C’est la double peine : vos serveurs sont HS, mais vous ne pouvez même pas rediriger les requêtes vers d’autres serveurs.

La communication d’OVH est aussi à prendre avec du recul. On nous dit que l’incident de Strasbourg a duré 4 heures, et que celui de Roubaix a duré 2 heures 20 minutes.

Pourtant, si on regarde dans le détail, 9 heures après le début de l’incident de Strasbourg, seuls 71% des serveurs avaient été redémarrés ; au bout de 30 heures, 99% des serveurs étaient redémarrés ; les derniers serveurs ont été redémarrés après 4 jours d’interruption. En effet, ce genre de problème électrique peut faire griller des serveurs, dont certaines parties physiques doivent alors être remplacées.
Et concernant Roubaix, il faut plutôt attendre 6h30 avant que la plate-forme soit complètement stable.

Dans tous les cas, il se pose la même question que pour l’incident du 29 juin : les solutions mises en place sont-elles pérennes ou bien sont-elles juste des bricolages effectués rapidement pour que les services soient en ligne ? Dans le deuxième cas, est-ce que le temps a été pris ensuite pour revenir dessus et tout remettre d’équerre ?

Mon analyse :
Là encore, on voit que la situation résulte de choses connues et anticipables par OVH. Que ce soit l’installation électrique pas « au standard » à Strasbourg, ou les cartes CPU qui devaient être changées à Roubaix. L’explication tient évidemment au fait qu’il s’agit d’investissements coûteux dans un cas (pour Strasbourg, Octave parle de 4-5 millions d’euros) et délicat dans l’autre cas (on ne touche pas l’équipement réseau d’un nœud aussi important que Roubaix sans quelques précautions).
Mais dans les deux cas, c’était identifié et important. Ils ne l’ont pas fait avant que ça leur pète à la gueule, c’est tout.

6 décembre 2017

Là ce n’est vraiment pas de chance. Suite à l’incident du 9 novembre, ils ont prévu une intervention pour corriger les failles (isolation des équipements réseau en trois groupes séparés, pour qu’un souci ne puisse plus impacter qu’un tiers du trafic dans le pire des cas). Sauf qu’en préparant cette opération de maintenance, tout est retombé de nouveau − de manière identique au 9 novembre.

Les liens d’info :

Le résultat, c’est 4 heures d’interruption de service de nouveau.

On peut se dire que c’est quelque chose qui peut arriver. Rien n’est parfait, on est d’accord. Mais là, ça reste étrange : soit la plate-forme était tellement instable qu’elle menaçait de s’écrouler à tout moment, soit cette intervention aurait dû être menée avec beaucoup plus de précautions. Peut-être qu’il aurait fallu être plus précautionneux, justement parce que la plate-forme était instable.

Est-ce que des équipements réseau identiques avaient été montés en labo, pour répéter l’opération avant de la tenter « pour de vrai » ? On ne le saura jamais. De la même manière qu’on ne sait pas si l’opération a été refaite avec succès depuis…

24 janvier 2018

Dans le datacenter de Gravelines, un onduleur est tombé en panne. L’onduleur se rendant compte de son propre défaut, il laisse passer le courant en se by-passant lui-même. Malheureusement, le souci électrique de cet onduleur était « trop important », ce qui fait que le tableau électrique a arrêté de l’alimenter ; et donc les serveurs qui étaient derrière l’onduleur n’étaient plus alimentés à leur tour.

À lire :

C’est quelque chose qui peut arriver. Sauf que justement, ce type d’incident devrait être bien géré. Là, 1150 serveurs sont tombés. Le problème s’est déclaré à 23h02 ; plus d’un millier de serveurs avaient été redémarrés à 5h00 du matin (soit une interruption de 6 heures), mais ils ont fini de redémarrer tous les serveurs impactés le lendemain à 19h37 (plus de 20 heures d’interruption). Mais il faut savoir que ces serveurs étaient sans protection électrique par l’onduleur, puisqu’à 21h45 le support indiquait «Nous avons sorti l’UPS7 de l’installation. Nous avons procédé à son remplacement par un modèle neuf. Le nouvel UPS7 va être mis en fonctionnement.»

Là encore, on ne sait pas quand il a été mis en fonctionnement. Mais surtout, on ne sait pas si ce genre d’incident peut se renouveler. Un onduleur qui déconne, encore une fois, ça peut arriver. Mais ça ne devrait pas avoir ce genre d’impact et prendre autant de temps à être corrigé.
Enfin, peut-être que je me trompe.

29 janvier 2018

Et donc, dernier gros incident en date, durant lequel il semblerait qu’un équipement réseau soit tombé en panne à 7h33. Malheureusement, le ticket d’incident est assez cryptique. J’en comprends que c’est un équipement qui travaillait en binôme («L’autre membre du couple p19-94-n6 est toujours fonctionnel») ; mais dans ce cas, pourquoi celui qui n’est pas tombé en panne n’a pas pris correctement la relève ? Est-ce que ces équipements sont sous-dimensionnés au point que même en étant redondés, un élément d’une paire ne peut pas faire le travail de la paire entière ?

Le résultat est que tous les hébergements mutualisés sur Paris sont devenus indisponibles. Mais aussi, l’interface de gestion est devenue indisponible (ainsi que l’API OVH qui permet de gérer les services sans l’interface web), exactement comme lors de l’incident de novembre à Roubaix. Ça devient un peu lourd, d’ailleurs ; que le souci soit à Paris ou à Roubaix, on subit les mêmes effets…

Toujours d’après le ticket, les services étaient de nouveau fonctionnels à 15h45, soit 8 heures d’interruption de service.

Sur cet incident, la communication a été particulièrement mauvaise (en tout cas pour le moment). Le ticket ne dit pas grand-chose, et les échanges sur Twitter se sont révélés très succincts.

D’ailleurs, lorsque des gens ont demandé sur Twitter s’il y aurait des indemnisations, la réponse était «c’est du mutualisé, donc pas de SLA, donc pas d’indemnisation». Je peux comprendre que ça commence à faire beaucoup d’indemnisation pour l’entreprise, mais si l’interruption du mois de juin avait duré 30 heures et entraîné 2 mois d’hébergement gratuit, c’est un peu dur de ne rien donner du tout cette fois-ci en échange d’une interruption de 8 heures.

Le manque de communication sur cet incident (pas de post-mortem notamment, mais on peut croiser les doigts qu’il arrive dans les jours ou semaines à venir) est étonnant et un peu problématique. On ne peut pas banaliser cette perturbation : si les hébergements mutualisés étaient importants en juin, ils le sont toujours aujourd’hui ; et le fait de ne pas pouvoir gérer ses serveurs et ses DNS est assez inadmissible.

Conclusion

C’est bien de soutenir l’innovation et de lever des millions (250 en 2016 et 400 en 2017), mais il faut que la base soit solide sinon tout s’écroule.

Le service DownDetector permet de faire quelques statistiques rapides et perfectibles, mais quand même intéressantes. Si on s’intéresse toujours à cette période de 7 mois comprise entre le 29 juin 2017 et le 29 janvier 2018 (soit 214 jours), on obtient :

  • OVH : 34 jours avec des incidents, soit 16%
  • AWS : 16 jours avec des incidents, soit 8%
  • Salesforce : 6 jours avec des incidents, soit 2,8%
  • Microsoft Azure : 3 jours avec des incidents, soit 1,4%
  • Rackspace : 3 jours avec des incidents, soit 1,4%

Ça laisse quand même à réfléchir.

On peut remarquer que plusieurs incidents sont le résultat de choses qui auraient dû être anticipées. Et que l’argent économisé en ne lançant pas les chantiers à temps est perdu en devant payer des jets privés pour dépêcher des équipes techniques en urgence (sans parler des coûts humains).

Mais faut-il quitter OVH pour autant ? À chacun de se faire sa propre idée, mais la réponse ne peut évidemment pas être binaire. Pour ma part, j’utilisais déjà OVH et AWS en parallèle, en choisissant les services chez l’un ou chez l’autre en fonction de ce qui me semblait pertinent. Et, comme je l’ai écrit en préambule, je comptais écrire un article au sujet de l’offre Public Cloud que je trouve pas mal du tout.

Pour le moment, ces incidents ne me font pas quitter OVH. Bien sûr, ils me rendent plus attentif, mais les offres restent d’une compétitivité incroyable. On peut se dire qu’il vaut mieux payer plus cher ailleurs pour avoir un service qui ne tombe absolument jamais, mais je n’en suis pas encore là ; les économies restent largement supérieures aux inconvénients. D’un autre côté, si un jour tout tombe en rade pendant une longue durée, je ne tiendrai pas le même discours…

Il est assez amusant de voir que le bilan que je tirais en 2011 reste complètement d’actualité. Il faut de toute façon se préparer à ce que les choses se passent mal, quel que soit l’hébergeur.

Edit du 31 janvier 2018 : Sur Twitter, le support OVH vient de me répondre, me disant qu’aucun post-mortem n’est prévu pour l’incident de cette semaine. C’est assez honteux.

Pour la petite histoire, je vous copie-colle un extrait du post-mortem qui avait été écrit suite à l’incident de juin :
«Cet épisode a révélé la nécessité de mieux coordonner les informations durant un incident, afin de fournir aux utilisateurs une explication qui ne soit pas seulement transparente, c’est le minimum, mais aussi cohérente, compréhensible par tous et régulièrement actualisée.»

C’est amusant de voir comment les bonnes résolutions sont vite oubliées.

La suite de ce paragraphe était : «Au-delà de la refonte prévue du site travaux.ovh.net, au profit d’une interface plus évoluée, et de la possibilité prochaine d’être alerté de façon personnalisée en cas d’incident impactant l’un de ses services, une équipe spécialisée sera mise en place pour délivrer aux utilisateurs une information dont la qualité est adaptée à ce type de situation.»

Les trois choses évoquées ici (nouveau site de suivi des incidents, alertes personnalisées et équipe dédiée à la communication de crise) ne sont toujours pas en place, 7 mois après. Malheureusement, durant cette période, OVH a traversé sa pire suite de problèmes techniques. Le truc, c’est que les clients − à commencer par moi − sont passablement patients et sympas tant que la communication reste au top ; là j’ai l’impression que ça se dégrade, alors qu’il faudrait au contraire augmenter l’effort.

Edit du 02 février 2018 : Et on recommence. Aujourd’hui, nouvelle impossibilité de se connecter à l’interface client (cf. ici, et encore ). Pas de ticket d’incident qui semble en parler sur le site travaux.ovh.net. Pas d’infos sur Twitter, à part une réponse succincte à l’un des messages que j’ai mis en lien et qui dit en gros «on va regarder», puis plus rien. Bref, le grand néant…

Dispak : Gestion et déploiement de tags/branches Git + serveurs/services

Après Arkiv (dont je vous avais parlé dans un précédent article), voici un nouvel outil que j’ai développé pour mes besoins et que je publie sous licence libre : Dispak

Mon besoin était :

  • Créer facilement des tags sur un repository Git, en effectuant un certain nombre de vérifications et actions automatiques (état du repo, minification de fichiers JS/CSS, envoi de fichiers statiques sur Amazon S3, …).
  • Déployer les tags sur mes serveurs, là aussi en automatisant des choses (génération de fichiers de configuration, migration de schéma de base de données, installation de crontab, installation de fichiers de configuration Apache, …).

Et je voulais deux choses en plus :

  • Afficher la liste des tags de manière plus pratique que ce qu’offre Git.
  • Gérer les branches : les créer (en local et en distant), les effacer, les merger sur le master, et backporter les nouveautés du master vers les branches.

Je voulais aussi pouvoir ajouter facilement des fonctionnalités supplémentaires, pour éviter d’avoir plein de scripts qui se baladent dans tous les coins (qu’il s’agisse d’ajouter un utilisateur dans ma base de données, générer de la documentation à partir du code, effacer des fichiers temporaires, redémarrer des services sous certaines conditions, etc.).

N’hésitez pas à aller lire la documentation complète sur GitHub et à installer Dispak.

La genèse

J’avais commencé à gérer tout ça avec un fichier Makefile. J’utilise beaucoup les Makefiles, et pas seulement pour compiler du code source. C’est très pratique dès que vous voulez faire un script shell qui peut prendre des options sur la ligne de commandes. Et encore plus pratique pour centraliser plusieurs actions qui seraient habituellement séparées en plusieurs scripts.
Mais assez rapidement, je me suis retrouvé avec un très gros fichier, et même si j’avais trouvé un moyen pour mutualiser le code (des règles « privées » qui sont appelées par plusieurs règles « publiques »), ça devenait un peu acrobatique. C’est là que je me suis dit qu’un vrai outil serait préférable.

J’ai défini le périmètre :

  • Je voulais faire un outil vraiment portable, donc pas développé dans un langage de programmation de haut niveau dont l’interpréteur n’est pas forcément présent. Naturellement, j’en suis venu au shell. Par contre, je me suis quand même autorisé à utiliser le bash qui offre pas mal de facilitées bien utiles tout en étant très répandu.
  • Je voulais pouvoir facilement ajouter de nouvelles fonctionnalités à l’outil, que ce soit de manière globale ou individuellement par projet de développement. Cela a conduit à le rendre modulaire, avec une attention particulière sur la simplicité d’écriture des modules.
  • Je me suis autorisé certains choix quant à la manière de gérer les types de plates-formes, la normalisation des tags, la manière de gérer les migrations de bases de données, ou encore les logiciels utilisés. Je vais revenir sur ces différents points.

Concepts-clés

Dispak utilise la gestion sémantique de versions et la numérotation impaire pour les versions instables.
Les tags sont donc nommés sous la forme X.Y.Z :

  • X : Numéro de version majeure. Dois être incrémenté en cas d’évolution importante ou lorsque la compatibilité descendante n’est plus assurée.
  • Y : Numéro de version mineure. Dois être incrémenté pour chaque évolution de fonctionnalité.
    • Les numéros pairs (0, 2, 4, …) sont utilisés pour les versions stables.
    • Les numéros impairs (1, 3, 5, …) sont utilisés pour les versions instables.
  • Z : Numéro de révision. Dois être incrémenté lors de résolutions de bugs.

Dispak gère 3 types de plates-formes :

  • dev : Poste de développement
  • test : Serveur de test/staging/pré-production
  • prod : Serveur de production

La plate-forme est détectée automatiquement à partir du nom de la machine, ou peut être indiquée dans un fichier de configuration. Si la machine est nommée ‘test‘ suivi de chiffres, elle est considérée comme un serveur de test ; si son nom commence par ‘prod‘, ‘web‘, ‘db‘, ‘cron‘, ‘worker‘, ‘front‘ ou ‘back‘ (suivi de chiffres), c’est un serveur de production ; autrement on la considère comme un poste de développement.

Seules les versions stables peuvent être installées en production. Les versions instables ne peuvent être installées qu’en test/pré-production uniquement. C’est une sécurité qui peut être très utile.
De la même manière, la fonctionnalité de copie des fichiers statiques vers Amazon S3 n’est exécutée que pour les tags stables (mais peut être forcée via le fichier de configuration).

Fonctionnalités de base

Affichage de l’aide

Cliquez pour agrandir

Lister les tags d’un projet en version succincte

Cliquez pour agrandir

Liste des tags en version détaillée

Cliquez pour agrandir

Création de tags

La création de tags suit plusieurs étapes (certaines étant optionnelles) :

  • Suggestion du numéro de version (ou vérification si un numéro est fourni).
  • Vérification de la branche et des fichiers non commités ou non poussés.
  • Exécution de scripts de pré-packaging.
  • Commit du fichier de migration de base de données.
  • Minification JS/CSS.
  • Envoi des fichiers statiques sur Amazon S3.
  • Exécution de scripts de post-packaging.

Déploiement de tags

L’installation d’une nouvelle version automatise le process suivant :

  • Vérification qu’un tag instable n’est pas déployé en production.
  • Exécution de scripts pré-installation.
  • Installation de fichier crontab.
  • Migration de schéma de base de données.
  • Installation de fichiers de configuration Apache.
  • Gestion des droits d’accès aux fichiers.
  • Exécution de scripts post-installation.

Gestion des branches

Dispak offre en plus quelques raccourcis par-dessus Git :

  • Création de branches : Les branches sont toujours créées à partir de la branche master, soit depuis son état courant, soit depuis un tag donné.
  • Effacement de branches
  • Merge : Pour rapatrier sur le master les évolutions d’une branche.
  • Backport : Pour récupérer sur une branche les dernières nouveautés du master.

Ajout de fonctionnalités

Il est très facile d’ajouter des modules supplémentaires, qui peuvent être soit utilisables pour tous les projets (en plaçant le module dans le répertoire d’installation de Dispak), soit juste pour un projet particulier (en mettant le module dans l’arborescence du projet).

Il suffit de créer un petit fichier en shell Bash dont la version minimale ne contient qu’une variable et deux fonctions (l’une pour l’affichage de l’aide, l’autre pour l’exécution du module).

Voici un exemple très rapide (détaillé dans la documentation) :

#!/bin/bash

# Rule's name.
RULE_NAME="minimal"

# Show help for this rule.
rule_help_minimal() {
	echo "   dpk $(ansi bold)minimal$(ansi reset)"
	echo "       $(ansi dim)Minimal rule that displays the current user login.$(ansi reset)"
}

# Execution of the rule
rule_exec_minimal() {
	echo "Current user login: " $(id -un)
}

Pour un usage plus avancé, le module peut attendre des paramètres sur la ligne de commande, qui peuvent être obligatoires ou optionnels ; Dispak se charge alors de vérifier que tous les paramètres obligatoires sont bien fournis, et qu’il n’y a aucun paramètre non attendu.

Une vingtaine de fonctions shell sont utilisables. Il y a des fonctions servant à l’affichage des données, d’autres facilitant les vérifications (on est sur une branche/le master, tous les fichiers ont été commités/poussés, …), la récupération de données (branche courante, tag courant, prochain numéro de version, …) ou encore le traitement général (affichage de message d’alerte, arrêt des traitements, etc.).

La documentation est assez complète, vous verrez qu’il est vraiment facile de créer des modules supplémentaires. Si vous n’êtes pas fan des scripts shell, vous pouvez faire un code minimal qui se contentera d’appeler vos programmes externes.

Combien ça coûte de créer une entreprise ?

Cela fait maintenant un peu plus de 3 mois que j’ai créé Skriv, et on m’a demandé plusieurs fois combien cela m’a coûté. Il est difficile de donner directement un chiffre, donc je vais essayer de détailler un peu les choses ici, s’entendant que cela ne s’applique qu’à mon cas particulier.

Si l’exercice est un peu délicat, c’est parce qu’il faut séparer deux types de dépenses : celles qui sont absolument nécessaire à la création de l’entreprise d’un point de vue légal, et celles qui sont tout autant indispensables mais qui varient en fonction de votre contexte et de vos choix.

Le capital social

On parle beaucoup du capital social. En France, il doit même être annoncé dans tout un tas de documents légaux, ce qui est étrange parce que cela ne veut pas dire grand-chose. Le capital social représente l’argent qui a été investi dans l’entreprise à sa création ; ou en tout cas une partie de cet argent. Mais à un instant donné, cela ne reflète en rien la santé financière de l’entreprise − qui a très bien pu tout dépenser.

Il y a une petite astuce qui se fait de plus en plus, c’est de limiter le capital social à une valeur assez faible (par exemple 1000 €) ; le reste de l’argent investi dans l’entreprise par ses créateurs est déposé sur le compte courant d’associés. Ainsi, cet argent étant simplement mis à la disposition de l’entreprise, il sera possible de le récupérer par la suite, alors que le capital social appartient à l’entreprise et ne peut pas être repris.

Et le fait que le capital social soit de 1000 € n’est pas un problème lors d’une levée de fonds. Là encore, ce montant est décorrélé de la réalité. Par exemple, j’ai entendu parler d’une startup ayant fait une levée de fond de 2,4 millions d’euros (il me semble), et dont le capital social est alors passé de 1000 € à 1240 €, le restant passant en prime d’émission.

Frais « légaux »

Il y a trois frais inévitables lorsque l’on crée une entreprise.

  1. Pour commencer, il faut faire paraître une annonce légale dans un journal faisant partie d’une liste fournie par votre CCI (Chambre de Commerce et de l’Industrie).
    Personnellement, je suis passé par Le Parisien, qui offre une interface web pour le faire, assez facile et rapide à utiliser. Prix : 118,80 €
  2. Fort de cette parution légale, vous pouvez aller à la CCI pour faire enregistrer votre entreprise. Les droits de greffe sont à payer au Greffe du tribunal de commerce. Prix : 41,50 €
  3. Quelques jours ou semaines après la création de l’entreprise, on reçoit un courrier au sujet de la déclaration des bénéficiaires (actionnaires), avec un nouveau chèque à faire à l’ordre du Greffe du tribunal de commerce. Prix : 54,32 €

Il s’agit là du minimum sans lequel une entreprise ne peut pas exister. Sauf que pour éviter tout problème, il vaut mieux ajouter deux choses en amont :

  • Passer par un avocat pour faire rédiger les statuts de l’entreprise. Un bon avocat passera du temps avec vous pour comprendre votre situation et vos besoins, et adaptera les statuts en conséquence. Je suis très satisfait du travail réalisé par mon avocat, pour un prix plutôt inférieur à la moyenne du marché. Je ne conseille pas de faire rédiger les statuts gratuitement par un comptable ; un avocat saura mieux s’en occuper (du moins c’est mon avis, j’avoue avoir peu de recul sur la question). Prix : 300 €
  • Au moment de déposer le dossier à la CCI, le moindre petit grain de sable amène au refus pur et simple. Il vaut donc mieux faire appel à l’offre d’assistance à la création d’entreprise. Un employé de la CCI vous reçoit alors et passe en revue avec vous les différentes pièces que vous apportez, et répond à vos éventuelles questions. Prix : 60 €

Nous arrivons donc à un total de : 574,62 €

Avec ça, votre entreprise est créée. Maintenant il y a tout plein d’autres frais qui vont se rappeler à vous.

Autres frais

Dans les autres actions à mener, la première à prendre en considération (parce qu’il faut entamer les démarches avant de créer l’entreprise), c’est évidemment l’ouverture d’un compte bancaire professionnel. Et là, les choses sont très variées d’une banque à une autre et même d’une agence à une autre.
J’ai eu la chance d’avoir une offre assez intéressante : Je n’ai pas de frais mensuels pendant un an, seuls les mouvements (entrées et sorties d’argent) se voient « taxés » sur un petit pourcentage. Dans l’ensemble, pour une startup qui va faire peu de chiffre d’affaire au début de son activité, c’est extrêmement intéressant.

Autre chose à laquelle il est impossible de le dérober : il vous faut un comptable. Je suis passé par une offre en ligne. Prix : 82,80 € / mois

La plupart du temps, on a besoin de prendre une assurance responsabilité civile professionnelle. Il ne faut pas hésiter à comparer les tarifs des assurances. Prix : 30 € / mois

Quand on crée une startup, on a besoin d’une visibilité sur le web. Donc il faut acheter un nom de domaine, et payer un certificat SSL.
Pour le nom de domaine, les prix sont incroyablement variables, suivant le type d’extension que vous choisissez (je vous conseille quand même fortement le .com très standard), et si ce nom est disponible ou si vous devez le racheter à quelqu’un. Dans mon cas, j’ai acheté plusieurs noms de domaines (et le domaine skriv.com était mis en vente par une entreprise dont c’est le business, il m’a coûté cher).
Prix minimum : 12 € pour un .com et 36,90 € pour un certificat wildcard

Pour peu qu’une startup soit technologique, on a besoin d’au moins un serveur. On a de la chance, il y a maintenant des offres Cloud vraiment pas chères, c’est très pratique pour commencer. Prix : 3,58 € / mois

Il faudra que j’écrive un jour un article pour parler un peu de propriété intellectuelle. En attendant, si le nom de votre startup ou de votre service est original, il est important d’en déposer la marque à l’INPI. Prix : 210 €

En attendant de pouvoir louer des locaux, vous pouvez aller travailler dans un espace de coworking. J’en ai trouvé un très bien dont j’ai déjà parlé dans un article précédent. Prix : 80 € / mois

Vous pourrez vouloir créer un blog. Il existe un certain nombre d’offres gratuites et payantes, mais la plate-forme qui monte depuis quelques temps (et qui héberge aussi ceux de Bill Gates et de Barack Obama) a un modèle de frais fixe qui se paye une fois pour toute − ce n’est pas un abonnement. Prix : 65,90 €

On a habituellement besoin d’un minimum d’identité visuelle, via un logo par exemple. Là encore les prix sont très variables, depuis l’ami(e) qui vous dépanne gracieusement jusqu’au graphiste qui vous facturera 1500 € (voire beaucoup plus).

Dernier petit détail, loin d’être une obligation mais quand même utile, je me suis fait faire des cartes de visite. Prix : 13,98 €

Total sur un an

Si on additionne tout ça et que l’on multiplie les abonnements mensuels par 12, on atteint un total de 574,62 + 2695,34 = 3269,96 €

Voilà, créer une entreprise, dans le contexte qui est le mien, ça coûte au minimum 3500 euros (j’arrondis).
Sachant que j’ai eu des frais supplémentaires (noms de domaines, incubateur, …) mais que je n’ai pas eu besoin d’acheter de matériel particulier.

À chacun de voir si ce montant semble élevé ou non. Évidemment, ce n’est pas grand-chose comparé au moindre salaire. Même un stagiaire payé le minimum (soit 15% du plafond horaire de la sécurité sociale − au-dessus il faudra payer des charges sociales) vous coûtera entre 500 et 550 € par mois, soit plus de 6000 € par an…

N’hésitez pas à me contacter si vous souhaitez plus d’informations sur les prestataires par lesquels je suis passé (avocat, banque, comptable, registrar, fournisseur de certificat SSL, hébergeur, espace de coworking, plate-forme de blog, graphiste, imprimeur).

Configurer le nom d’un serveur

Un petit article technique sur quelque chose que j’ai longtemps considéré comme un point de détail, mais qui peut s’avérer important dans quelques rares cas.

Lorsqu’on configure un ordinateur, on lui donne un nom. Jusque-là, tout va bien.

Je pourrais disserter sur la manière de nommer les serveurs. Certaines personnes aiment donner des noms de planètes, des noms d’animaux, des noms de personnages issus de livres ou de films, ou simplement des prénoms ; personnellement, je préfère m’en tenir à des noms techniques qui retirent toute ambiguïté. (“db1”, “db2”… pour les bases de données ; “web1”, “web2”… pour les frontaux web ; et ainsi de suite). Mais ce n’est pas le but de cet article.

Pour l’exemple, on va dire que nous installons un serveur nommé “test1”, faisant partie du domaine “exemple.fr”. Lors de la configuration du serveur, il y a 2 fichiers à modifier (/etc/hostname et /etc/hosts). Leur contenu est moins évident qu’il n’y paraît, et non seulement on peut prendre en considération des documentations comme la RFC 1178, mais il semblerait que les choses soient différentes suivant le système Unix utilisé, voire même la distribution Linux… Je vais donner ici des infos pour les systèmes dérivés de Debian, comme Ubuntu par exemple.

Le fichier /etc/hostname doit contenir le nom de la machine, sans le nom de domaine. Dans notre exemple, ce sera simplement “test1”.
Pour s’assurer qu’il soit pris en compte sans attendre le redémarrage de la machine, il faut en plus exécuter la commande suivante (en tant que root) :

# hostname test1

On peut vérifier que le nom est bien pris en compte en lançant cette commande :

# hostname

Elle devrait afficher simplement :

test1

Le cas du fichier /etc/hosts est un peu plus délicat (enfin bon, n’exagérons rien). En fait, le système se base sur ce fichier pour connaître le nom complet (FQDN = Fully Qualified Domain Name) de la machine.
Donc, on début du fichier, on écrira les deux lignes suivantes :

127.0.0.1        test1.exemple.fr        test1
127.0.0.1        localhost.localdomain   localhost

On peut vérifier que tout est bon en exécutant :

# hostname --fqdn

On devrait alors obtenir :

test1.exemple.fr

Conclusion : Tout cela ne méritait peut-être pas un article. Mais dans les liens que j’ai fournis plus haut, on trouve des témoignages intéressants (un employé de Digg dit avoir rendu le site indisponible pendant 2 heures à cause d’une modification innocente du fichier /etc/hosts ; et il semblerait que certaines applications d’Oracle nécessitent une configuration différente), donc c’est mieux de savoir ce qu’on fait.

Skriv a 3 mois : la version bêta arrive

Skriv existe depuis maintenant 3 mois, et a rejoint un incubateur en septembre. C’est le moment de vous tenir un peu au courant.

Une copie d’écran pour attiser votre curiosité 😉

Le service est toujours en cours de développement. Beaucoup de travail a été réalisé ; les principaux concepts ont été implémentés et le but est de sortir une version bêta dans le mois à venir.

Maintenant je suis à la recherche de personnes et d’équipes qui souhaitent tester Skriv.
Je vous demande de l’utiliser réellement, sur les projets de votre équipe − pas juste faire un petit test de cinq minutes. Je sais que ça demande une implication forte, et cela doit être récompensé ; en échange de votre aide, vous aurez un accès gratuit et illimité jusqu’à fin 2018, pour vous et votre équipe.

Un rappel de l’intérêt de Skriv par rapport à la concurrence :

  • Skriv est orienté workflow
    La gestion de tâches, ça n’existe pas ; cela revient à jongler entre les tâches. La gestion de projets devrait être meilleure que ça.
  • Skriv rend votre équipe plus productive
    Le travail des chefs de projets n’est pas d’assigner des tâches encore et encore tout au long de la vie des projets. Les intervenants ne devraient pas être ralentis par les tâches administratives de leurs chefs de projets.
  • Skriv est simple d’utilisation
    Je sais, tous les autres logiciels prétendent être faciles à prendre en main. Mais alors pourquoi ressemblent-ils au tableau de bord d’une navette spatiale ?

Si vous voulez participer au bêta-test de Skriv, c’est assez simple :

  1. Envoyez un email à contact@skriv.com pour montrer votre intérêt. Parlez-moi de votre équipe, des types de projets sur lesquels vous travaillez et de comment vous les gérez.
  2. Nous passerons de 15 minutes à une heure ensemble, afin que je vous présente le fonctionnement de Skriv. On peut faire ça par téléphone, mais une rencontre de visu sera plus efficace.
  3. Toutes les semaines, je vous contacterai pour savoir comment les choses se passent. Pendant ce temps, vous pourrez faire des remontées de bogues sur une interface dédiée.

J’espère qu’ensemble nous pourrons créer le meilleur outil de gestion de projets.
Je vous remercie d’avance pour votre temps et votre aide.