mar, 16/06/2009 - 12:15 | Yoran   Tutoriels Drupal

Mettre à jour Drupal simplement

ark3.png

Lorsque vient le temps de mettre à jour Drupal ou ses modules, c'est un peu la panique. Il faut aller vite car la faille de sécurité est généralement là, mais il ne faut pour autant pas se précipiter sous peine de finir avec un beau plantage. Voici dons mes recettes de cuisine pour mettre Drupal à jour sans risque avec un minimum d'efforts.

Tout ce qui suit est basé sur l'utilisation d'une plate-forme UNIX standard avec les outils par défaut (perl, diff, patch, rsync, etc.). Pour toute autre plate-forme, ces outils sont généralement disponibles à travers le projet autonomes (ex. cygwin pour Windows).

Se tenir informé

Pour commencer, être à jour c'est avant tout être informé. Pour cela un client RSS comme liferea ou Akregator est un outil indispensable sur lequel il faut ajouter le flux http://drupal.org/security/rss.xml.

Le coeur modifié

Dans un monde idéal, la mise à jour de Drupal consiste juste à décompresser la nouvelle archive, et lancer la commande magique :

# On vérifie déjà ce qui change (notez le --dry-run )
gaston$rsync --dry-run -av --progress --delete --exclude .svn --exclude /sites --exclude /files --exclude /tmp drupal_6.666/ chemin/vers/mon_drupal/
bla bla...
bla.
 
# Et lorsque l'on a exhaustivement vérifié que tout est bon, on relance "pour de vrai"
gaston$rsync -av --progress --delete --exclude .svn --exclude /sites --exclude /files --exclude /tmp drupal_6.666/ chemin/vers/mon_drupal/
bla bla...
bla.
synchronisation des sources

Mais il faut être un peu honnête, garder sur un site un tant soit peu évolué avec une version de Drupal pur-jus, sans aucune modification du coeur, est pour le moins chimérique. On a tous, à un moment ou à un autre, besoin d'adapter la gestion des commentaires, d'assouplir le cache de page ou que sais-je encore, en fonction des besoins du client.

Mais comme nous sommes des gens prudents et organisés, toutes ces modifications ont été soigneusement documentée avec nom de l'auteur du patch, explication et ancien code.

