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à !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *