Patrice Ferlet
Patrice Ferlet
Créateur de ce blog.
Publié le oct. 24, 2008 Temps de lecture: 15 min

Me suivre sur Mastodon

OpenOffice en mode serveur

Il est parfois compliqué de créer des documents dignes de ce nom en PDF à partir de templates… Soit on tente d’utiliser des librairies telles que FPDF, HTPM2PDF pas forcément très classes, soit on cherche à monter une solution plus qualitative. Il existe des solution propriétaires très bien faites (dans le genre de Adobe…) mais dans un monde où le libre prend le dessus, nous pouvons monter des solutions très professionnelles.

Voici donc une solution que j’utilise en production. Elle utilise OpenOffice (v 3) en mode serveur et un script Python pour lancer la génération de document. Bien que le fonctionnement reste relativement simple, l’installation sur un serveur de production est très tortueuse. En effet, un serveur de production ne peut pas se permettre de laisser tourner un serveur X (Xorg, serveur d’affichage) pour des raison de sécurité et de fiabilité. Seulement voilà… OpenOffice a une facheuse **fenêtre de premier démarrage** que nous ne pouvons pas “zapper”. De plus, OpenOffice est avant tout un système graphique et demande donc la possibilité d’utiliser des polices, des rendus, bref il lui faut un serveur X ou quelque chose qui y ressemble.

Même si le second point n’est pas bloquant, le premier l’est ! Heureusement Linux (ou tout autre Unix, Unix/Like) est bourré de configuration qui permettent de faire énormément de manipulations pour s’en sortir. Notemment, nous allons nous régler nos soucis grâce à: -ssh avec forward X11 pour initialiser OpenOffice pour une première utilisation -utiliser Xvfb pour laisser tourner le serveur dans un X virtuel (X = serveur d’affichage)

Le revers de la médaille, c’est qu’il va falloir passer quelques minutes les mains dans le cambouis afin de rendre la plateforme fonctionnelle.

Très important

Dans ce billet, je vous demande de vous connecter en SSH et de quitter les sessions pour vous reconnecter… Il est très important que vous fassiez cela et ne pas utiliser la commande “su - utilisateur”. En fait, ce que je vous présente ici demande une véritable “reconnexion” à SSH dans la plupart des cas, notamment en ce qui concerne le Forward X11 SSH. Si vous tentez de faire “su - office” je vous assure que l’export d’affichage ne va pas macher. Il faut réellement se connecter en SSH avec cet utilisateur directement.

Voilà qui est dit.

Présentation

Je vais donc vous montrer comment procéder sur une CentOS 5.2 pour installer et configurer un Xvfb + OpenOffice 3 et lancer un serveur OpenOffice. Je vous présenterai aussi un exemple de code Python qui pourra créer des fichier PDF depuis un fichier .odt, .doc, .html… bref, faire ce que sait faire openoffice mais cette fois ci depuis une ligne de commande.

Assurez vous que vous pouvez être root sur votre serveur, que vous avez assez d’espace disque (minimum 200Mo). J’estimerai dés à présent que vous avez déjà travaillé sur un serveur Linux, car les commandes peuvent parfois paraitre ésotériques.

Enfin, si vous êtes sur une Debian ou Ubuntu, ou tout autre distribution, je vous remercie de me donner la liste des paquets que je mettrai à jour dans ce ticket.

Prêt ? FEU !

Prérequis

Il y a quelques prérequis à satisfaire, notemment avoir Java, Xvfb, xauth et quelques polices prêtes à l’emploi. On commence par se rendre sur notre serveur distant et on installe les paquets nécéssaires:

$ ssh root@server
$ yum install java xorg-x11-server-Xvfb xauth xorg-x11-fonts-75dpi xorg-x11-font-utils xorg-x11-fonts-base.noarch liberation-fonts

[edit pour Debian et Ubuntu]\\ Pour Debian et Ubuntu, ces paquets semblent être les plus appropriés, à tester

su - 
#ou pour ubuntu
sudo -s
apt-get install xfonts-75dpi xfs ttf-liberation xvfb openjdk-6-jdk openjdk-6-jre 

#sur debian, c'est plus corsé... il faut installer:
#d'abord Java, téléhargez le puis:
$ chmod 755 jre-6u10-linux-i586.bin
$ ./jre-6u10-linux-i586.bin
$ mv /jre1.6.0_10 /opt/java
$ apt-get install libxext6 libsm6  xbase-clients xfonts-base xfonts-75dpi xfs xvfb

#dans tous les cas, relancez xfs (X Front Server)
$ /etc/init.d/xfs restart

