Rpm-maven-plugin & fichiers de configuration
Chez Alinto, nous avons choisi le format RPM pour packager nos applications. Pour les construire, nous utilisons Maven et plus précisément le plugin répondant au doux nom de « rpm-maven-plugin ». Il suffit de quelques lignes de configuration pour définir le comportement du RPM comme nous allons le voir à présent.
Exemple générique
Voici à quoi ressemble typiquement la configuration du plugin maven :
<profile> <id>rpm</id> <activation> <activeByDefault>false</activeByDefault> </activation> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>rpm-maven-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>rpm</goal> </goals> </execution> </executions> <configuration> ... </configuration> </plugin> </plugins> </build> </profile>
On définit ici un profil « rpm
» qu’on active au besoin (-Prpm
) lors du lancement du build Maven. Regardons de plus près la configuration pour une application web :
<configuration> <name>alinto-nom-produit</name> <version>1.0</version> <release>BETA1</release> <summary>Produit d'Alinto</summary> <description>Bla bla bla</description> <group>Application/Collectors</group> <defaultDirmode>750</defaultDirmode> <defaultFilemode>660</defaultFilemode> <defaultUsername>tomcat</defaultUsername> <defaultGroupname>tomcat</defaultGroupname> <requires> <require>tomcat >= 0:6.0.29</require> </requires> <mappings> <mapping> <directory>/chemin/vers/tomcat/webapps/ma-webapp</directory> <sources> <source> <location>target/fichiers-compiles</location> </source> </sources> </mapping> </mappings> </configuration>
Rien de bien compliqué ici, vous devez définir le nom du RPM, sa version, son tag et renseigner quelques informations descriptives.
Par défaut, les fichiers sont créés avec comme propriétaire et comme groupe « tomcat
» afin d’éviter toute erreur de permissions lors du déploiement des applications web.
D’autre part, on définit une dépendance : le paquet ne peut être installé sans Tomcat en version supérieure à 6.0.29.
Penchons-nous à présent sur la partie mappings : ces quelques lignes permettent d’inclure les fichiers compilés lors du mvn install
(« target/fichiers-compiles
») dans le RPM et que ceux-ci soient posés dans le répertoire des webapps Tomcat à l’installation. D’autre part, les fichiers définis dans le mapping sont déclarés comme liés au RPM : vous pouvez le vérifier en tapant rpm -qpl fichier.rpm
.
Vous le savez probablement, la configuration d’un RPM est définie par un fichier en .spec
. Voyons à quoi il ressemblerait avec la configuration actuelle :
Name: alinto-nom-produit Version: 1.0 Release: BETA1 Summary: Produit d'Alinto License: 2013 Alinto Vendor: Alinto URL: http://mon.url.com Group: Application/Collectors Packager: Alinto Requires: tomcat >= 0:6.0.29 autoprov: yes autoreq: yes BuildRoot: /.../target/rpm/nom-produit/buildroot %description Bla bla bla %files %defattr(660,tomcat,tomcat,750) /chemin/vers/tomcat/webapps/ma-webapp
Gestion des fichiers de configuration
L’exemple de mapping ci-dessus est plutôt sommaire. Entre autres, il ne permet pas d’utiliser des fichiers de configuration (.properties
) pour pouvoir paramétrer l’application après livraison. Ceci est bien évidemment facilement réalisable dans le packaging RPM. Avant de parler de configuration Maven, faisons un petit point sur le comportement des fichiers définis dans la partie %files
du .spec
.
Lors de la première livraison du RPM, tous les fichiers définis dans la partie %files
sont créés dans le répertoire désiré. Si ce sont des fichiers de configuration, l’administrateur devra très certainement éditer ces fichiers pour renseigner la connexion à la base de données par exemple. Jusqu’ici, tout va bien.
Maintenant, que se passe-t’il si l’on livre une nouvelle version du RPM dans laquelle ces fichiers de configuration ont été mis à jour ? Seront-ils écrasés ou non ? Le comportement dépend alors de la configuration définie dans le .spec
:
Directive .spec |
Fichier intact sur le serveur | Fichier modifié sur le serveur |
Défaut | Écrasé par le fichier du RPM | Écrasé par le fichier du RPM |
%config |
Écrasé par le fichier du RPM | Écrasé par le fichier du RPM, ancien fichier en .rpmsave |
%config(noreplace) |
Écrasé par le fichier du RPM | Fichier intact, nouveau fichier du RPM en .rpmnew |
Chez Alinto, nous définissons généralement 3 fichiers de configuration par application :
local.properties
qui définit toute la configuration spécifique à la plateforme : typiquement l’adresse du serveur de base de données, le login et mot de passe associés… Cette configuration change avec la plateforme d’installation mais rarement avec les nouvelles version du produit ;product.properties
qui définit toute la configuration spécifique au produit : injections Spring, services utiles… À l’inverse, cette configuration change souvent avec les versions de produit mais est sensée être identique d’une plateforme à l’autre ;log4j.properties
qui définit le comportement du logging et est donc plutôt lié à la plateforme d’installation.
Bien évidemment, on n’a pas envie de perdre à chaque nouvelle livraison les configurations de l’instance définies dans le local.properties
et le log4j.properties
. Elles sont faites une bonne fois pour toutes et ne sauraient être remplacées. En revanche, la configuration du product.properties
doit être mise à jour lors d’une livraison de RPM sans quoi l’application a de bonnes « chances » de ne plus fonctionner.
D’après le tableau ci-dessus, ce comportement peut être obtenu en définissant les fichiers local.properties
& log4j.properties
en %config(noreplace)
d’une part et le fichier de product.properties
en %config
d’autre part. Ce dernier sera donc le seul écrasé à chaque mise à jour de RPM.
La configuration Maven correspondante est la suivante :
<mappings> <mapping> <directory>/chemin/vers/tomcat/webapps/ma-webapp</directory> <sources> <source> <location>target/fichiers-compiles</location> </source> </sources> </mapping> <mapping> <directory>/chemin/vers/tomcat/webapps/ma-webapp/WEB-INF/classes</directory> <configuration>noreplace</configuration> <sources> <source> <location>/chemin/vers/fichiers/de/conf/source</location> <includes> <include>log4j.properties</include> <include>*.local.properties</include> </includes> </source> </sources> </mapping> <mapping> <directory>/chemin/vers/tomcat/webapps/ma-webapp/WEB-INF/classes</directory> <configuration>true</configuration> <sources> <source> <location>/chemin/vers/fichiers/de/conf/source</location> </source> </sources> </mapping> </mappings>
Vous noterez qu’en réalité, on applique ici la directive %config
par défaut à tous les fichiers contenus dans le répertoire de configuration. Les fichiers local.properties
et log4j.properties
sont simplement surchargés en %config(noreplace)
.
Le .spec
final ressemble alors à ceci :
... %files %defattr(660,tomcat,tomcat,750) ... %config(noreplace) /chemin/vers/tomcat/webapps/ma-webapp/WEB-INF/classes/exemple.local.properties %config(noreplace) /chemin/vers/tomcat/webapps/ma-webapp/WEB-INF/exemple.local.properties %config /chemin/vers/tomcat/webapps/ma-webapp
Pour finir, imaginons le cas où l’on installe un RPM à 17h, on modifie tous les fichiers de configuration installés puis on met à jour le RPM quelques minutes plus tard avec de nouveaux fichiers de configuration. Le listing de ces fichiers devrait ressembler à ça :
[root@machine conf]# ls -l total 32 -rw-rw---- 1 tomcat tomcat 2807 oct. 18 17:01 exemple.local.properties -rw-rw---- 1 tomcat tomcat 1498 oct. 18 17:16 exemple.local.properties.rpmnew -rw-rw---- 1 tomcat tomcat 6904 oct. 18 17:16 exemple.product.properties -rw-rw---- 1 tomcat tomcat 6614 oct. 18 17:01 exemple.product.properties.rpmsave -rw-rw---- 1 tomcat tomcat 3599 oct. 18 17:01 log4j.properties -rw-rw---- 1 tomcat tomcat 3642 oct. 18 17:16 log4j.properties.rpmnew
Le product.properties
a bien été remplacé par la nouvelle version, l’ancienne étant sauvegardée en .rpmsave
. En revanche, les autres fichiers n’ont pas été écrasés et les nouvelles versions sont disponibles en .rpmnew
. Et voilà !