Alfresco est un ECM opensource très complet. Il utilise pricipalement des briques elles aussi opensources, comme un serveur d’application (tomcat par défaut), une suite bureautique (openoffice ou libreoffice), des outils de manipulation d’image (imagemagick), et bien sur un SGBD! C’est cette dernière partie qui nous interresse ici. Après avoir fournit par défaut mysql, l’installeur Alfresco embarque aujourd’hui postgreSQL par défaut. On pourrait discuter les avantages de l’un ou de l’autre, et certainement qu’aucun consensus n’emmergerait…
Quoiqu’il en soit, j’ai eu l’occasion de voir des cas de figure où des DBAs souhaitent se débarrasser de leur base MySQL pour passer sous postgres.
Ce tuto explique comment réaliser cette opération pour Alfresco. Cette procédure fonctionne (pour autant que j’ai pu la tester) avec Alfresco 3.4.x et 4.x. elle ne fonctionne pas tel qu’elle avec des version plus anciennes que 3.4!
Le principe ici est relativement simple:
Le schéma de base de données est relativement complexe et entièrement géré par hibernate/ibatis… difficile de d’y comprendre quelque chose au premier abord! Afin de minimiser les sources d’erreur, on va laisser Alfresco créer la nouvelle base, puis ensuite y insérer des données brutes… Bien entendu, quelques traitements seront nécessaires mais rien de fondamentalement tordu.
- Prérequis:
- On suppose ici que les versions source et destination sont identiques: Si une migration de version est prévue, elle peut être faite dans un second temps. Ceci est purement une précaution car je n’ai pas testé la procédure lors d’un changement de version…mais ca pourrait bien marcher!
- On suppose aussi que les collations et jeux de caractères (charset) utilisés sont similaires. Par défaut postgres et mysql devraient utiliser UTF-8 et utf8_bin.
- Il est nécessaire de prévoir un downtime lors de l’upgrade afin d’assurer la cohérence des données des instances source et destination.
- Une base toute belle, toute propre:
Pour commencer on va déployer une nouvelle instance d’Alfresco, instance complètement vierge, utilisant PostgreSQL comme SGDB. On ne va pas détailler cette procédure étant donné que si vous penser à changer de SGBD, je suppose que vous maitriser l’installation d’Alfresco et ses différents composants. En résumé, installez Tomcat, créez une base Postgres et son user associé, posez les war Alfresco, dans webapps, et configurer votre fichier alfresco-global.properties afin de pointer sur la base vide nouvellement créée.
Lorsque Tomcat va déployer Alfresco, celui-ci va trouver une base de donnée vide. Il va donc la structurer comme il se doit (si quelqu’un sait faire ça, c’est bien Alfresco lui même!), et la remplir des données nécessaires au démarrage du serveur.
Une fois le démarrage terminé, Alfresco a fait sa part du travail, à nous de jouer donc! Nous allons utiliser cette base nouvellement créée comme un modèle pour être sur d’avoir une structure tel qu’attendu par Alfresco. Pour cela on dump la structure de la base (les données ne nous intéressent pas ici).
~$ pg_dump -h gimly -U alfresco -W -s alfresco > /tmp/pg_schema.sql
Afin d’éviter des problèmes lors de la restauration des données, nous allons séparer ce fichier en deux. D’un coté on créé un fichier contenant la définition des tables (/tmp/pg_schema_table.sql), et de l’autre un second fichier qui contient les contraintes et les index (/tmp/pg_schema_fk-idx.sql). On garde ces fichiers précieusement pour plus tard, quant au reste de l’instance on peut le supprimer.
- Sauvegarde des données de prod:
On va maintenant éteindre l’instance Alfresco source (celle tournant sur MySQL), afin de procéder à un backup consistant de la base de données et des autres données.
Pour faire la sauvegarde du content store et des indexes, un outil comme tar fera tout à fait l’affaire. Dans notre cas, pour la sauvegarde de la base, ou va utiliser mysqldump et lui spécifier de ne prendre que les données en ignorant toutes les statements des création de la structure. En effet, pour la structure, on s’appuiera sur la base créée précédemment durant le déploiement d’Alfresco.
~$ mysqldump -u root -p -n -c --hex-blob --default-character-set=utf8 --compact --compatible=postgresql -t alfresco | \
sed -r -e 's/0x00([),])/false\1/g' \
-e 's/0x01([),])/true\1/g' \
-e "s/([(,])0x([0-9a-fA-F]*)([),])/\1decode('\2','hex')\3/g" \
-e 's/INSERT INTO "([a-zA-Z_-]+)" \((.*)\) VALUES \(/INSERT INTO "\1" (\L\2) VALUES (/g' \
> /tmp/data.sql
Comme vous pouvez le voir ci dessus, on procède en même temps à une série de traitement sur les requêtes produites. En voici en détails, l’explication de chaque option/traitement:
-n : spécifie à mysqldump de ne pas inclure les requêtes de création de table.
-c : spécifie à mysqldump d’inclure les nom des tables dans les statements d’INSERT. Ceci évite des problèmes dues à l’ordonnancement des colonnes dans une table.
–compatible=postgresql : spécifie à mysqldump de produire une sortie plus PostgreSQL friendly (malheureusement ça n’est pas suffisant pour permettre à postgres de traiter le fichier).
–hex-blob : spécifie à mysqldump de traiter les champ de type binaire (blolb ou booléen) comme des chaines hexa-décimales. Cela permet un traitement plus simple via sed.
–default-character-set=utf8 : spécifie le jeu de caractère par défaut comme étant UTF-8.
–compact: spécifie à mysqldump de zapper différents statement inutiles ici.
s/0x00([),])/false\1/g : on map la valeure hexadecimale 0x00 inconnue de Postgres vers false (typiquement requis pour les champs booléens).
s/0x01([),])/true\1/g : on map la valeure hexadecimale 0x01 inconnue de Postgres vers true (typiquement requis pour les champs booléens).
s/([(,])0x([0-9a-fA-F]*)([),])/\1decode(‘\2′,’hex’)\3/g : on insert la fonction decode() de Postgres afin de re-créer les champs binaires correctement.
s/INSERT INTO « ([a-zA-Z_-]+) » \((.*)\) VALUES \( : On utilise sed afin de passer les nom de table et de colonnes en lower case.Le fichier ainsi obtenu et presque prêt, il ne reste plus qu’à y ajouter les lignes ci dessus au tout début:
SET statement_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET escape_string_warning = off;
- Restaurons les données sur PostgreSQL:
Afin de restaurer les données sur notre nouveau SGDB, on va tout d’abord supprimer la base postgres que nous avons créé à la première étape, puis la recréer vide. Celle ci ne nous a servi qu’à avoir un dump postgres de la structure de la base.
~$ dropdb alfresco
~$ createdb -Oalfresco alfresco
On restaure la structure seule de la base, sans les index ni les contraintes:
~$ psql -h gimly -U alfresco -W alfresco < /tmp/pg_schema_table.sql
Puis on insert les données:
~$ psql -h gimly -U alfresco -W alfresco < /tmp/data.sql
Et ensuite on recréé les index et les contraintes:
~$ psql -h gimly -U alfresco -W alfresco < /tmp/pg_schema3411_fkIdx.sql
A ce stade, la base de données est quasiment prête pour me démarrage d’alfresco. Le dernier problème qu’il nous reste a traiter est la gestion des séquence. En effet Postgres, comme la plupart des RDBMS, utilise des séquences pour choisir automatiquement les valeurs d’entier à venir. MySQL, quant à lui, ne possèdent pas de séquence mais utilise à la place une option pour les champs de type entiers: AUTO_INCREMENT. Là encore on pourrait disserter sur le bien fondé et les limitations de chaque approche (sans parlé du respect des standards SQL)…
Toujours est il qu’il est nécessaire de mettre à jour les séquences postgreSQL afin de ne pas créer de problème lors de l’utilisation d’Alfresco.
Pour cela on va extraire de MySQL, les valeurs des champs impliqués, et les stocker dans un fichier:
mysql> use information_schema
mysql> SELECT TABLE_NAME,AUTO_INCREMENT
FROM TABLES
WHERE TABLE_SCHEMA='alfresco'
AND TABLE_NAME NOT LIKE 'jbpm_%'
INTO OUTFILE '/tmp/AI.sql';
Puis on traite ce fichier afin de mettre à jour les séquences PostgreSQL:
grep -v '\N$' /tmp/AI.sql | \
awk '{print "ALTER SEQUENCE " $1 "_seq RESTART WITH " $2 ";"}' | \
psql -h gimly -U alfresco -W alfresco
Enfin il reste une séquence à mettre à jour. Cette dernière est un peu différentes car elle est partagée entre plusieurs tables (voir ce le JIRA Alfresco MNT-7445 pour plus de détails). Afin de trouver la valeur à la quelle on doit la mettre à jour on utilise la commande MySQL suivante:
mysql> SELECT max(AUTO_INCREMENT)
FROM TABLES
WHERE TABLE_SCHEMA='alfresco'
AND TABLE_NAME LIKE 'JBPM%';
On récupère la valeur la plus élevée du résultat et on l’utilise dans la requête PostgreSQL suivante:
ALTER SEQUENCE hibernate_sequence RESTART WITH <VALUE>
- Configuration d’Alfresco:
Dernière étape avant de démarrer Alfresco, il faut mettre à jour la configuration afin d’utiliser Postgres et non MySQL. On réalise ceci dans le fichier alfresco-global.properties (consultez la doc officielle):
db.driver=org.postgresql.Driver
db.url=jdbc:postgresql://localhost:5432/${db.name}
db.name=alfresco
db.username=alfresco
db.password=donttellanybody
Assurez d’avoir les jar nécessaires au driver postgres dans votre installation tomcat, et redémarrer Alfresco.
Notez bien que cette procédure (que j’ai testée avec Alfresco entreprise 3.4.11 suivi une upgrade vers 4.2) n’est pas officiellement supportée. Donc si vous avez contracté du support auprès d’Alfresco, il sera toujours préférable de les contacter avant de vous lancer dans ce type de migration. De même si vous souhaitez faire ce genre de choses sur votre environnement de production, veiller à en tester tous les aspects. Pour ma par je n’ai pas pu tout tester!
Laisser un commentaire