Voilà, on passe à OpenOffice…

OpenOffice

Je suis allé sur le site de OpenOffice pour prendre l’adresse que je donne à manger à “wget”, si une version supérieure à la 3.0.0 existe, vous pouvez remplacer le lien dans les lignes qui suivent par la version qui vous intéresse.

Sachez aussi que cela fonctionnera avec une version 2.X.

Donc, toujours sur le serveur distant en ssh connecté en “root”:

$ cd /tmp
#Pour Fedora, Centos, RHEL...
$ wget http://sunsite.rediris.es/mirror/openoffice.org/localized/fr/3.0.0/OOo_3.0.0_LinuxIntel_install_wJRE_fr.tar.gz
$ tar zxvf OOo_3.0.0_LinuxIntel_install_fr_deb.tar.gz
$ cd OOO300_m9_native_packed-1_fr.9358/RPMS/
$ rpm -ivh ./*.rpm

#si vous êtes sur une vraie debian, faites:
$ export JAVA_HOME=/opt/java

#Pour Debian ou ubuntu
$ wget  wget http://mirrors.evolva.ro/openoffice.org/localized/fr/3.0.0/OOo_3.0.0_LinuxIntel_install_fr_deb.tar.gz
$ tar zxvf OOO300_m9_native_packed-1_fr.9358/DEBS/ooobasis3.0-core02_3.0.0-9_i386.deb
$ cd  OOO300_m9_native_packed-1_fr.9358/DEBS/
$ dpkg -i ./*.deb

Cela a pour effet d’installer OpenOffice à la mode “openoffice”… c’est à dire que les RPM (ou .deb pour Debian) sont génériques et installent tout dans /opt. Donc vous allez avoir des répertoire openoffice qui vont apparaitre dans /opt. Normal, ce répertoire est d’ailleurs le plus adéquat pour des installations de ce genre… tout est installé à part et c’est mieux selon moi.

Pour des raisons de sécurité, nous ne lancerons pas OpenOffice avec “root” mais un utilisateur plus restreint. Créons cet utilisateur que nous nommerons “office”:

adduser office
passwd office
#là on vous demande de taper 2 fois le mot de passe

Très bien, il faut maintenant lancer OpenOffice avec cet utilisateur… sauf que si vous testez maintenant, vous allez vous rendre compte que ça ne marchera pas puisque nous n’avons pas de X qui tourne.

Comme je vous l’ai dit, OpenOffice va vous demander de remplir un formulaire… et sans affichage ça va se compliquer.

Et Xvfb n’est pas encore la solution puisque qu’il est virtuel, cela ne nous avancera pas encore puisque l’affichage doit être **réel* pour le moment. La solution est d’utiliser le serveur X que vous avez chez vous…

Et oui, c’est possible! SSH, encore lui, permet de déporter l’affichage sur une autre machine, et comme vous êtes sous Linux, vous allez pouvoir permettre l’utilisation de votre X pour une session SSH. C’est magique :)

Mais là il va falloir configurer deux ou trois choses… En premier lieu le serveur ssh distant.

$ vi /etc/ssh/sshd_config
# trouvez les lignes X11Forwarding et X11DisplayOffset, 
# enlevez les diéses devant si besoin et placez les 
# valeurs "yes" et 10 comme indiqué:
X11Forwarding yes
X11DisplayOffset 10

# enfin, sauvez le fichier, relancez le service sshd...
$ /etc/init.d/sshd reload

# quittez votre session SSH
exit

Pour le serveur on est ok, on passe à votre machine, le client (qui va faire office de serveur X pour l’installation)

Préparation sur le client

Avant de nous reconnecter à notre serveur, il faut que votre poste client (le votre, chez vous) puisse récupérer les forward X, voici comment on procède:

$ su -lc "gedit /etc/ssh/ssh_config"
Host *
   ForwardAgent yes  
   ForwardX11 no
#on sauve, on quitte puis on autorise les connexions avec xhost
xhost +

Maintenant, on peut se connecter via SSH avec l’option “-X” qui demande un forward X11 depuis le serveur ssh distant

Etant donné que je veux configurer OpenOffice pour l’uitilisateur “office”, je me connecte avec cet utilisateur:

$ ssh -X office@server
xmessage "Je teste mon serveur distant"

Vous devriez voir un petit popup apparaitre chez vous avec écris “Je teste mon serveur distant” sur votre bureau. Pressez le bouton “Okay”, c’est bon, le forward fonctionne. Alors lançons notre openoffice depuis le serveur:

Pour information, ce qu’il vient de se passer c’est que le programme xmessage fonctionnait bien sur le serveur distant, mais il a utiliser le serveur X de votre machine pour s’afficher. On dit merci à SSH et on continue:

#pour Debian
$ export JAVA_HOME=/opt/java

#puis, pour tout le monde:
$ /opt/openoffice.org3/program/soffice

Cela va être un peu plus lent, ceci étant dut au temps que l’affichage arrive depuis le serveur distant jusque sur votre poste.

Un assistant apparait, remplissez les champs, cliquez sur “Suivant” ou “Next”. Lorsque vous avez fini, OpenOffice vous présente sa fenêtre principale. Vous pouvez quitter OpenOffice, c’est fini.

Fermez votre session ssh en tapant exit dans le shell.

Revenir à une configuration plus sécurisée

Il faut maintenant revenir à un mode sécurisé. On se reconnecte en root sur le serveur:

$ ssh root@server
$ vi /etc/ssh/sshd_config
# recherchez la ligne X11Forwarding et remettez la valeur "no", 
# commentez aussi X11DisplayOffset 10 en y mettant un dièse en début de ligne:
X11Forwarding no
#X11DisplayOffset 10
#Sauvez, fermez...

$ /etc/init.d/sshd reload
$ exit

Voilà, maintenant que nous avons coupé notre forward X11, nous somme revenu à un mode normal.

Je vous rassure, on n’aura plus à le faire :)

Nous avons donc terminé avec l’installation et l’initialisation de OpenOffice. On passe au service.

Testons Xvfb et OpenOffice

Il faut maintenant que OpenOffice fonctionne dans un serveur d’affichage, mais Xorg n’étant pas la solution la plus viable pour un serveur de production, nous allons utiliser un serveur purement virtuel. Le projet Xorg nous propose donc un serveur Xvfb, ou X virtual frame buffer. Tout programme peut se lancer dans cet affichage, personne ne pourra voir le programme en question visuellement, mais il fonctionne comme si il était vraiment affiché.

Rappelez vous que nous parlons de serveur d’affichage, et comme un service réseau nous pouvons avoir des ports. En fait, sous Linux et Unix en général, nous pouvons avoir plusieurs session X en route. Chaque affichage porte un numéro, c’est ce que nous appellons le port, auquel on se connecte pour afficher un programme. Par défaut, le port est “:0”. Mais pour des raisons de sûreté (sait-on jamais si un jour je veux lancer Xorg…) je vais utiliser “:1”.

On retourne sur le serveur et on lance un serveur Xvfb. On lui spécifie un port d’affichage (à ne pas confondre avec un port réseau), ici ‘:1’

$ ssh root@server
$ Xvfb :1 &

Je met un ‘&’ pour pouvoir reprendre contrôle de la ligne de commande, Xvfb est donc lancé en “tâche de fond”, pour le fermer, il suffira te “tuer” le processus.

Ne pas prendre compte de l’erreur: \\ Starting Xvfb (Virtual X server)error opening security policy file /usr/lib/xserver/SecurityPolicy

Je tenterai de trouver pourquoi nous avons cette erreur, mais cela ne gène pas vraiment le fonctionnement.

Reste à lancer OpenOffice.org sur le Xvfb

Lancement du serveur OpenOffice

Ouvrez une console à coté, connectez vous avec “office” en ssh sur le serveur. Nous allons déporter l’affichage dans “:1” grâce à l’export de variable DISPLAY.

$ ssh office@server
#pour tout le monde
$ export PATH=/opt/openoffice.org3/program:$PATH
$ export DISPLAY=:1
#Debian:
$ export JAVA_HOME=/opt/java

#pour tout le monde
$ soffice.bin -headless -invisible '-accept=socket,host=localhost,port=8123;urp;' &

La dernière commande est lancée en tâche de fond. Je vais vous présenter succinctement les options utilisées: –headless coupe toute interaction utilisateur –invisible, pas la peine de vous préciser ce que cela veut dire –accept prend une série d’options -d’abord socket,host=localhost,port8123 spécifie que nous ouvrons un socket sur “localhost” (boucle locale réseau, donc seuelement pour les connexion depuis ce serveur), port 8123. -urp: UNO request Protocol, on spécifie que le port attendra des paquets spécifiques à UNO (on y viendra après)

Vérifions donc que tout cela a fonctionné:

$ ps ax | grep soffice
#vous devez voir quelques lignes apparaitre contenant "soffice.bin"
$ su -
$ netstat -taupe | grep 8123
# et là, vous devez avoir une réponse qui vous dit que le port 8123 est en écoute, par exemple:
[root@sd-12345 ~]# netstat -taupe | grep 8123
tcp        0      0 sd-12345:8123  *:*  LISTEN   office   44387576  20974/soffice.bin

Voilà, on a bel et bien un serveur OpenOffice qui tourne sur le serveur virtuel Xvfb. OpenOffice attend qu’on lui envoi des commandes sur le port 8123.

Afin de discuter avec lui, nous allons nous pencher sur PyUNO, l’interface python avec le module UNO qui permet de travailler avec OpenOffice.

PyUno

OpenOffice est livré avec un python propre à lui. Je préfère largement utiliser ce python que celui de mon installation puisqu’il ne me pose pas de problème en ce qui concerne les chemins de modules.

Voici donc un script python qui me permet de tester mon service OpenOffice: ` #!/usr/bin/env python

-- coding: utf-8 --

import sys

#importe le module UNO import uno from com.sun.star.beans import PropertyValue

#le port où se connecter port=“8123” #fichier d’entré et de sorite inputfile = uno.systemPathToFileUrl(sys.argv[1]) outputfile = uno.systemPathToFileUrl(sys.argv[2])

Récupération d’un manager de service

context = uno.getComponentContext() resolver = context.ServiceManager.createInstanceWithContext(“com.sun.star.bridge.UnoUrlResolver”, context) ctx = resolver.resolve(“uno:socket,host=localhost,port="+port+";urp;StarOffice.ComponentContext”) smgr = ctx.ServiceManager

Charge le document d’entrée

properties = [] p = PropertyValue() p.Name = “Hidden” p.Value = True properties.append(p) properties = tuple(properties)

desktop = smgr.createInstanceWithContext(“com.sun.star.frame.Desktop”, ctx) doc = desktop.loadComponentFromURL(inputfile, “_blank”, 0, properties)

Création de propriétés de sauvegardes

properties = [] p = PropertyValue()

On autorise l’écrasement de fichier

p.Name = “Overwrite” p.Value = True properties.append(p)

on utilise le filtre PDF

p = PropertyValue() p.Name = “FilterName” p.Value = ‘writer_pdf_Export’ properties.append(p)

#on passe la variable en type ’tuple’ properties = tuple(properties)

#on sauve doc.storeToURL(outputfile, properties) #on relache doc.dispose() `

Donc, voilà comment tester, enregistrez le script ci-dessus sur /home/office/test.py (sur le serveur distant), ouvrez un shell SSH

$ ssh office@server
$ /opt/openoffice.org3/program/python test.py /chemin/complet/du/fichier.odt /chemin/complet/du/fichier.pdf

Oui, je sais, il faut donner un chemin **complet** et non relatif… j’ai pas codé ce script pour qu’il soit fonctionnel dans tous les cas, mais pour tester l’installation. Si tout se passe bien vous allez avoir un PDF bien propre et bien réglé.

On nettoie et on monte un vrai service

Ok, nous avons tout lancer à la main. Reste maintenant à faire un script de type “service”. Je suis sous CentOS (donc un genre de RedHat), ceci ne sera pas exact pour Debian et Ubuntu, je vous laisserai me donner les spécifications si vous le souhaitez.

J’utilise donc le système Red Hat qui demande d’utiliser le script /etc/init.d/functions afin d’utiliser les fonctions “deamon” et “killproc”.

Commencez par vous connecter en root et fermez tous les processus restants de Xvfb et soffice

killall Xvfb
killall soffice.bin

Et maintenant, créez un fichier /etc/init.d/ooffice, placez ce code dedans: ` #!/bin/bash

chkconfig: 345 20 100

description: OpenOffice server listener

. /etc/init.d/functions

PIDFILE="/var/lock/subsys/ooservice" PORT=“8123” USER=“office”

case “$1” in start) if [[ -f $PIDFILE ]]; then echo “A server is already active” exit 1 fi echo -n “Starting Xvfb (Virtual X server)” daemon Xvfb :1 & RETVAL=$? echo if [[ $RETVAL -eq 0 ]]; then
sleep 2 echo -n “Starting OpenOffice Server on port $PORT” daemon “su - $USER -c "export PATH=/opt/openoffice.org3/program/:$PATH; export DISPLAY=:1; soffice -headless -invisible ‘-accept=socket,host=localhost,port=$PORT;urp;’"” & echo else echo -n “Kill all processus… error appears” killproc Xvfb killproc soffice.bin
fi echo [ $RETVAL -eq 0 ] && touch $PIDFILE ;; stop) echo -n “Stopping OpenOffice”
killproc soffice.bin echo echo -n “Stopping Xvfb (Virtual X server)” killproc Xvfb RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f $PIDFILE ;; restart) $0 stop $0 start ;;

echo "Usage: $0 {start|stop|restart}"
exit 1

esac

exit 0 `

En ce qui concerne Debian, je n’ai pas tout sous la main pour coder un bon daemon, mais ceci peut **largement** faire l’affaire. En premier lieu, ouvrez /home/office/.bashrc et placez en fin de fichier:

#Debian, export de JAVA_HOME
export JAVA_HOME=/opt/java

Sur Ubuntu il n’y aura pas de souci normalement… puis ce script fera office de démon: `

#!/bin/bash

chkconfig: 345 20 100

description: OpenOffice server listener

USER=“office” PORT=“8123” PIDFILE="/var/lock/subsys/ooservice"

start() {

if [[ -f $PIDFILE ]]; then
    echo "A server is already active"
    exit 1
fi
echo -n "Starting Xvfb (Virtual X server):"
Xvfb :1 &

sleep 2
echo -n "Starting OpenOffice Server:"
su - $USER -c "export PATH=/opt/openoffice.org3/program/:\$PATH; export DISPLAY=:1; soffice -headless -invisible '-accept=socket,host=localhost,port=$PORT;urp;'"  > /dev/null 2>&1 &
[[ $? -eq 0 ]] && touch $PIDFILE
return 0

}

stop() { echo -n “Stopping OpenOffice”
killall soffice.bin sleep 1 echo echo -n “Stopping Xvfb (Virtual X server)”
killall Xvfb rm -f $PIDFILE echo return 0 } case “$1” in start) start ;; stop) stop ;; restart) stop start ;;

    echo "Usage: $PROG {start|stop|restart}"
    exit 1

esac `

Et voilà, vous le sauvez, et pour lancer le service vous faites:

/etc/init.d/ooffice start

et pour le couper:

/etc/init.d/ooffice stop

Vous pouvez aussi relancer le service pour le rafraichir:

/etc/init.d/ooffice restart

Vous pouvez bien entendu demander un démarrage au lancement du serveur grâce aux options “chkconfig” placées dans l’entête du script. La commande qui activera le daemon est:

chkconfig --add ooffice

Ou pour Ubuntu et Debian:

update-rc.d ooffice defaults 99

Vous remarquerez que j’utilise un “su -c office…” pour lancer la commande “soffice”, cela a pour effet de lancer une commande en tant qu’un utilisateur particulier.

Pour finir

Reste à voir ce que vous en ferez… sachez que le format ODT (Open Document) est en fait un zip. Si vous décompressez le fichier, vous y verrez un fichier “content.xml” dans lequel vous pouvez remplacer du texte, des balises… donc il vous suffit de créer un fichier odt, et de l’utiliser comme patron (template) pour générer des documents.

Vous pourrez donc faire des script PHP, Perl, Bash… qui feront des remplacements et de la génération de PDF à la volée. Le seul “hic” pour le moment c’est que j’utilise Python. “hic” parce que je fais pas mal de service web et que je trouve gênant d’utiliser un appel de commande système depuis PHP vers un script Python.

Il existe un projet qui se nomme PHPuno mais encore en phase alpha et je ne sais même pas si il fonctionne correctement…

Autre point, il est vrai que pour un gros lot de fichier à générer sur un court laps de temps (genre 2-3 documents/secondes), il serait préférable de créer un “pooler” de document. Cela pourra faire l’objet d’un autre billet. Voilà pour ce billet, j’espère que cela vous a aidé. Si vous avez des questions, n’hésitez pas !

[edit 27 oct. 2008]\\ J’ai découvert ce projet de daemon OpenOffice: http://udk.openoffice.org/python/oood/index.html. Ce daemon permet même plusieurs instance de serveur. A vérifier et tester :)

[edit 27 oct. 2008]\\ J’ai beaucoup corrigé le billet pour que cela fonctionne sur Ubuntu et Debian. Il faudra tout de même tester :)

[edit 27 oct. 2008]\\ Correction du script Python. Reste à corriger pour Debian (on a eut des soucis avec Vainvain pour installer sur une Debian en dev… mais c’est passé)

[edit 27 oct. 2008]\\ Correction pour Debian (pas Ubuntu) afin d’avoir un Java qui marche et un bon export de JAVA_HOME avant lancement de soffice. Chez nous ça a fonctionné

comments powered by Disqus