Zum Inhalt springen
>_marc-oltersdorf.de

MediaWiki-Upgrade: update.php bricht mit „DBReadOnlyError: Database is read-only“ ab

Marc Oltersdorf 3 Min. Lesezeit

Wer ein Wiki vor dem Upgrade mit $wgReadOnly sperrt, sperrt bei aktuellen MediaWiki-Versionen auch update.php aus. Eine Ausnahme für die Kommandozeile hält Besucher draußen und lässt die Wartungsskripte schreiben. Dazu drei Stolperfallen nach dem Upgrade: Login, Interwiki und ein überschriebenes Logo.

$ git log --graph Der Weg zur Lösung

  1. Problem update.php bricht mit DBReadOnlyError ab

    Beim Upgrade auf MediaWiki 1.46 scheiterte update.php sofort mit „Database is read-only“.

  2. Irrweg Schreibschutz vor dem Update gesetzt

    Ich hatte das Wiki wie empfohlen mit $wgReadOnly gesperrt und angenommen, Wartungsskripte seien davon ausgenommen.

  3. Erkenntnis Auch update.php hält sich an $wgReadOnly

    Der Fehler kam beim ersten Schreibzugriff, die Datenbank blieb unverändert.

  4. Lösung Schreibschutz nur fürs Web

    Mit PHP_SAPI === "cli" ? false : "…" dürfen Wartungsskripte schreiben, Besucher sehen das Wiki weiter gesperrt.

  5. Erkenntnis Nacharbeiten: Login, Interwiki, Logo

    Login erst nach Aufheben des Schreibschutzes testen, Interwiki aus LocalSettings entfernen, Logo dauerhaft im Upload-Ordner ablegen.

Beim Upgrade eines MediaWiki auf 1.46 per Shell bin ich so vorgegangen, wie es viele Anleitungen empfehlen: Wiki mit $wgReadOnly sperren, Backup ziehen, neue Version entpacken, Ordner tauschen, update.php ausführen. Der letzte Schritt brach sofort ab:

Going to run database updates for wikidb
Depending on the size of your database this may take a while!
Creating existencelinks table...Wikimedia\Rdbms\DBReadOnlyError from line 683 of /var/www/wiki/includes/libs/Rdbms/Database/Database.php: Database is read-only: Wartung: Upgrade läuft
#0 /var/www/wiki/includes/libs/Rdbms/Database/Database.php(635): Wikimedia\Rdbms\Database->executeQuery()
…
#9 /var/www/wiki/maintenance/update.php(191): MediaWiki\Installer\DatabaseUpdater->doUpdates()

Das Problem

Ich war davon ausgegangen, dass $wgReadOnly nur Bearbeitungen über die Weboberfläche verhindert und Wartungsskripte davon unberührt bleiben. Bei MediaWiki 1.46 stimmt das nicht: Auch update.php hält sich an den Schreibschutz und scheitert beim ersten Schreibzugriff. Ab welcher Version genau das so ist, habe ich nicht geprüft.

Die gute Nachricht: Der Fehler kommt beim allerersten Schreibversuch. Die Datenbank war danach unverändert, ein Zurückspielen des Dumps war nicht nötig.

Die Lösung

Der Schreibschutz soll für Besucher gelten, nicht für die Kommandozeile. PHP verrät über PHP_SAPI, wie ein Skript gestartet wurde. Statt der üblichen Zeile kommt diese in die LocalSettings.php:

$wgReadOnly = "Wartung: Upgrade läuft";
$wgReadOnly = PHP_SAPI === "cli" ? false : "Wartung: Upgrade läuft"; # upgrade-sperre

Der Kommentar am Ende dient als Markierung, damit sich die Zeile später sicher wieder entfernen lässt. Der Ablauf auf der Shell:

cd /var/www/wiki
echo '$wgReadOnly = PHP_SAPI === "cli" ? false : "Wartung: Upgrade läuft"; # upgrade-sperre' >> LocalSettings.php
php -l LocalSettings.php
php maintenance/run.php update --quick
sed -i '/# upgrade-sperre$/d' LocalSettings.php
php maintenance/run.php runJobs

Wer die neue Version in einen eigenen Ordner entpackt und die LocalSettings.php dorthin kopiert, nimmt die Zeile automatisch mit. Entfernt wird sie dann im neuen Ordner.

Warum das funktioniert

Wartungsskripte laufen über die PHP-Kommandozeile, PHP_SAPI ist dort cli. Seitenaufrufe kommen über PHP-FPM oder das Apache-Modul und haben einen anderen Wert. MediaWiki wertet false als „nicht schreibgeschützt“. Die Kommandozeile darf also schreiben, die Weboberfläche bleibt gesperrt. Ich habe die Zeile mit php -l geprüft und auf der Kommandozeile ausgewertet, dort ergab sie false. Danach lief update.php durch.

Stolperfallen

Login testen erst ohne Schreibschutz

Nach dem Upgrade habe ich das Wiki im Browser getestet, solange der Schreibschutz fürs Web noch aktiv war. Die Anmeldung scheiterte mit der Meldung, dass Cookies nicht aktiviert seien. Vermutlich kann MediaWiki die Sitzung nicht speichern, solange die Datenbank für Webzugriffe gesperrt ist. Den Zusammenhang habe ich nicht abschließend geprüft. Ich würde den Schreibschutz deshalb vor dem Login-Test aufheben und erst dann testen.

Interwiki steckt seit 1.44 im Core

Die Extension Interwiki wurde mit MediaWiki 1.44 in den Core übernommen. Der Release-Branch der Extension enthielt bei mir keine extension.json mehr. Die Zeile wfLoadExtension( 'Interwiki' ); muss aus der LocalSettings.php raus. Spezial:Interwiki gibt es weiterhin.

Eigenes Logo unter dem Namen des Platzhalters

Wer sein Logo einfach als resources/assets/change-your-logo.svg gespeichert hat, bekommt nach dem Upgrade wieder den Platzhalter. Die Datei gehört zum Paket und wird ersetzt. Dauerhaft sicher liegt das Logo im Upload-Ordner, den jedes Upgrade übernimmt:

mkdir -p /var/www/wiki/images/logo
cp logo.svg /var/www/wiki/images/logo/logo.svg
$wgLogos = [
    '1x'   => "$wgScriptPath/images/logo/logo.svg",
    'icon' => "$wgScriptPath/images/logo/logo.svg",
];

Eigene Farben gehören aus demselben Grund nicht in die Skin-Dateien, sondern auf die Wiki-Seite MediaWiki:Common.css oder die passende Skin-Seite. Die liegt in der Datenbank und übersteht jedes Upgrade.

Prüfskripte mit grep -q in der Pipe

Wer das Backup per Skript mit set -o pipefail prüft, sollte tar tzf archiv.tar.gz | grep -q LocalSettings.php vermeiden. grep -q beendet sich beim ersten Treffer, tar bekommt beim Weiterschreiben ein SIGPIPE, und die Pipe meldet Code 141. Bei einem großen Archiv sieht ein vollständiges Backup dann wie ein fehlerhaftes aus. Abhilfe: die Inhaltsliste erst in eine Datei schreiben und darin suchen.

Hat dir das geholfen?

RSS abonnieren

$ ls ../ Passt dazu