Drupal frissítés - a Drupal.hu tapasztalatai (2)

Az előző rész hiányosságaként tomsolo rámutatott, hogy meg kell különböztetnünk kétféle frissítést is. A könnyebbik esetben biztonsági és/vagy hibajavító frissítést telepítünk (például Drupal 4.6.0-ról valamely későbbi 4.6.x-es kiadásra váltunk). Ez könnyebb a webhely gazdája számára, hiszen adatbázis változtatást szinte biztosan nem kell végrehajtani, csak a kódot kell cserélni, sőt a kiegészítő modulok kompatibilitása is biztosított. Emiatt ez a fajta frissítés mindenképpen javasolt.

Ebben a sorozatban viszont a nagyobb verzió ugrások végrehajtásához szeretnék tippeket adni, mint például a Drupal 4.6.x-ről 4.7.0-ra történő frissítés, vagy esetünkben a Drupal 4.5.x-es sorozatról a legújabb 4.7.0-ra. Itt garantált, hogy a korábban használt modul kódok nem lesznek kompatibilisek, új fordításokat kell telepítenünk és az adatbázis struktúra is szinte biztosan megváltozik.

Gondoljunk az adatbázisra és a fordításokra is

Az előző részben megbizonyosodtunk róla, hogy az új frissítendő kiadáshoz rendelkezésre állnak a számunkra szükséges kiegészítő modulok kódjai. Két dologról azonban még mindenképpen meg kell győződnünk a frissítés megkezdése előtt.

A Drupal 4.7.0 a korábbiaknál is felhasználóbarátabb adatbázis frissítő megoldással érkezik. Régebben a kiegészítő modulokhoz tartozó adatbázis táblák frissítését egyedileg kellett elvégeznünk, a modulonkénti leírások átolvasásával. A 4.7.0-hoz kiadott modulok esetén .install fájlokban leírhatóak a telepítésnél és frissítésnél végrehajtandó utasítások, és minden modulhoz saját adatbázis séma verziót tart nyilván a rendszer, ami alapján a szükséges frissítések kiterjesztésenként külön megállapíthatóak. Ha az általunk kívánt kiegészítő modulok esetében nem volt adatbázis változás, vagy rendelkeznek ilyen frissítést segítő fájllal, akkor szerencsénk van. Előfordulhat, hogy mégis egyedi leírások alapján kell a kiegészítő táblákat frissíteni, hiszen ez a telepítő alrendszer még friss, nem minden modul fejlesztőjének sikerült még áttérni rá.

Nem elhanyagolható szempont magyar (vagy más) nyelvű webhely karbantartásánál, hogy a kívánt modulokhoz elérhető-e már a kívánt fordítás. Ez az alapcsomag esetében semmiképpen nem gond, a kiegészítők már változatosabb mintát mutatnak az elérhető fordítások tekintetében. Ha véletlenül nincs letölthető fordítás a kívánt modulhoz, nem kell elkeseredni. A modul kódjának mappájából elindítva az extractor.php segítségével könnyen generálhatjuk a fordítási sablon fájlokat (.pot), melyekből kiindulva a modul fordítását magunk is elkészíthetjük, egy egyszerű szöveges fájlszerkesztő használatával. Bármilyen nyelvre is fordítunk, csak arra kell feltétlenül figyelnünk, hogy UTF-8 kódolást használva mentsük el a fordítást. Ezután érdemes a közösséggel megosztani a munkát, így erősítve az általunk használt rendszer képességeit, hozzájárulva jövőjének biztosításához. Bővebb információ a magyar fordításról.

A hivatalos verzió: frissítés adatbázis mentéssel

Nem érdemes feltételezni, hogy minden rögtön tökéletesen fog működni, ezért különösen veszélyes egy éles webhelyen frissítést végrehajtani. Könnyen lehet, hogy valami félrecsúszik, és ilyenkor mindenképpen jó, ha van egy biztonsági mentésünk a frissítés megkezdése előtti állapotról, amire könnyen visszaállhatunk. Valójában magán a mentésen, azaz a mentés alapján létrehozott teszt webhelyen érdemes a frissítést elindítani, biztonságos távolságra az éles környezettől.

A Drupal.hu MySQL adatbázist használ, így most ezzel fogunk foglalkozni. Vegyük tehát a kedvenc adatbázis dump előállító programunkat (phpMyAdmin webes felületen vagy mysqldump a parancssorból), és egy .sql állományba mentsük el az adatbázisunk tartalmát. A mysqldump használatával a következőképpen juthatunk eredményre:


mysqldump --user=felhasznalonev --password=jelszo adatbazisneve > dumpfile.sql

Valójában eléggé nagy mentésünk lesz a cache, locales_target, locales_source és hasonló táblák miatt, amik tartalmára valószínű nem lesz szükségünk, a fordításokat úgyis újra kell importálnunk, a gyorstárat pedig a fordítás miatt úgyis űríti majd a rendszer. Ezeket a kivételeket azonban a mysqldump számára nem egyszerű megadni, ezért a magam részéről inkább együttélek a nagy fájl le- és feltöltésével járó nagyobb várakozással.