/* Gaston: Modification de cette fonctionnalité en faisant bla bla
 * parce que bla bla.
 * if ( $comments ) {
 */

 if ( $comments && $condition_magique ) {
 // Gaston: Fin du patch
documentation d'un patch

Les plus valeureux pourront garder dans un dossier spécial tous les patchs isolés en mettant une modification par fichier, mais là cela devient presque excessif.

Toujours est-il qu'à se stade, synchroniser les sources à la mode "Monde idéal" n'est pas une option. C'est ici qu'intervient la technique de génération de patch.

Génération d'un patch de mise à jour

Le principe est en soit très simple. Il s'agit de créer un fichier .patch qui contiendra toutes les différences entre la version courante de officielle Drupal et la version cible. Attention, il ne s'agit pas de faire un patch entre les sources de votre site et ceux de la nouvelle version mais bien de récupérer les sources officiels sur drupal.org correspondant à la version qui est actuellement sur votre site.

De manière générale cette technique peut être aussi utilisée sur un coeur non modifié, car le patch présente l'immense avantage de servir de mémoire. Vous pouvez ainsi sauvegarder chacun des patchs appliqués, les étudier pour comprendre ce qui a changé (très instructif pour les mise à jour de sécurité) et aussi pouvoir revenir en arrière car un patch peut être appliqué dans les deux sens.

Prenons un exemple. Vous êtes actuellement sur Drupal 6.8 (c'est très mal !!) que vous avez copieusement modifiée et vous allez faire évoluer vers la version 6.12. Vous allez donc récupérer la version 6.12 ET 6.8 sur drupal.org et faire votre patch avec ces deux versions. Ensuite ce patch va être appliqué à votre version 6.8 modifiée pour la mettre à jour vers une 6.12 elle aussi modifiée. Si vous avez de la chance, les mises à jour ne porteront pas sur du code que vous avez modifié, et l'application du patch se fera sans encombre, dans le cas contraire, il faudra gérer chaque confit à la main, mais nous verrons cela plus tard.

Pour l'heure commençons par créer notre patch en utilisant la commande diff :

gaston$cd ~
gaston$mkdir patchs
gaston$cd patchs
 
# récupération de la version actuelle non modifiée et décompression
gaston$wget http://ftp.drupal.org/files/projects/drupal-6.8.tar.gz
gaston$tar -zxvf drupal-6.8.tar.gz
drupal-6.8/
drupal-6.8/includes/
drupal-6.8/includes/actions.inc
...
 
# récupération de la nouvelle version
gaston$wget http://ftp.drupal.org/files/projects/drupal-6.12.tar.gz
gaston$tar -zxvf drupal-6.12.tar.gz
drupal-6.12/
drupal-6.12/includes/
drupal-6.12/includes/actions.inc
...
 
# Création d'un patch entre la 6.8 et la 6.12
diff -Naur drupal-6.8/ drupal-6.12/ > drupal-6.8-6.12.patch

Le patch est maintenant créé, il ne reste plus qu'à l'appliquer sur le code.

gaston$cd /chemin/vers/drupal
 
# D'abord on vérifie que tout passe bien avec l'option --dry-run
gaston$patch --dry-run -p1 < ~/patchs/drupal-6.8-6.12.patch
 
# Si l'on a AUCUN "FAILLED", on peut appliquer le patch "pour de vrai"
gaston$patch -p1 < ~/patchs/drupal-6.8-6.12.patch
application du patch

Gestion des conflits

Si vous avez obtenu des "FAILLED" lors de l'application du patch en mode "dry-run", vos modifications du coeur sont donc en confit avec les mises à jour.

Mon approche approche dans ce cas consiste à :
  1. Commencer par sauvegarder le fichier incriminé dans un coin.
  2. Avec un outil de comparaison de fichier comme meld, comparer la version "canonique" du fichier qui se trouve dans le dossier ~/tmp/drupal-6.8/chemin/vers/monfichier.php avec le fichier modifié qui pose problème.
  3. Si la modification n'est sans intérêt comme de simples retours chariots ou un mauvais formatage, il faut noter dans un coin la modification
  4. Lorsque la modification a été notée, écraser le fichier avec la version originale.
  5. Appliquer à nouveau le patch en mode dry-run et recommencer à l'étape (1) si ça coince autre part.
  6. Lorsque tout passe, appliquer le patch sans dry-run
  7. Enfin, ré-écrire toutes modifications qui ont été notées.

Généralement cette dernière étape est un bon moment pour se demander s'il est intelligent de faire cette modification à cet endroit, ce qui finir 9 fois sur 10 par le constat d'une grosse flemme un vendredi soir à 19h alors que la même modification faite à 8h un lundi matin aurait donné lieu à la création d'un module....

Mise à jour de la base

Voilà, si tout c'est bien passé, il ne reste plus qu'à mettre à jour la base de données (update.php), tester exhaustivement, puis synchroniser avec la production.

Mise à jour des modules

La mise à jour des modules peut passer par la même procédure de génération de patch, avec les mêmes bénéfices que pour le coeur, que ces modules aient été modifiés ou pas. Cependant, autant mettre à jour le coeur n'arrive pas, et heureusement, tous les quatre matins, il n'en est pas de même des modules. Plus il y en a, plus les mises à jours sont régulières.

Commentaires

pounard, le jeu, 27/08/2009 - 16:13

Et si on ne faisait pas de modifications dans le coeur, ça serait surement plus simple de mettre à jour?:D

Trois commandes Drush, et c'est fini!

Enfin je dis ça, je dis rien. Cet article est assez intéressant, mais si je peux donner un conseil à tout le monde: ne patchez jamais le coeur ou un module contrib (dans le pire des cas pour un module, forkez le).

Ceci pour plusieurs raisons:

  1. ça rend vos mises à jour impossibles à faire ..
  2.  .. impossible à automatiser et ..
  3.  .. c'est déguelasse.
  4. (optionnellement) on peut toujours détourner beaucoup de features à l'aide d'un module qui hook au bon endroit, ou directement en attaquant le thème.
Yoran, le dim, 30/08/2009 - 18:45

Tes régles sont justes mais jusqu'à quelle envergure de projet sont-elles réalistes ?

D'expèrence il est difficile voir imposible de maintenir un coeur intègre sur un trés gros projet. Ne serait-ce que parce que tu as toujours besoin, tôt ou tard, d'appliquer un patch qui n'est pas encore intégré en standard.Ou alors lorsque tu dois modifier certains aspects bas niveaux (exemple perso, mettre en cache les utilisateurs) .

En bref, sans pour autant être dégeulasse (il y a des manières popre de faire des patchs), ce type de manipulation est nécessaire même si ton conseil est le bon, et que dans 80% des cas il est possible de passer par un module.

jef (non vérifié), le mer, 20/01/2010 - 14:15

bjr,

Ma petite contribution à 1 euro ... 6 mois après.

Plutôt que de gérer des patches 1 par 1, il me paraît plus simple d'utiliser un outil de gestion de version.

(GV = gestionnaire de version - CVS ou autre)

  1. Référencer la 1ère version Drupal dans le GV.
  2. On apporte des modif au cours du temps.
  3. Avant d'appliquer 1 nouvelle version : commiter toutes les modifs réalisées.
  4. Descendre la nouvelle version de Drupal dans une nouvelle branche.
  5. Merger les 2 branches.

On peut bien sûr commiter plus souvent, voir partir sur des branches test, dev, ... Le GV maintient un historique. On peut travailler à plusieurs ... Bref tous les avantages d'un GV.

Sinon, merci pour vos articles sur le développement de module qui dégrossissent bien le sujet.

Yoran, le sam, 25/09/2010 - 06:32

Bon alors j'ai fait quelques test et c'est pas si simple avec le GV. En effet si tu as ton drupal sur le master et que tu le modifies, que tu crées une branche pour la nouvelle version de drupal et que tu la merge sur le master, tu va perdre toutes les modifications faites dans le core de Drupal (le fait que cela tue ou pas des chatons n'est pas le débat hein, c'est juste une réalité dans 90% des projets que l'on reprend :-). Idem pour la mise à jour de module (beaucoup plus modifiés que le core généralement).

A la limite se serait l'inverse qu'il faudrait faire, à savoir merger le master sur la nouvelle branche, mais là le problème c'est que cela implique que le projet que tu récupères ait toujours été sur le GV, ce qui là aussi est rarement le cas.

PS: Réponse 8 mois plus tard tout de même, je te grille grave :-)

jef (non vérifié), le lun, 27/09/2010 - 14:34

bonjour,

Effectivement très surpris d'une réponse après 8 mois!

L'idée du GV est la même que la tienne avec les patches : pouvoir appliquer sur la version n+1 des modifs effectuées sur la version n.
C'est quand-même bien le domaine de prédilection d'un GV.
Avec 2 branches, ça doit le faire:
> B1: version n -> version n + modifs persos
> B2: version n+1

On merge B1 dans B2. Le GV sait faire tant que et n+1> ne sont pas sur les mêmes lignes - sinon, il nous demande de trancher.

Sur la mise en oeuvre réelle, ça va dépendre des GV.
Pour CVS, tu peux lire:
http://ximbiot.com/cvs/manual/cvs-1.11.23/cvs_13.html#SEC103

jef (non vérifié), le lun, 27/09/2010 - 14:37

correction:
On merge B1 dans B2. Le GV sait faire tant que modifs perso et modifs n -> n+1 ne sont pas sur les mêmes lignes - sinon, il nous demande de trancher.

Yoran, le lun, 27/09/2010 - 17:54

Oui, encore désolé pour la réponse tardive, j'ai un peu de mal en ce moment.

Ok, je vois le principe mais finalement quelle est la valeur ajouté par rapport à un patch facilement automatisable ?

jef (non vérifié), le sam, 04/12/2010 - 16:38

bonjour,

Je viens d'appliquer la solution d'un gestionnaire de version sur mon projet.
Effectivement, la solution du patch telle que tu la décris marche bien. Mais, il me semble quand-même qu'un GV va complètement formaliser la démarche et apporter d'autres avantages:

- historique des modifications apportées
- automatisation du merge
- gestion des conflits
- on peut plus facilement créer des sous-branches qui permettront de tester certaines modifications ou des sous-branches propres à chaque client
- gestion des renommages et des suppressions
- sauvegardes facilitées
- ...

Dans mon cas, j'ai utilisé bazaar (GV décentralisé = on ne s'emmerde pas à gérer un serveur).
Ma démarche a été la suivante (vocabulaire Bazaar, les notions peuvent être différentes d'un GV à l'autre):

1. Création branche std (standard) - J'y ai mis drupal 6.16 + modules en version standard (en gros 05.2010 = correspondant à l'état de mon projet).

