Blog myBlog = BlogFactory.getWordPressBlog();
Systèmes d’information
Maven au pays des proxys
15/01/12
Le problème…
Il y a quelques temps, j’ai eu pour mission de stabiliser et de « mavenizer » une application legacy, dont le build était devenu ingérable (dépendances dans divers répertoires, mélanges de scripts shell, Ant, etc.).
Au sujet de la mavenization elle-même, je vous recommande cet article, donnant une méthode fiable permettant de retrouver la version exacte des dépendances lorsqu’elles ne sont pas connues. Je passe cependant rapidement sur cette étape qui n’est pas le sujet ici. Nous arrivons donc directement au moment où nous avons un fichier « pom.xml » convenable, dont nous voulons vérifier le bon fonctionnement pour assurer le packaging de l’application. Et c’est là que les choses commencent à se compliquer.
Car ce que j’ai oublier de préciser, c’est que cette mission est effectuée pour « Gros client », chez qui les règles de sécurité sont strictes : l’accès internet se fait uniquement au travers d’un proxy. Et plus particulièrement le modèle PALC avec toutes les options : identification individuelle obligatoire sur ledit proxy, mot de passe à modifier tous les 3 mois, verrouillage du compte après 5 tentatives ratées, etc. Pour Maven qui aime bien « télécharger l’univers », c’est problématique.
Petite digression sur une mauvaise surprise découverte lors de cette mission… Ubuntu 11.10 n’est pas du tout adapté au travail dans un environnement utilisant un proxy : il souffre en effet d’une régression empêchant le paramétrage d’exceptions (pour les serveurs du réseau local).
Paramétrer le proxy pour Maven
Maven fournit un guide pour paramétrer un proxy. L’opération consiste à renseigner les paramètres du proxy dans le « settings.xml » :
1 2 3 4 5 6 7 8 9 10 11 | <proxies> <proxy> <active>true</active> <protocol>http</protocol> <host>palc.grosclient.com</host> <port>8080</port> <username>user</username> <password>password</password> <nonProxyHosts></nonProxyHosts> </proxy> </proxies> |
Une fois ce paramétrage effectué, les dépôts sont bien résolus et les dépendances téléchargées. Mais il reste un soucis : certains dépôts irréductibles résistent encore… Par exemple le dépôt JBoss, ou encore Sonatype OSS. La cause est vite identifiée : ces dépôts utilisent le protocole « https » et non « http ».
Qu’à cela ne tienne : on duplique le bloc « proxy » en modifiant le protocole. A ceci près que ça ne marche pas… Maven ne sait utiliser qu’un seul proxy à la fois. Si on utilise le proxy « https », on pert le « http », et inversement. Peut-être une idée de correction à implémenter pour le hackergarten de mercredi prochain…
La seule solution que j’ai pu trouver à ce jour est de paramétrer les proxys au niveau de la ligne de commande :
1 2 3 4 5 6 7 8 9 10 | mvn -Dhttp.proxyHost=palc.grosclient.com -Dhttp.proxyPort=8080 -Dhttp.proxyUser=user -Dhttp.proxyPassword=password -Dhttps.proxyHost=palc.grosclient.com -Dhttps.proxyPort=8080 -Dhttps.proxyUser=user -Dhttps.proxyPassword=password install |
Il est possible de paramétrer un proxy dans le « settings.xml » et le deuxième en ligne de commande mais ce n’est pas très intuitif. J’aime autant que tous les paramètres soient au même endroit.
Une fois les paramètres correctement configurés, on peut les pérenniser en les enregistrant dans la variable d’environnement MAVEN_OPTS.
Utiliser un dépôt Maven interne
Suite au paramétrage correct des proxys (http et https), Maven peut à nouveau télécharger tout internet… et le build peut fonctionner. Nous pouvons donc aller plus loin et installer un dépôt Maven chez « Gros client », afin d’y publier les artefacts produits.
Cependant, ce serveur peut également servir à régler autrement notre problème de proxy. Pour cela, il y a un pré-requis : le serveur doit être accessible directement depuis le réseau de développement, et avoir accès à internet (si possible sans proxy). Dans notre cas, c’est Nexus qui fait office de dépôt Maven (mais la même technique doit fonctionner avec Artifactory ou autre…). Ensuite :
- On configure différents dépôts de type « proxy » vers chacun des dépôts externes dont on a besoin.
- On ajoute tous ces dépôts au dépôt groupe « public ».
Enfin, nous devons expliquer à Maven qu’il doit systématiquement utiliser notre serveur interne au lieu de tenter d’accéder directement aux dépôts externes (Maven central, etc.). Pour cela, retour dans « settings.xml », mais cette fois dans le bloc mirrors. Il suffit d’expliquer à Maven que tous les dépôts dont ont a besoin ont pour miroir notre serveur interne :
1 2 3 4 5 6 7 8 | <mirrors> <mirror> <id>nexus.grosclient.com</id> <name>Serveur Nexus de Gros client</name> <url>http://nexus.grosclient.com/content/groups/public</url> <mirrorOf>*</mirrorOf> </mirror> </mirrors> |
Avec cette configuration, le paramétrage des proxys fait précédemment doit être supprimé (ou une exception doit être ajoutée pour le dépôt interne).
Cette dernière configuration présente plusieurs avantages :
- L’ensemble des dépôts susceptibles d’être utilisés dans les différents projets de l’entreprise sont configurés de manière centrale, au niveau du dépôt. Cela permet
à l’équipe agileau chef de projet (rappel : nous sommes chez Gros client) de contrôler les dépôts/librairies utilisées sur le projet. - Le premier développeur qui demande une librairie au serveur Nexus va déclencher son téléchargement depuis son dépôt initial. Mais celle-ci sera ensuite mise en cache sur le serveur. Ainsi, les appels suivants (par les autres développeurs) se contenteront d’effectuer un téléchargement sur le réseau local, avec un gain de temps (voire de bande passante) non négligeable.
Sauvegarde automatique de l’historique d’un document
27/09/11
Il est des semaines où on doit troquer son IDE préféré pour des outils bizarres tels que OpenOffice LibreOffice, Microsoft Office, voire pire… Microsoft Project. Or avec ces outils, on a vite fait de perdre plusieurs heures de travail avec une fausse manipulation. Afin de palier à ce problème, j’ai mis à contribution un de mes outils préférés : git. Il n’y a pas de raison que les documents ne soient pas versionnés, au même titre que du code. D’autant plus que le coût de mise en place d’une telle sauvegarde est très faible :
1 2 3 | git init git add mondocument git commit -m 'Première sauvegarde de mon document' |
Diff entre deux versions
En commitant régulièrement son document, on en constitue un historique. Et avec les branches, on peut même le décliner en plusieurs versions. Je n’ai par contre pas réussi à créer de « feature branch » documentaire, la fusion automatique de documents binaires avec git se passant bizarrement assez mal.
L’autre problème avec des documents binaires, c’est qu’ils passent assez mal dans le « diff », ce qui fait perdre à la gestion de configuration une partie de son intérêt. Mais pour ce problème là, il existe une solution. Il suffit d’avoir un outil permettant d’afficher un document un mode texte. Dans le cas du format OpenDocument, on peut par exemple utiliser odt2txt.
Il faut ajouter dans .gitconfig le bloc suivant, pour déclarer le convertisseur associé au format odf :
1 2 | [diff "odf"] textconv=odt2txt |
Enfin, dans le répertoire du dépôt du projet, il faut associé ce convertisseur avec les extensions des fichiers OpenOffice. Ca se passe dans le fichier info/attributes :
1 2 3 | *.odt diff=odf *.ott diff=odf # idem pour les formats ods, ots, odp et otp |
Cette modification effectuée, on récupère la possibilité de calculer le différentiel entre deux commits, et toutes les fonctionnalités associées.
Le seul inconvénient, c’est qu’il faut répéter cette opération pour chaque dépôt de documents. Je n’ai pas trouvé le moyen de définir ces comportements dans la configuration globale de git. Si quelqu’un a une solution, je suis preneur !
Automatisation de la sauvegarde
Afin d’améliorer un peu le processus, il suffit d’un petit script shell qui automatise l’enregistrement du document à intervalles réguliers :
1 2 3 4 5 6 7 8 9 | #!/bin/sh # Intervalle entre deux enregistrements SAVE_PERIOD_IN_SECONDS=120 while : do echo "Autosave : $(date)" git commit -a -m "Autosave $(date)" sleep $SAVE_PERIOD_IN_SECONDS done |
Ce script utilise une des particularités intéressantes de git : si le fichier n’a pas évolué pendant l’intervalle, le commit n’est pas effectué. Ainsi, l’historique des versions du document pourra sauter des enregistrements (si on a oublié d’enregistrer le document entretemps par exemple).
Pour finir, voici donc le script en action :
Premiers pas sur CloudBees
10/07/11
Mardi dernier se tenait le traditionnel Paris JUG, recevant Patrick Chanezon venu nous parler du Cloud. Au passage, félicitons l’organisation qui est passée de JugEvent à EventBrite, beaucoup plus fiable (et qui m’a permis d’avoir une des dernières places libérées le jour même de la conférence).
Dans la nuit qui a suivi, Olivier et Nicolas ont respectivement publié des excellents comptes-rendus de cette soirée. Merci et félicitations à eux donc :
- Paris JUG « Cloud »
- Patrick Chanezon au Paris JUG, Didier Girard, SFEIR, Création de valeur et compétitivité avec le Cloud, et CloudFoundry présenté par Guillaume Laforge, Soirée Patrick Chanezon
Voici donc, modestement, un petit compte-rendu de tests que j’ai eu l’occasion de faire sur deux des plate-formes dont il était question à cette soirée.
La suite >
Mettre en place un workflow git
2/06/11
Si vous avez été à une ou deux présentations de git, vous avez sans doute déjà vu ce diagramme (ou un équivalent).
Après avoir un peu pratiqué git, ce genre de workflow devient naturel, et est particulièrement appréciable :
- les fonctionnalités ont chacune leur branche dédiée : la lecture de son historique n’est donc pas gêné par le reste des développements
- les livraisons peuvent être préparées sans empêcher les personnes qui travaillent sur les futures fonctionnalités de partager leur travail
- etc.
Voila pour la théorie : sur le papier, ça laisse absolument rêveur ! Mais dans la pratique, tout ne fonctionne pas aussi bien, surtout au début. Et c’est là que commence mon retour d’expérience sur la mise en place de ce workflow.
PlayFramework et CloudFoundry RELOADED
5/05/11
L’informatique bouge décidément très vite !… A peine quelques jours et mon précédent article est déjà obsolète. Voici donc sa mise à jour.
Problèmes de fixtures
Revenons tout d’abord aux problèmes que j’ai rencontré avec la classe Fixtures, qui provoquaient deux erreurs lors du déploiement de l’application sous forme de WAR. Il s’agissait d’un bug spécifique à la version 1.2 de PlayFramework. Or avant même que j’aie le temps de le temps de dire ouf, la version 1.2.1 était publiée (une journée après mon article), corrigeant le bug en question !
J’ai depuis revérifié mon exemple : plus aucun problème de ce côté. Il est donc possible de déployer l’application YABE sur Cloud Foundry sans avoir à modifier la moindre ligne de code.
1 2 3 4 5 6 | cd $PLAY_HOME/samples-and-tests play war yabe -o yabe_war cd yabe_war jar -cvf yabe.war * rm -rf WEB-INF vmc push |
Ca marche !
Utilisation du service MySQL de CloudFoundry
De ce côté là aussi, les choses ont bougé. Je me suis attelé à la tâche en créant un plugin dédié, dont le code (et les binaires) est disponible sur GitHub. Bon, je n’ai pas beaucoup de mérite : le plus gros du travail a été fait par SpringSource, avec le cloudfoundry-runtime.
Ca a été pour moi l’occasion de me familiariser vraiment avec une des nouvelles fonctionnalités de PlayFramework : la gestion des dépendances Maven. Voici à titre d’exemple le fichier dependencies.yml du plugin :
self: play -> cloudfoundry 0.1
require:
- play
- org.cloudfoundry -> cloudfoundry-runtime 0.6.0:
exclude:
- org.springframework -> *
- org.springframework.amqp -> *
- org.springframework.data -> *
- org.apache.tomcat -> *
- commons-dbcp -> *
repositories:
- spring_milestone:
type: iBiblio
root: http://maven.springframework.org/milestone
contains:
- org.cloudfoundry -> *Cette librairie effectue le travail de lecture et de parsing des variables d’environnement. Il suffisait donc ensuite de se servir des résultats de se parsing pour configurer la connexion à la base de données.
Cette fois, c’est le PlayFramework lui-même qui va nous simplifier la tâche. Les plugins peuvent surcharger la méthode onApplicationStart(), qui s’exécute comme son nom l’indique au démarrage de l’application.
1 2 3 4 5 6 7 8 9 10 11 | public class CloudFoundryDBPlugin extends PlayPlugin { @Override public void onApplicationStart() { Properties p = Play.configuration; MysqlServiceInfo mysqlServiceInfo = getInfoFromCloudFoundryRuntimeLib(); p.put("db.driver", "com.mysql.jdbc.Driver"); p.put("db.url", mysqlServiceInfo.getUrl()); p.put("db.user", mysqlServiceInfo.getUserName()); p.put("db.pass", mysqlServiceInfo.getPassword()); } } |
Et c’est tout. Pour utiliser ce plugin, il suffit d’ajouter le module correspondant dans l’application PlayFramework que l’on veut déployer sur Cloud Foundry, soit dans application.conf :
1 2 3 | # Replace ce memory db by the cloudfoundry MySQL service # db=mem module.cloudfoundry=${play.path}/modules/cloudfoundry |
Encore une fois, c’est tout : la magie de PlayFramework se charge du reste !
Il n’y a plus qu’à régénérer le WAR et mettre à jour l’application : ça marche, comme en témoigne l’application mise à jour http://yabe.cloudfoundry.com/
Et maintenant…
Le plugin ne gère pour l’instant que la configuration automatique d’un service MySQL de Cloud Foundry. Mais si des spécialistes de Redis, MongoDB veulent donner un coup de main pour gérer ces bases, les merge request de GitHub sont là pour ça.
Application Play Framework sur Cloud Foundry
1/05/11
Il y a quelques semaines, j’ai obtenu un accès à la béta de Cloud Foundry. Pour ceux qui n’ont pas suivi l’actualité, il s’agit d’un PaaS (Platform as a Service) Open Source de VMWare, permettant d’exécuter en cloud des applications Java (WAR, Spring, ROO), Rails, ou Node.js (pour l’instant, mais d’autres pourraient bientôt venir enrichir cette liste).
Prise en main
La prise en main de l’outil de déploiement VMC via le tutoriel est extrêmement simple. On y apprend à créer et déployer une application sur le cloud en quelques commandes.
Deuxième chose à laquelle je m’intéresse, les systèmes de persistance. On a le choix entre trois systèmes, SQL (MySQL) ou NoSQL : MongoDB (base orientée documents) et Redis (base clé-valeur). Cette liberté de choix est très appréciable, et permet de répondre aux différents types de besoins que l’on peut avoir. Et là encore, on peut penser que d’autres systèmes viendront prochainement enrichir cette liste.
Côté Java, encore de bonnes surprises : contrairement au Google App Engine (par exemple), il n’y a aucune restriction sur l’utilisation de l’API : l’application est exécutée sur un serveur Tomcat. Il est donc possible de développer une application web Java complètement standard, et ensuite de la déployer sur Cloud Foundry au lieu d’un serveur d’application classique.
J’ai fait le test (avec une application simple) et ça fonctionne !
Avec Spring et l’outil de développement Spring Tool Suite, la gestion de la persistence MySQL est très simple, comme expliqué sur le blog officiel.
La suite >
Gérer AUTREMENT un projet Maven avec Git
13/04/11
Comme vous avez été nombreux à apprécier mon article sur Maven et git, en voici la suite ! Il s’agit d’une solution alternative permettant de répondre à la même problématique, basée sur les subtree.
Rappel : mon but était de séparer la gestion de configuration de plusieurs modules Maven d’un même projet, tout en conservant un dépôt pour maintenir le projet (pom racine du projet, etc.).
La problématique étant la même, nous allons nous baser sur le même exemple : un projet créé à partir de l’archetype appfuse-modular-jsf. Pour sa mise en place de ce projet, je vous renvoie donc aux étapes Créer le projet de démonstration et Mise en place des dépôts distants.
Revenons à notre espace de travail
Maintenant que nous avons nos dépôts distants, la première chose à faire pour mettre en place les subtrees est de supprimer les répertoires des deux modules dans l’espace de travail. En effet, avec cette méthode, les modules n’ont pas de dépôt git locaux dédiés.
Déclarons ensuite les dépôts distants de notre espace de travail :
1 2 3 | git remote add origin $BARE_REPOS/demo.git # S'il n'existe pas déjà git remote add core $BARE_REPOS/demo-core.git git remote add webapp $BARE_REPOS/demo-webapp.git |
A ce stade, les habitués de git qui ne sont pas trop endormis doivent crier « KEUOUA ??? ». Effectivement, les démos distants sont normalement des clones du dépôt local. Or nous venons de déclarer trois dépôts distants qui n’ont pas un seul commit en commun.
Ce n’est pas une erreur, et c’est le mode de fonctionnement des subtrees. Contrairement aux submodules pour lesquels on avait trois dépôts locaux, avec les subtree, on a un unique dépôt local : le lien entre cet unique dépôt et les dépôts distants passe donc par les « remotes » du dépôt local.
Des branches locales pour travailler sur les modules
Nous allons maintenant créer des branches locales associées aux branches distantes afin de pouvoir travailler sur nos modules.
1 2 3 4 | git fetch core git fetch webapp git branch localcore --track core/master git branch localwebapp --track webapp/master |
Il est maintenant possible de travailler sur les modules localcore et localwebapp dans leurs branches locales respectives. Le tracking étant défini, les push seront effectués vers les dépôts respectifs des deux modules.
Et l’arborescence globale de notre projet ?
Depuis notre unique dépôt local, nous avons vu comment travailler séparément sur nos différents modules. Mais à ce stade, nous n’avons pas reconstitué l’arborescence de notre projet Maven. C’est à ce stade qu’interviennent les subtrees.
On rebascule dans la branche master de notre projet, et on exécute :
git read-tree --prefix=core/ -u localcore git read-tree --prefix=webapp/ -u localwebapp
Après cette étape, on n’oublie pas de commiter l’ensemble et nous avons récupéré l’arborescence globale de notre projet.
Mettre à jour le projet lorsque les modules évoluent
Notre module core a maintenant évolué dans sa branche. Ces modifications ne sont pas automatiquement reportées dans la branche master de notre projet.
Pour récupérer ces mises à jour, il suffit d’utiliser la commande :
1 | git merge -s subtree localcore |
Cette opération aura pour effet de fusionner dans la branche master les modules (ainsi que leurs historiques respectifs).
On peut juger que ces historiques sont « parasites » à ce niveau : on les a déjà dans la branche du module. On préfèrera dans ce cas la commande :
1 | git merge -s subtree --squash --no-commit localcore |
Cela aura pour effet d’agréger tous les commits en un seul et de préparer le message de commit (qui concatène les messages de tous les commits agrégés). Il ne reste plus qu’à corriger ce message et à valider le commit.
Submodules ou Subtrees ?
Nous avons donc deux méthodes permettant de traiter la même problématique. Il ne reste plus qu’à en choisir une. Les deux approches ont leurs avantages et leurs inconvénients.
Les subtrees sont plus faciles à manipuler : ils nécessitent moins d’opérations, et il est plus difficile de faire une erreur qu’avec les submodules (oubli d’un push par exemple).
Les submodules sont plus complexes à utiliser, mais plus structurés (il s’agit là d’un avis subjectif de ma part) : chaque dépôt distant est associé à un dépôt local.
Personnellement, ce sont les submodules que je préfère.
Gérer un projet Maven multi-modules avec Git
4/03/11
J’ai récemment assisté à l’atelier Git avancé de Christophe Porteneuve. Au programme, de nombreuses choses intéressantes, dont les submodules Git, La partie de la formation les concernant m’intéressait particulièrement pour une problématique que je rencontre très fréquemment : travailler avec un projet Maven multi-modules.
Il y a bien sûr la solution qui consiste à utiliser un unique dépôt Git à la racine du projet. Ca fonctionne bien, mais pour des gros projets, je préfère avoir un dépôt dédié à chacun des modules Maven. Cela ne poserait aucun problème, s’il n’y avait une arborescence de répertoires entre le projet principal, et ses modules.
Voyons donc avec un exemple comment mettre en place une gestion de configuration séparée pour chacun des modules d’un projet Maven.
La suite >
Au revoir SVN… Bonjour Git !
7/12/10
Commençons par un résumé des épisodes précédents :
- Tout a commencé avec la découverte de Git.
- Après un premier test concluant, c’est à l’atelier de rentrée de Git-Attitude que j’ai vraiment appris à utiliser Git et eu « l’effet Whaou » !
- Convaincu par l’intérêt des DCVS, j’ai commencé à travailler avec Git comme frontal de Subversion : voir ici et là.
- Après avoir joué avec Git, « Git + SVN » laisse un sérieux arrière-goût d’inachevé. Nous avons donc cherché et trouvé une solution pour coupler Git au SI, de la même manière que SVN avant lui.
La solution ayant été trouvée, il ne reste plus qu’à effectuer la migration définitive de SVN vers Git, en conservant l’historique du projet.
La suite >
Git et LDAP en entreprise
19/11/10
Le gain apporté par les gestionnaires de configuration distribués n’est plus à démontrer. Dans ce domaine, les projets libres montrent la voie, et en utilisent presque tous un, que ce soit Git, Mercurial, etc.
Cela fait maintenant quelques temps que je teste Git, y compris au travail en interface avec SVN, notre gestionnaire de configuration d’entreprise.
Pour aller plus loin dans cette utilisation, il fallait envisager de remplacer (ou de doubler) le serveur SVN central par un repository Git central (« bare repository« ). La contrainte imposée par mon administrateur système préféré étant d’avoir le même système de gestion des droits d’accès, centralisé sur notre serveur LDAP (où chaque projet est associé à un groupe d’utilisateurs).
Voici différentes pistes que nous avons envisagées pour ce faire :
La suite >