A következő lépés egy friss üres Drupal 4.7.0 telepítése, mely alá a gyárilag szállított MySQL adatbázis helyett a mentett adatbázisunkat töltsük fel. Ezután az index.php betöltése helyett az update.php oldalt hívjuk be. Itt kaphatunk egy hibaüzenetet, hogy nem vagyunk belépve, és így nem tudjuk elvégezni a frissítést. Ezesetben az update.php tetején található $access_check változót állítsuk FALSE értékre, így nem kell belépnünk. A frissítés után természetesen állítsuk vissza TRUE értékre, vagy töröljük az update.php fájlt teljesen.

Ha minden rendben megy, a frissítést elindíthatjuk, kiválasztva az összes felajánlott frissítési lehetőség közül azokat, amikre szükségünk van. Attól függően, hogy bekapcsolt vagy kikapcsolt JavaScript mellett futtatjuk a kódot, egy kicsit más felület fogad bennünket. Mindenképpen feltűnő a korábbiakhoz képest barátságosabb előrehaladást mutató sáv, mely a végére érve egy összefoglaló oldalra irányít bennünket, ahol áttekinthetjük a frissítés során végrehajtott adatbázis átalakító utasításokat, és az esetleges hibaüzenteket. Ezzel az összes frissítésre felkészített modulunk mögött álló adatbázist sikeresen az új verzióra állítottuk át, meglátogathatjuk az eseménynaplót a rögzített esetleges hibaüzeneteket áttekintendő, vagy rögtön a címlapunkra léphetünk.

A drupal.hu változat: párhuzamos tesztelés

Akik hozzánk hasonlóan saját modulokat is adtak a rendszerhez, esetleg még sminket is szeretnének változtatni, vagy már korán el szeretnék kezdeni a frissítés előkészítését, azok nem számíthatnak azonnal megfelelő eredményre. Könnyen lehet, hogy a teszteléshez használt rendszert folyamatosan a meglévő rendszer működtetése mellett kell előkészíteni. Ezt tettük a Drupal.hu esetében is.

Mivel a folyamatos párhuzamos üzemeltetés nem kényelmes kézi eszközökkel, egy kis segésszkriptet valósítottuk meg, mely veszi a meglévő drupal.hu adatbázist, és az azonos szerveren, de a világ szeme elől elrejtve karbantartott tesztelésre használt virtuális hosztnak megfelelő adatbázisba másolja azt. A PHP-beli megvalósítás lehetővé teszi, hogy speciális módosításokat is végrehajtsunk az adatbázison, mielőtt az update.php-t futtatjuk. Nézzük részleteiben a klónozásra használt szkript kódját:

// Kapcsolat felepitese
$conn = mysql_connect("localhost", "ujuser", "ujjelszo");
mysql_select_db("ujdrupalhu", $conn);
// Ujdrupalhu tablak eldobasa
$tables = mysql_list_tables("ujdrupalhu", $conn);
while ($r = mysql_fetch_row($tables)) {
mysql_query("DROP TABLE ujdrupalhu.$r[0]", $conn);
}
?>

Az első fontos pont, hogy nem a Drupal rendszer adatbázis műveleteit használjuk, hiszen ahhoz be kellene tölteni a Drupal alaprendszert, ami viszont egy aktuális adatbázis sémát feltételez, és éppen ez az, ami még nem áll rendelkezésünkre. Így magunkra vagyunk utalva. Annyit teszünk, hogy az új adatbázishoz csatlakozva eldobjuk annak minden tábláját (egy korábbi klónozás eredményét), és felkészülünk az újabb klónozásra.

// Drupalhu klonozas
$tables = mysql_list_tables("drupalhu", $conn);
while ($r = mysql_fetch_row($tables)) {
$c = mysql_fetch_row(mysql_query("SHOW CREATE TABLE drupalhu.$r[0]", $conn));
mysql_query(preg_replace("!CREATE TABLE `([^`]+)`!", "CREATE TABLE ujdrupalhu.\\1", $c[1]), $conn);
mysql_query("INSERT INTO ujdrupalhu.$r[0] SELECT * FROM drupalhu.$r[0]", $conn);
}
?>

Ezekután nincs mit tenni, mint egyenként venni a drupalhu adatbázis tábláit, a CREATE TABLE utasításukat lemásolni, az ujdrupalhu adatbázisban felhasználva lefutattni, majd az adatokat átmenteni. Ez természetesen azért lehetséges, mert olvasási jogot kapott az ujuser felhasználó a korábbi drupalhu adatbázisra. Ott más jogosultságra nincs szüksége, és nem is szabad adni neki, nehogy a frissítés negatívan érintse a meglévő rendszert.