2. Création branche jef (contiendra modifs perso) -> créée par branchement sur std à la dernière révision (voir 1. = contenant drupal + modules standards). A ce stade les 2 branches sont identiques.

3. Evolution de la branche jef avec mes propres modifs. Possibilité de faire des commits à chaque série de modif pour mieux isoler les modifications.

4. Mise à jour branche std avec drupal 6.19.

5. Merge std > jef. Résolution conflits éventuels (indiqués par bazaar). La branche jef est désormais en drupal 6.19 modifiée.

6. Mise à jour branche std avec modules à jour 12.2010.

7. Merge std > jef. Résolution conflits éventuels. La branche jef est désormais en drupal 6.19 + modules 12.2010 avec modifs perso.

Par la suite, pour toute nouvelle version Drupal ou modules, on met d'abord à jour std puis on merge = une commande bazaar.
Note: 4-6 et 5-7 auraient pu être regroupés.

(Dommage, pas de possibilité de poster le "log bazaar" qui aurait montré graphiquement comment les 2 branches évoluent).

Si on a plusieurs projets, on peut imaginer d'autres sous branches:
- Branche std = drupal+modules std
- Branche gen = modifications tous projets - branchement de std - que l'on met à jour par merge depuis std
- Branche pr1 = modifications projet1 - branchement de gen - que l'on met à jour par merge depuis gen
- ...