Mivel elkészült a korábbi adatbázis másolata, akár rögtön neki is állhatunk az update.php futtatásának, mi azonban kihasználva a PHP nyújtotta lehetőségeket, még a fent említett adat eldobásokról is gondoskodunk, elmozgatva a felesleges adatokat, amik csak meghosszabbítanák a frissítést.

// Felesleges dolgok az adatbazisban
mysql_query("DELETE FROM ujdrupalhu.cache", $conn);
mysql_query("DELETE FROM ujdrupalhu.locales_source", $conn);
mysql_query("DELETE FROM ujdrupalhu.locales_target", $conn);
// Korabban hasznalt, de mar nem alkalmazott modulok torlese
mysql_query("DELETE FROM ujdrupalhu.system WHERE name in ('weblink', 'trstatus')", $conn);
// A simplelinks a weblink helyettesitoje
mysql_query("INSERT INTO ujdrupalhu.system (filename, name, type, status)
VALUES ('modules/simplelinks/simplelinks.module', 'simplelinks', 'module', 1)", $conn);
?>

Ugyanitt lehetőségünk van azoknak a módosításoknak a végrehajtására is, amiket a frissítés után a webes felületen amúgyis végrehajtottunk volna. Például az előző részben leírtak szerint új saját fejlesztésű simplelinks.module helyettesíti a korábbi weblink modul funkcionalitását, így a weblink bejegyzését töröljük, a simplelinks bejegyzését viszont hozzáadjuk az adatbázishoz. Ehhez hasonlóan bármilyen előkészítő lépést megtehetünk.

Mindez természetesen nem lenne szükségszerű, ha a folyamatosan alakított és frissített Drupal illetve modul forráskódok miatt nem kellene rendszeresen újra futtatnunk a frissítést. Így viszont a folyamat automatizálása jelentősen könnyítette az életünket. Maga a frissítés természetesen már az update.php betöltésével kényelmesen elvégezhető.

Drupal.hu specialitás: a kódolások visszavágnak

Még egy momentum okozott számunkra fejfájást. A drupal.hu mögött álló adatbázis tábláinak szöveges mezői történelmi okok miatt (eléggé helytelenül) iso-8859-2 kódolásúra vannak állítva a MySQL számára. Ez nem okoz különösebben gondot a napi működésben, ilyen adatbázisban is tud a MySQL UTF-8-as adatokat tárolni. A 4.7.0 frissítése azonban a szöveges mezők típusát kifejezetten UTF-8 beállításúra próbálja állítani. Ez nem is lenne gond, ha a kapcsolat kódolását már a konverzió előtt az első pillanattól nem UTF-8-ra állítaná a rendszer. Így viszont az iso-8859-2 kódolású mezőket átvezetve ezen a kapcsolaton olyan karaktersorozatokat kap a PHP, melyeket a Drupal által előszeretettel használt unserialize() nem tud kibontani (nem annyi karakter van ugyanis a kódolás váltás miatt a karaktersorozatban, mint amit az unserialize() elvárna). Ez nem teszi lehetővé a frissítés lefutását, menetközben végtelen ciklusba kerül (körülbelül 70%-os frissítettségnél).

A probléma megoldása egyszerűbb, mint amilyennek a gond leírása hangzott. Egyszerűen nem alkalmazunk UTF-8 alapú kapcsolatot addig, amíg nem olyan formában állnak rendelkezésre az adatok. Ehhez a database.mysql.inc fájlban a 84-86. sorban a következő módosított változatot használjuk:

if (version_compare(mysql_get_server_info(), '4.1.0', '>=') && !function_exists('update_sql')) {
mysql_query('SET NAMES "utf8"', $connection);
}
?>

Az update_sql csak az update.php által betöltött oldalon létezik, így a frissítés során nem lesz aktív ez a kapcsolat kódolás beállítás, csak később. Ehhez még hozzá kell vennünk egy cache tábla eldobást a frissítési oldalak végén, különben előfordulhat, hogy olyan gyorsítótár állapot marad meg az adatbázisunkban, ami az új kódolásnak nem megfelelő (az unserialize() által használt formátum miatt). Ezért beillesztettük még az alábbi sort a Drupal update.php kódjának végére:

db_query("DELETE FROM {cache}");
?>

Hogy erre a két módosításra szüksége van-e más magyar Drupal webhely működtetőknek, az azon múlik, hogy a frissítés enélkül is sikeresen lefut-e, azaz hogy milyen adatbázis struktúra volt a korábbi adatbázisban. Az mindenesetre fontos, hogy a majdani későbbi frissítések már helyes kódolással fussanak le, tehát az első kis változtatást a későbbiekben már nem szabad a rendszerben hagyni.

Frissíteni könnyű

Akár a hivatalos verziót követjük, akár a klónozásos párhuzamos tesztelést, a megfelelő előkészítő lépések megtétele után a frissítés könnyedén le tud futni. Ha mégis probléma lenne a frissítéssel, akkor a drupal.org hibajelentőjében lehet részletes hibajelentéssel élni, mely javítása esetén egy remélhetőleg még jobban használható frissítési folyamathoz vezet a jövőben.