De mémoire, et en gros, les commandes Bazaar sont les suivantes:
1. Dans std : bzr init - récup fichiers - bzr add - bzr commit
2. Dans jef : bzr branch
3. Dans jef : modifs perso - bzr commit (n fois)
4. Dans std : récup nouvelle version - bzr add - bzr commit
5. Dans jef : bzr merge - (bzr resolve) si conflits - (bzr add) si nouveaux fichiers dans std - bzr commit

Il est préférable d'adopter la démarche en amont, à la création du projet. Le plus dur a été de retrouver les modules d'origine. J'ai écrit un petit outil qui recherche dans les diverses versions des modules que j'utilise (archives brutes .tar.gz) ceux qui ont le datestamp qui correspond (écrit en Python - je peux le transmettre à ceux qui me le demandent).
Mais, avec la solution du patch, le problème est le même: il faut pouvoir mettre en parallèle la version standard et la version modifiée.

Effectivement, il faut faire l'effort de se mettre à Bazaar (ou Git), mais, je pense que le temps passé (qui reste raisonnable) sera rentabilisé rapidement. Peux-t-on développer sérieusement sans Gestionnaire de version ?
Par exemple, avec un bzr push sur chacune de mes 2 branches vers un répertoire dans ma dropbox, j'assure la sauvegarde de tout l'historique de mon projet.

Yoran, le sam, 18/12/2010 - 10:01

Déjà une point d'angoisse lorsque je lis "push sur chacune de mes 2 branches vers un répertoire dans ma dropbox". Je ne sais pas sur quel type de projet vous travaillez, mais moi je n'aurais absolument pas confiance en un système externe pour ce type de données qui sont par nature confidentielles. Ce qui est certain c'est que j'aurais des clients qui gueuleraient, et à juste titre :)

Globalement l'approche par gestionnaire de version est bonne, mais je ne peux m'empêcher de la trouver trop lourde. En effet, je ne sais pas pour vous, mais lorsque j'ai un drupal 6.20 qui pointe le bout de son nez, j'ai du coup une bonne douzaine de sites à mettre à jour dans la foulée et ce le plus rapidement possible. L'avantage pour moi de l'approche par patch est la capitalisation du dit patch. Je génère un patch, et je l'applique sereinement à chacun des sites dont j'ai la charge. Au final, tout est de toute façon sauvé dans un gestionnaire de version (git en l'occurrence) car c'est ce que j'utilise de manière systématique pour mes déploiements. Avec l'approche "patch", je peux (je l'ai fait avant hier), upgrader ma douzaine de site en grosso-modo 1h. C'est pour moi le point fort de cette approche.

Dab (non vérifié), le dim, 24/01/2010 - 10:47

... Il faut aller vite car la faille de sécurité est généralement là ...

hmmm ... et pas qu'une : http://osvdb.org/search?search[vuln_title]=Drupal&search[text_type]=titles

Yoran, le sam, 18/12/2010 - 10:02

Oups, désolé Dab, j'avais pas vu ton commentaire :) Ben tu sais, les projets collaboratifs de cette taille avec ce nombre d'intervenant sans failles, j'en connais peu. En plus il faut bien faire la part entre les failles de Drupal et celles des modules contribution.

Publier un nouveau commentaire

Le contenu de ce champ sera maintenu privé et ne sera pas affiché publiquement.
  • Les adresses de pages web et de courriels sont transformées en liens automatiquement.
  • Les lignes et les paragraphes vont à la ligne automatiquement.
CAPTCHA
Cette question est là pour déterminer si vous êtes humain ou pas...