Upgrade OpenLDAP-Server unter Opensuse auf Leap 42.2 – Fehler – OLC-Konfiguration für Datenbank Backends

Heute bin ich endlich eine Aufgabe angegangen, dass ich schon seit einem Jahr vor mir her schiebe: Ich habe einen LDAP-Server, der noch unter Opensuse 13.1 lief auf Opensuse Leap 42.2 umgestellt.

Die Umstellung habe ich schrittweise abgewickelt : OS 13.1 => OS 13.2 => Leap 42.1 => Leap 42.2. Beschreibungen eines generellen Upgrade-Vorgehensmodell auf Basis von “zypper” für Opensuse finden sich hier:

https://www.unixmen.com/upgrade-opensuse-13-2-opensuse-13-1/
https://www.unixmen.com/how-to-upgrade-to-opensuse-42-1-from-opensuse-13-2/
http://www.2daygeek.com/how-to-upgrade-from-opensuse-leap-42-1-to-opensuse-leap-42-2/2/

Die Paket-Updates liefen (bis auf bekannte Kleinigkeiten) eigentlich ganz gut ab; jede neue erzielte Opensuse-Version konnte erfolgreich gebootet werden. Auch praktisch alle Services liefen – mit Ausnahme eines bekannten Apache-Problems, das nach den Updates ein Eingreifen in bestimmte Konfigurationseinstellungen erfordert. Und eben auch bis auf den LDAP-Service; nach dem letzten Update musste ich schnell zur Kenntnis nehmen, dass es da ein gravierendes Problem gab.

Nach Upgrade zu Leap 42.2 war kein Login mehr auf anderen Servern möglich

Nach dem Übergang von Leap 42.1 zu Leap 42.2 konnte ich mich mit definierten UIDs (außer root) nicht mehr auf Server-Systemen in unserem LAN einloggen. Praktisch alle unsere Server beziehen Authentifizierungsinformationen eben vom zwischenzeitlich upgegradeten OpenLDAP-Server.

Die Authentifizierung läuft dabei über eine Kombination aus SSSD-Services und OpenLDAP (unter TLS). Zunächst dachte ich deshalb, dass ggf. der SSSD-Dämon auf dem OpenLDAP Server nicht laufen würde. Der erfreute sich aber selbst nach den drei Updates bester Gesundheit:

serv:~ # rcsssd status
● sssd.service - System Security Services Daemon
   Loaded: loaded (/usr/lib/systemd/system/sssd.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2017-06-01 15:21:30 CEST; 1h 9min ago
  Process: 1249 ExecStart=/usr/sbin/sssd -D -f (code=exited, status=0/SUCCESS)
 Main PID: 1294 (sssd)
    Tasks: 4 (limit: 512)
   CGroup: /system.slice/sssd.service
           ├─1294 /usr/sbin/sssd -D -f
           ├─1297 /usr/lib/sssd/sssd_be --domain default --uid 0 --gid 0 --debug-to-files
           ├─1298 /usr/lib/sssd/sssd_nss --uid 0 --gid 0 --debug-to-files
           └─1299 /usr/lib/sssd/sssd_pam --uid 0 --gid 0 --debug-to-files

Jun 01 15:21:27 serv systemd[1]: Starting System Security Services Daemon...
Jun 01 15:21:29 serv sssd[1294]: Starting up
Jun 01 15:21:29 serv sssd[be[1297]: Starting up
Jun 01 15:21:29 serv sssd[1299]: Starting up
Jun 01 15:21:29 serv sssd[1298]: Starting up
Jun 01 15:21:30 serv systemd[1]: Started System Security Services Daemon.

Vom OpenLDAP-Service ließ sich das dagegen nicht behaupten; so zeigte ein Blick in das systemd Journal mittels
“journalctl -xe” :

Jun 01 15:48:17 serv systemd[1]: Starting OpenLDAP Server Daemon...
-- Subject: Unit slapd.service has begun start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit slapd.service has begun starting up.
Jun 01 15:48:17 serv slapd[15835]: @(#) $OpenLDAP: slapd 2.4.44 $
                                          opensuse-buildservice@opensuse.org
Jun 01 15:48:17 serv slapd[15835]: UNKNOWN attributeDescription "OLCDBCACHESIZE" inserted.
Jun 01 15:48:17 serv slapd[15835]: UNKNOWN attributeDescription "OLCDBCHECKPOINT" inserted.
Jun 01 15:48:17 serv slapd[15835]
: UNKNOWN attributeDescription "OLCDBCONFIG" inserted.
Jun 01 15:48:17 serv slapd[15835]: UNKNOWN attributeDescription "OLCDBIDLCACHESIZE" inserted.
Jun 01 15:48:17 serv slapd[15835]: UNKNOWN attributeDescription "OLCDBINDEX" inserted.
Jun 01 15:48:17 serv slapd[15835]: config error processing olcDatabase={1}hdb,cn=config:
Jun 01 15:48:17 serv slapd[15835]: DIGEST-MD5 common mech free
Jun 01 15:48:17 serv slapd[15835]: slapd stopped.
Jun 01 15:48:17 serv slapd[15835]: connections_destroy: nothing to destroy.
Jun 01 15:48:17 serv start[15835]: Starting ldap-server
Jun 01 15:48:17 serv systemd[1]: slapd.service: Control process exited, code=exited status=1
Jun 01 15:48:17 serv systemd[1]: Failed to start OpenLDAP Server Daemon.
-- Subject: Unit slapd.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit slapd.service has failed.
-- 
-- The result is failed.
Jun 01 15:48:17 serv systemd[1]: slapd.service: Unit entered failed state.
Jun 01 15:48:17 serv systemd[1]: slapd.service: Failed with result 'exit-code'.

Auch ein manueller Start von OpenLDAP mittels

serv:/etc/openldap/slapd.d # /usr/sbin/slapd -u ldap -h ldap://127.0.0.1:389/ -d 256

lieferte die gleichen Fehlermeldungen. Der Grund für die fehlgeschlagenen Logins lag also schlicht darin, dass ausgerechnet der OpenLDAP-Service, über den in unserem LAN User und Gruppen verwaltet werden, nach den Upgrades – genauer: nach dem letzten Upgrade – nicht mehr lief.

Eigenschaften der LDAP “Datenbank Backends” wurden offenbar nicht erkannt

Die Fehlermeldungen deuteten an, dass Eigenschaften des eingesetzten Datenbank-Backends (in meinem Fall hdb) dem System nicht bekannt waren. Daraus ergibt sich die Frage: Weiß die neue OpenLDAP-Installation unter Laep 42.2 überhaupt irgendetwas von ihren Backends?

Wenn man sich ein wenig mit LDAP beschäftigt hat, hat man sicher mitbekommen, dass die Datenbank-Backends in neueren OpenLDAP-Versionen (wie andere LDAP-Komponenten auch) über Module geladen und konfiguriert werden können. In früheren Versionen haben dagegen Build-Optionen bei der Erzeugung der LDAP-Programme dafür gesorgt, dass diverse Backends von Haus verfügbar waren. Einträge in der “slapd.conf” dienten dann der Auswahl der konkret heranzuziehenden Datenbank-Variante.

Man kann Backends aber eben auch dynamisch nachladen. Typischerweise sollte das in der Grundkonfiguration von OpenLDAP geschehen; was wenn das aber unter Leap 42.2 nicht der Fall ist?

Mit ein wenig Recherche im Internet findet man genügend Hinweise, wie man Datenbank-Backend-Module lädt und dass das tatsächlich in etlichen Installationen der Fall ist: Siehe etwa

http://vaab.blog.kal.fr/2010/03/06/how-to-add-a-schema-in-openldap-24/
(siehe dort den Abschnitt (“How to add a database?”)).

https://www.digitalocean.com/community/tutorials/how-to-configure-openldap-and-perform-administrative-ldap-tasks
http://nodedirector.bigsister.ch/refdoc/group__ref__cfg–director__slapd__conf.html
https://github.com/yast/yast-auth-server/blob/master/package/yast2-auth-server.changes
https://cat.pdx.edu/~nibz/openldap/openldap-server.html
und
http://www.openldap.org/doc/admin24/backends.html
http://www.openldap.org/doc/admin24/
slapdconf2.html

Im letzteren Artikel siehe insbesondere Absatz 5.2.2.

Die genannten Artikel deuten an, dass man die Direktive “olcModuleLoad” in der sogenannten OLC-Grundkonfiguration des LDAP-Servers einsetzen soll.

Dass in meiner aktuellen LDAP-Konfiguration tatsächlich Module geladen werden, zeigte folgender Befehl:

  
serv:/etc/openldap/slapd.d # grep -r ModuleLoad .
./cn=config/cn=module{0}.ldif:olcModuleLoad: {0}back_monitor.la

Leider handelt es sich hier aber nicht um ein Datenbank-Backend-Modul! Die nächste Frage war also: Welche Datenbank-Module werden denn überhaupt benutzt?

  
serv:/etc/openldap/slapd.d/cn=config # grep -r olcDatabase .
./olcDatabase={2}monitor.ldif:dn: olcDatabase={2}Monitor
./olcDatabase={2}monitor.ldif:objectClass: olcDatabaseConfig
./olcDatabase={2}monitor.ldif:olcDatabase: {2}Monitor
./olcDatabase={-1}frontend.ldif:dn: olcDatabase={-1}frontend
./olcDatabase={-1}frontend.ldif:objectClass: olcDatabaseConfig
./olcDatabase={-1}frontend.ldif:olcDatabase: {-1}frontend
./olcDatabase={-1}frontend.ldif:structuralObjectClass: olcDatabaseConfig
./olcDatabase={0}config.ldif:dn: olcDatabase={0}config
./olcDatabase={0}config.ldif:objectClass: olcDatabaseConfig
./olcDatabase={0}config.ldif:olcDatabase: {0}config
./olcDatabase={0}config.ldif:structuralObjectClass: olcDatabaseConfig
./olcDatabase={1}hdb.ldif:dn: olcDatabase={1}hdb
./olcDatabase={1}hdb.ldif:objectClass: olcDatabaseConfig
./olcDatabase={1}hdb.ldif:olcDatabase: {1}hdb

Aha, ich hatte die LDAP-Datenbanken bei der ursprünglichen Servereinrichtung unter OS 13.1 offenbar als “hdb”-Banken aufgesetzt. Es lag daher nahe, mal versuchsweise das entsprechende Backend-Modul zu laden.

Ergänzungen in slapd.conf sind nicht hinreichend, wenn zur Konfiguration OLC [cn=config] benutzt wird

Dummerweise bin ich bei den Recherchen dann aber auch über folgenden Ratschlag gestolpert:

https://forums.opensuse.org/showthread.php/522385-SlapD-will-nach-Update-von-42-1-nicht-mehr?p=2817944#post2817944

Dem bin ich dann naiverweise gefolgt – und habe zunächst lediglich die “slapd.conf” so ergänzt, dass alle Backends geladen werden:

# Load backend modules such as database engines
modulepath /usr/lib64/openldap
moduleload back_mdb.la
moduleload back_hdb.la
moduleload back_bdb.la

Das reichte in meinem Fall natürlich aber nicht ! Warum? Ich hatte die LDAP-Konfiguration beim Aufsetzen des LDAP-Servers unter Opensuse 13.1 mittels OLC, also über Einträge unter “cn=config“, vorgenommen! (Für weniger LDAP-Kundige: Die Konfigurationseinträge unter OLC sind ganz im Stil von LDAP-Datenbank-Records gehalten.)

Unter Opensuse wird die Verwendung der sog. Online-[OLC]-Konfiguration des OpenLDAP-Servers in der Datei “/etc/sysconfig/openldap” über die Option

OPENLDAP_CONFIG_BACKEND= “files|ldap”

festgelegt. In meinem Fall:

OPENLDAP_CONFIG_BACKEND=”ldap”

Das steuert dann den Aufruf des LDAP-Services und den Start des zugehörigen Programms. Letzteres wird dann die Konfigurationseinstellungen unter dem Verzeichnis “/etc/openldap/slapd.d/cn=config” auslesen und zur Anwendung bringen.

Die OLC-Konfiguration des OpenLDAP-Servers kann selbst über LDIF-Dateien oder LDAP-CLI-Kommandos (“ldapadd”, “ldapmodify”) angepasst werden. Damit werden dann die Einträge unter “cn=config” passend modifiziert.

Die notwendige initiale Datenbank-Konfiguration beim Starten des LDAP-Servers erfolgt unter dem Verzeichnis “cn=config” übrigens über folgende LDIF-Datei:

/etc/
openldap/slapd.d/cn=config/olcDatabase\=\{0\}config.ldif

Eine andere Stelle, die grundsätzlich auch für das Laden von Modulen mit Hilfe von “olcLoadModule”-Statements in Frage käme, wäre die grundlegende Konfigurationsdatei für Module:

/etc/openldap/slapd.d/cn=config/cn=module{0}.ldif

Sie hat in meinem Fall den Inhalt:

# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
# CRC32 5b49ffc3
dn: cn=module{0}
objectClass: olcModuleList
cn: module
cn: module{0}
structuralObjectClass: olcModuleList
entryUUID: 49b0aac8-614a-1032-8c55-83b54eef05ad
creatorsName: cn=config
createTimestamp: 20130604100720Z
olcModuleLoad: {0}back_monitor.la
entryCSN: 20130604100720.232512Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20130604100720Z

Ein möglicher Weg zur Ergänzung von Statements, mit denen man alle üblichen Datenbank-Module laden würde, sähe hierfür in etwa so aus:

serv:/etc/openldap/slapd.d # ldapadd -Y EXTERNAL -H ldapi:///
dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/lib64/openldap
olcModuleLoad: back_bdb.la
olcModuleLoad: back_hdb.la
olcModuleLoad: back_mdb.la          

Würde das im vorliegenden Fehlerfall funktionieren? Natürlich nicht – der OpenLDAP-Server läuft ja überhaupt nicht und ein “ldapadd”-Befehl könnte deshalb gar nicht umgesetzt werden!

Direktes Editieren der Konfiguration?

Manche mutige Zeitgenossen wagen es bei kleineren Änderungen (und nach einem vorherigen Sicherheits-Backup der LDAP-Konfiguration), die Einträge in den LDIF-Dateien unter dem Verzeichnis “/etc/openldap/slapd.d/cn=config” auch direkt über Editor-Befehle zu modifizieren. An dieser Stelle muss allerdings gesagt werden, dass die offiziellen OpenLDAP Aministrationshandbücher davon streng abraten. Na ja …

In meinem Fall war eigentlich nur eine Ergänzung erforderlich (s.o.). Ich verhielt mich also mutig; nach einem

serv:/etc/openldap/slapd.d/cn=config # vi olcDatabase\=\{0\}config.ldif 

habe ich die folgende Zeile in der genannten Datei hinzugefügt:

olcModuleLoad: {0}back_hdb

Insgesamt sieht die entsprechende Konfigurationsdatei “olcDatabase\=\{0\}config.ldif” nun so aus:

# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
# CRC32 a4b13d6e
dn: olcDatabase={0}config
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcRootDN: cn=config
structuralObjectClass: olcDatabaseConfig
entryUUID: 14a9819c-624a-1032-8687-49710846e729
creatorsName: cn=config
createTimestamp: 20130604100551Z
entryCSN: 20130604100551.266001Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20130604100551Z
olcModuleLoad: {0}back_hdb

Man sieht nebenbei: Mein OpenLDAP-Server ist schon was älter. Nach der obigen Modifikation lief und läuft er jedoch auch unter Leap 42.2 wieder und verrichtet nun erneut seinen wichtigen Dienst im Netz:

serv:/etc/openldap/slapd.d/cn=config # systemctl start slapd.service 
serv:/etc/openldap/slapd.d/cn=config # systemctl status slapd.service 
● slapd.service - OpenLDAP Server Daemon
   Loaded: loaded (/usr/lib/systemd/system/slapd.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2017-06-01 16:32:38 CEST; 2h 28min ago
  Process: 2632 ExecStart=/usr/lib/openldap/start (code=exited, status=0/SUCCESS)
 Main PID: 2735 (slapd)
    Tasks: 5 (limit: 512)
   CGroup: /system.slice/slapd.service
           └─2735 /usr/sbin/slapd -h ldap:/// ldaps:/// ldapi:/// -F /etc/openldap/slapd.d -u ldap -g ldap -o slp=off

Jun 01 19:00:25 serv slapd[2735]: conn=1304 op=37 SEARCH RESULT tag=101 err=0 nentries=0 text=
Jun 01 19:00:49 serv slapd[2735]: conn=1325 op=6 SRCH base="dc=superduper,dc=de" scope=2 deref=0 filter="(&(
objectClass=posixAccount)(uid=*)(uidNumber=*)(gidNumber=*))"
Jun 01 19:00:49 serv slapd[2735]: conn=1325 op=6 SRCH attr=objectClass uid userPassword uidNumber gidNumber gecos homeDirectory loginShell krbPrincipalName cn memberOf entryuuid modi...
Jun 01 19:00:49 serv slapd[2735]: conn=1325 op=6 SEARCH RESULT tag=101 err=0 nentries=5 text=
Jun 01 19:00:50 serv slapd[2735]: conn=1325 op=7 SRCH base="dc=superduper,dc=de" scope=2 deref=0 filter="(&(objectClass=posixGroup)(cn=*)(&(gidNumber=*)(!(gidNumber=0))))"
Jun 01 19:00:50 serv slapd[2735]: conn=1325 op=7 SRCH attr=objectClass cn userPassword gidNumber member entryuuid modifyTimestamp modifyTimestamp
Jun 01 19:00:50 serv slapd[2735]: conn=1325 op=7 SEARCH RESULT tag=101 err=0 nentries=0 text=
Jun 01 19:00:50 serv slapd[2735]: conn=1325 op=8 SRCH base="dc=superduper,dc=de" scope=2 deref=0 filter="(&(objectClass=ipService)(cn=*)(ipServicePort=*)(ipServiceProtocol=*))"
Jun 01 19:00:50 serv slapd[2735]: conn=1325 op=8 SRCH attr=objectClass cn ipServicePort ipServiceProtocol modifyTimestamp
Jun 01 19:00:50 serv slapd[2735]: conn=1325 op=8 SEARCH RESULT tag=101 err=0 nentries=0 text=
Hint: Some lines were ellipsized, use -l to show in full.

Ich rate dennoch zur Vorsicht! Wer lieber nicht mutig sein will und eher einen sauberen Weg bevorzugt, findet einen alternativen Vorschlag in den Diskussionsbeiträgen unter folgender Bug-Meldung:
https://bugzilla.opensuse.org/show_bug.cgi?id=1011582.

Viel Spass mit OpenLDAP unter Opensuse Leap 42.2 !

Erste Schritte mit Git für lokale und zentrale Repositories unter Eclipse – IV

Ich setze mit diesem Blog-Post meine kleine Serie von Artikeln zum Thema GIT-Einsatz unter Eclipse fort. Im ersten Beitrag
Erste Schritte mit Git für lokale und zentrale Repositories unter Eclipse – I
hatte ich ein einfaches Einsatz-Szenario für freiberufliche Entwickler dargestellt, die mobil unterwegs sein müssen und ihre Versionsentwicklung regelmäßig zwischen PCs, Laptops und einem oder mehreren zentralen Servern abgleichen müssen:

Im LAN des Homeoffice wird mit einem lokalen Git-Repositories auf dem Arbeitsplatz-PC gearbeitet. Änderungen sollen schon aus Backup-Gründen zeitnah in ein zentrales Git-Repository im LAN überführt werden. Über den LAN-Server soll bei Bedarf aber auch ein Laptop versorgt werden; das dortige lokale Repository wird zum Arbeiten während Reisen benutzt. Zur Sicherheit wird der Status auf dem Laptop mit einem zentralen Repository im Internet abgeglichen, wann immer sich dazu die Gelegenheit bietet.

Die Frage ist: Wir organisiert man das unter Eclipse? In den letzten zwei Beiträgen
Erste Schritte mit Git für lokale und zentrale Repositories unter Eclipse – II
Erste Schritte mit Git für lokale und zentrale Repositories unter Eclipse – III
habe ich mich deshalb zunächst mit der Anlage eines lokalen Repositorys auf einem PC mit Hilfe des EGit-Plugins unter Eclipse beschäftigt. [EGit ist übrigens auch als standalone Product unter dem Namen “GitEye” verfügbar.] Wir haben uns anschließend angesehen, wie man Commits durchführt, wie man Branches erzeugt und auch wieder mergt.

Im Zentrum dieses und kommender Blog-Beiträge steht aber vor allem ein zentraler Branch, der sog. “Master”-Branch”. Er stellt in unserem Szenario das wichtigste Bindeglied zwischen den verschiedenen Repositories auf PC, Laptop und zentralen Servern dar. Alle Entwicklungsaktivitäten werden in unserem Szenario letztlich auf ihn ausgerichtet. Wir merken aber bereits an dieser Stelle an, dass sich alle später dargestellten Abgleichverfahren zwischen lokalen und zentralen Repositorys realtiv zwanglos auf mehrere Branches erweitern lassen.

Ich wende mich in diesem Artikel der Anlage eines zentralen Repositorys auf einem Server im LAN zu. In einem zweiten Schritt binde ich dann das erzeugte LAN-Repository an das lokale Repositories unseres Entwicklungs-PCs an. Abschließend wird eine Änderung im lokalen Repository auf das zentrale Repository übertragen (“Push”-Operation). Das Spektrum der behandelten Themen entspricht in etwa der Lösung der Aufgaben 4 bis 7 des ersten Artikels.

Voraussetzung: Funktionierender SSH-Server

SVN-Nutzer wissen, dass ein SVN-Server eine spezielle Konfiguration über definierte Konfigurationsdateien und -verzeichnisse erfordert. U.a sind dabei spezielle Zugriffsrechte festzulegen. Weitere Sicherheitsaspekte sind zu berücksichtigen, wenn man SVN-Dienste über einen Webserver und “https” anbieten will.

Aus meiner Sicht ist die Einrichtung eines GIT-Servers für unser Szenario (aber nicht nur dafür) relativ einfach: Benötigt wird im Grunde nur ein hinreichend konfigurierter SSH-Server, auf dem man den Zugriff auf Verzeichnisstrukturen und Objekte eines “.git”-Verzeichnisses über User- und Gruppen-Accounts steuert. Ansonsten muss dort unter Linux nur das für die jeweilige Distribution passende Git-Paket installiert sein. Mehr ist zum Aufsetzen eines privaten Git-Servers unter SSH fast nicht erforderlich! Hinzu kommen lediglich zwei weitere, einfache Schritte:

  • Das auf einem PC bereits
    vorhandene Repository (hier für das Eclipse-Projekt “alien1”) ist zu klonen.
  • Der Git-Repository-Clone ist in ein definiertes Zielverzeichnis auf dem SSH-Server zu transferieren.

Man kann die oben genannten beiden Punkte mittels GIT theoretisch auch in einem Schritt erledigen; ich ziehe es aber der besseren Kontrolle wegen vor, hier zweistufig vorzugehen. Alle später einzurichtenden Git-Clients nehmen dann auf die URI des angelegten Git-Verzeichnisses auf dem Server Bezug.

Hinweis: Es gibt natürlich auch Möglichkeiten, eigene Git-Server über andere Protokolle und im Rahmen von Web-Server-Diensten einzurichten. Ich gehe in dieser Artikelserie aber nicht darauf ein. Ich sehe auch keinen Grund dafür, für unser einfaches privates Szenario nicht eine simple und sichere SSH-Variante zu nutzen.

Ich gehe in diesem Artikel zudem nicht auf die Bereitstellung und Konfiguration von SSH auf einem Server ein. Das habe ich an anderer Stelle dieses Blogs schon beschrieben. Ich gehe im LAN ferner von einem einfachen UID-bezogenen Login auf dem SSH-Server mittels eines Passwortes aus; für einen später zu kontaktierenden SSH-Server im Internet setze ich dagegen einen Login per RSA-Key (hinreichender Länge plus sicherem elliptischem KEX-Verfahren) voraus.

Unser LAN-Server heiße “debian8” und sei einer lokal definierten Domäne “lanracon.de” zugeordnet. Der Server sei aufgrund entsprechender DNS-Einträge aber auch direkt unter “debian8” ansprechbar. Ich gehe davon aus, dass wir auf diesem Server z.B. Giggle oder QGit installiert haben, um dort einen Blick auf neu installierte Repositories werfen zu können (s. hierzu auch den vorhergehenden Blog-Artikel). Das übergeordnete Zielverzeichnis für Git-Repositorys auf dem Server sei “/projekte/GIT/”. Das zentral zu erzeugende Repository beziehe sich in unserem Beispiel – wie das zuletzt betrachtete PC-Repository auch – auf unser PHP-Eclipse-Projekt namens “alien1”.

Erzeugen eines Repositories ohne Working Tree durch Klonen

Auf einem Git-Server benötigen wir in der Regel keinen Working Tree. Das Erzeugen eines Clones ohne Working Tree gelingt mit Hilfe des “git clone”-Befehls und bestimmter Optionen.

Ich bemühe an dieser Stelle die Kommandozeile einer Shell. Man kann zwar auch mit EGit ein vorhandenes Repository in lokale Verzeichnisse klonen; aber wir wollen ja anschließend die Clone-Dateien auch noch auf den Server bringen. Das ginge theoretisch zwar auch über geeignete grafische Eclipse-Tools für den Remote-Systems-Zugriff; warum aber mit Kanonen auf Spatzen schießen?

Das Repository und der Working Tree unseres Beispiels aus den letzten Blog-Posts waren auf unserem Entwicklungs-PC im Verzeichnis “/projekte/GIT/alien1” beheimatet. Ich lege mir für die Zwischenspeicherung des Clones und den anschließenden Transfer auf den Server im vorhandenen GIT-Verzeichnis des PCs (oder Laptops) aber ein separates Verzeichnis an – hier namens “alien1trans“. Also

myself@mytux:/projekte/GIT> mkdir alien1trans
myself@mytux:/projekte/GIT> cd alien1trans/

Die Struktur des notwendigen “clone”-Befehls ist:

git clone --bare <em>Repo-Pfad Target-Dir-Pfad</em>

Für die Erzeugung eines Repositorys ohne “Working Tree”-Verzeichnis sorgt die Option “–bare“. Wird der Target-Dir-Pfad des Verzeichnisses, in das geklont werden soll, nicht angegeben, wird der Clone im aktuellen Verzeichnis (Working Directory) angelegt. In unserem Fall ergibt sich:

myself@mytux:/projekte/GIT/alien1trans> git clone --bare ../alien1
Klone in Bare-Repository 'alien1.git' ...
Fertig.
myself@mytux:/projekte/GIT/alien1trans> ls -la
insgesamt 12
drwxr-xr-x 3 myself entw 4096  6. Mai 09:28 .
ndrwxr-xr-x 6 myself entw 4096  6. Mai 09:27 ..
drwxr-xr-x 7 myself entw 4096  6. Mai 09:28 alien1.git
myself@mytux:/projekte/GIT/alien1trans> du -s -h
60M     .
myself@mytux:/projekte/GIT/alien1trans> cd ../alien1
myself@mytux:/projekte/GIT/alien1> du -s -h
225M    .
myself@mytux:/projekte/GIT/alien1> du -s -h .git
60M     .git
myself@mytux:/projekte/GIT/alien1>
myself@mytux:/projekte/GIT/alien1> cd ../alien1trans/
myself@mytux:/projekte/GIT/alien1trans> mv alien1.git/ .git  
myself@mytux:/projekte/GIT/alien1trans> ls -la                                                                          
insgesamt 12                                                                                                       
drwxr-xr-x 3 myself entw 4096  6. Mai 11:25 .                                                                        
drwxr-xr-x 6 myself entw 4096  6. Mai 09:27 ..
drwxr-xr-x 7 myself entw 4096  6. Mai 09:28 .git

Wie man sieht, habe ich im Anschluss an das Klonen die korrekte Größe des Clone-Verzeicnisses geprüft. Das reine Repository (hier “alien1.git”) ist offenbar deutlich kleiner als der Working Tree selbst! Am Schluss habe ich das Repository-Verzeichnis des Clones, das als Anteil immer den Namen des Ursprungsrepositories erhält, noch in “.git” umbenannt. Grund: Viele Git-GUI-Programme suchen automatisch nach einem Verzeichnis namens “.git”.

Ok, wir haben nun einen Clone auf unserem PC. Wie bringen wir den jetzt auf den Server “debian8.lanracon.de”? Natürlich mittels SSH. Ich gehe mal davon aus, dass der User “myself” aus der Gruppe “entw” auch auf dem Server vertreten ist und sich dort per Passwort anmelden darf. Er verfüge über die notwendigen Schreibrechte im übergeordneten Zielverzeichnis auf dem Server, in dem wir spezifische GIT-Repositories aufbewahren wollen. Zunächst legen wir auf dem Server ein spezielles Zielverzeichnis für das “alien1”-Repository an:

myself@mytux:/projekte/GIT/alien1trans> ssh myself@debian8
Password: 
Last login: Sat May  6 11:41:46 2017 from xxx.xxx.xxx.xxx
Have a lot of fun...
myself@debian8:~> cd /projekte/GIT
myself@debian8:/projekte/GIT> mkdir alien1
myself@debian8:/projekte/GIT> exit
Abgemeldet
Connection to debian8 closed.
myself@mytux:/projekte/GIT/alien1trans>

Ich habe hier mal angenommen, dass wir auf dem Server bereits eine ähnliche Verzeichnisstruktur wie auf dem PC angelegt hatten. Das muss natürlich nicht so sein. Also das Zielverzeichnis bitte dort anlegen, wo man seine GIT-Repositories verwalten will.

Hinweis: An dieser Stelle können bereits Rechte (im Besonderen Gruppenrechte) eine Rolle für die spätere Nutzung des Repositories durch andere User spielen. Ich regele die korrekten Rechte auf Servern, die ich selbst komplett unter Kontrolle habe, meistens über ACLs und/oder das SGID-Bit. Das erspart einem viel Arbeit. Egal wie – es ist jedenfalls dafür zu sorgen, dass das Verzeichnis die richtige Gruppe und einen passenden Rechtekamm erhält.

Nun kopieren wir einfach die Dateien des geklonten “.git”-Verzeichnisses per “scp” vom PC auf den Server:

myself@mytux:/projekte/GIT/alien1trans> scp -r .git myself@debian8:/projekte/GIT/alien1/
Password: 
...
....
99eaff29e3720789e5e75e9e8999a5bde77733                                           100%  290     0.3KB/s   00:00    
a816f7c5ebab36333b9fd8574d459176f3ff07                                           100% 2416     2.4KB/s   00:00    
5f11c90dbb0170c0b2082f1d5fec9a0e10522b                                           100%   17KB  17.1KB/s   00:00    
101f6958c4e18057cfdf7c975a1483eeeddea9                                           100% 1349     1.3KB/s   00:00    
2fd38f7570791c179ec4c94b886ec62027d3a3                                           100% 9190     9.0KB/s   00:00    
config                                                              
             100%  127     0.1KB/s   00:00    
description                                                                      100%   73     0.1KB/s   00:00    
packed-refs                                                                      100%  289     0.3KB/s   00:00    
pre-commit.sample                                                                100% 1642     1.6KB/s   00:00    
pre-rebase.sample                                                                100% 4951     4.8KB/s   00:00    
pre-receive.sample                                                               100%  544     0.5KB/s   00:00    
prepare-commit-msg.sample                                                        100% 1239     1.2KB/s   00:00    
post-update.sample                                                               100%  189     0.2KB/s   00:00    
commit-msg.sample                                                                100%  896     0.9KB/s   00:00    
pre-applypatch.sample                                                            100%  424     0.4KB/s   00:00    
applypatch-msg.sample                                                            100%  478     0.5KB/s   00:00    
pre-push.sample                                                                  100% 1348     1.3KB/s   00:00    
update.sample                                                                    100% 3610     3.5KB/s   00:00    
HEAD                                                                             100%   23     0.0KB/s   00:00    
exclude                                                                          100%  240     0.2KB/s   00:00    
myself@mytux:/projekte/GIT/alien1trans> 

Je nach Größe des Repositorys rast hier eine Reihe von Dateien, die mit Hashes bezeichnet sind, an uns vorüber. Um zu prüfen, ob das Verzeichnis auf dem Server richtig aussieht, nutze ich z.B. Giggle:

myself@mytux:/projekte/GIT/alien1trans> ssh myself@debian8
Password: 
Last login: Sat May  6 11:48:46 2017 from xxx.xxx.xxx.xxx
Have a lot of fun...
myself@debian8:~> export NO_AT_BRIDGE=1
myself@debian8:~> giggle & 

Hinweis:

Mir passiert es auf Servern mit etwas älterem Kernel regelmäßig, dass ich die Umgebungsvariable NO_AT_BRIDGE mittels
export NO_AT_BRIDGE=1
auf dem Server setzen muss, um Giggle oder QGit (über SSH) zum Laufen zu bringen. Siehe hierzu: https://wiki.archlinux.de/title/GNOME#Tipps_und_Tricks und https://bbs.archlinux.org/viewtopic.php?id=176663 sowie auch https://bugzilla.redhat.com/show_bug.cgi?id=1056820

Unter Giggle muss man dann das “Projekt” alien1 unter dem entsprechenden Pfad zum Repository öffnen. Ich gehe auf die Bedienung von Giggle oder QGit nicht näher ein. Die meisten Git-Anwendungen sind nach ein wenig Beschäftigung mit Git weitgehend selbsterklärend. Das Ergebnis ist jedenfalls:

Gut! Wir können die Branches des geklonten Repositories offenbar auch auf dem Server mit graphischen Tools einsehen.

Hinweis:

Für diesen Artikel habe ich faktisch einen unter KVM angelegten Linux-Server auf einem Laptop benutzt. Im LAN kann man bzgl. graphischer Tools auf Servern noch performant genug mit “ssh -X” arbeiten. Wer hingegen mit einer graphischen Oberfläche auf echten Remote-Servern im Internet arbeiten muss, findet ggf. mit X2GO ein passendes Toolset; s. z.B.:
Remote Desktop für Debian 8 mit X2Go auf Strato-vServern.

Dem Leser werden Teile der Branch-Grafik bekannt vorkommen; einen ähnlichen Graphen hatte ich bereits gegen Ende des letzten Artikels abgebildet. Dort war der Zugriff aber auf das Repository des PCs erfolgt.

Hinweis: Wer Speicherplatz sparen will, kann nach diesem positiven Check das Zwischenverzeichnis “alien1trans” und seinen Inhalt löschen (“rm -r alien1trans”).

Anbinden des Master-Branches des Servers an den Master-Branch des PCs

Das Repository auf dem Server ist relativ nutzlos, wenn wir es nicht in Verbindung mit lokalen Repositories auf unseren PCs oder Laptops bringen. Wie also können wir von Eclipse/EGit aus auf das eben auf dem Server eingerichtete Repository zugreifen und wie füllen wir es mit Commits, die wir lokal durchgeführt haben?

Es gibt unter Eclipse/EGit mehrere Wege, einen Branch eines Remote-Git-Repositorys an einen korrespondierenden Branch eines lokalen Repositorys anzubinden. Ich wähle hier den Weg über den Punkt “Remotes” im hierarchisch organisierten Eclipse-View “Git Repositories” für die Darstellung lokaler Repositorys:

Im Kontextmenü zu “Remotes” findet sich ein Punkt “Create Remote”, den wir anklicken:

Im nächsten Popup-Dialog müssen wir der neuen “Remote-Git-Anbindung” einen Namen geben:

Die vorgewählte Radiobox für die Push-Konfiguration lassen wir in ihrem Zustand. Ich komme auf die Alternative in einem späteren Artikel zurück. Das Drücken des OK-Buttons führt zu einem weiteren Dialogfenster:

Dort wählen wir den Button “Change”, um die Verbindung zum Git-Server zu konfigurieren; es öffnet sich ein weiteres Dialogfenster (s.u.) mit mehreren Eingabefeldern, die wir wie folgt behandeln:

  • In das Feld “URI” geben wir zunächst nur den Pfad zum Repository auf dem Server an – also in unserem Beispiel:
    “/projekte/Git/alien1/.git”.
  • In das Feld “Host” geben wir in unserem Fall natürlich “debian8” ein. In der Combobox “Protocol” wählen wir “ssh”; ggf. müssen wir auch noch einen Nicht-Standard-Port angeben, falls SSH auf dem Server unter einem speziellen Port angeboten wird.
  • Im Feld “User” geben wir unsere UID auf dem Server ein – hier “myself”. Dann ergänzen wir noch das Password; das Feld “Store in Secure Store” lasse ich immer aktiv. Hier sammelt und verschlüsselt Eclipse die ihm anvertrauten Passwörter in einem Container, der wiederum ein Zugangspasswort erfordert.

Der Dialog baut den UR-Identifier im Zuge dieser Schritte vollständig auf:

Drücken auf den “Finish”-Button führt zum nächsten Dialog, der uns erlaubt, die sog. “Push-Reference”-Konfiguration vorzunehmen:

Worum geht es da? Für den Moment reicht es zu wissen, dass wir eine Beziehung zwischen einem lokalen Branch und einem Branch eines Remote-Repositories herstellen, so dass wir später neue, per Commit erstellte Knoten des lokalen Branches gezielt in den ausgewählten Remote-Branch überführen können.

Hinweis:

Faktisch kann man aber die nachfolgende einfache Konfiguration für genau einen Branch und einen Remote-Server auf verschiedene abzugleichende Branches und verschiedene Server im Rahmen ein und derselben Remote-Konfiguration ausdehnen. Dies ist insbesondere dann nützlich, wenn man lokale Repsitory-Änderungen gleichzeitig auf verschiedene Remote-Server übertragen will. Ich komme darauf in einem weiteren Blog-Beitrag zurück.

Wir drücken nun auf den Button “Add”. Folgende Schritte sind im nächsten Dialog zu leisten, um eine Referenz des Remote Master-Branches zum lokalen herzustellen; zunächst wählen wir den lokalen Branch; es genügt ein “m” in die betreffende Zeile einzugeben. Das Fenster bietet uns dann automatisch den (momentan einzigen) passenden Branch zur Auswahl an. Dann wählen wir den Remote-Branch:

Bei letzterem Schritt muss die SSH-Verbindung bereits funktionieren! Auch hier sollte eine Vorgabe von “m” zur Auswahl des richtigen (Remote-) Master-Branches führen.

Übrigens: Bei Einsatz von asymmetrischen Schlüsseln zur SSH-Authentifizierung müssen diese vorab im Eclipse-Dialog SSH2-Dialog unter “Preferences => General => Network Connections => SSH2” definiert worden sein.

Man wird dann ggf. zur Eingabe der Passphrase für den lokalen Schlüssel aufgefordert.

Im unserem Push-Referenz-Dialog ergibt sich nun folgendes Bild:

Und schließlich:

Weitere Git-“Remotes”

Ganz analog kann man nun weitere “Remotes” für andere Server anlegen – soweit das denn sinnvoll ist. Man erhält schließlich eine Kollektion verschiedener Remote-Verbindungen zu Git-Servern:

Jede dieser Remote-Anbindungen enthält eine separate “Push”-Konfiguration, die man nach Bedarf unabhängig von anderen Remote-Verbindungen für notwendige Abgleichvorgänge bedienen
kann. Aber Achtung:

In unserem Beispiel haben wir bisher nur eine funktionierende Push-Verbindung aufgebaut. Bereits die obige Abbildung verdeutlicht aber, dass es offenbar auch so etwas wie Fetch-Operationen gibt. Den Sinn und Zweck von “Fetches” behandle ich in einem kommenden Artikel.

Anwenden der Push-Verbindung zum LAN-Server – eine erste Push-Operation

Den Transfer lokaler Repository-Änderungen auf das Remote-Repository bezeichnet man als Push-Operation. Je nachdem, wer wann welche Änderungen auf dem Server eingespielt hat, setzt dies ggf. vorhergehende komplexe Merge-Operationen mit lokalen Branches voraus. In unserem Szenario, in dem wir alleine den Master-Branch auf dem LAN-Server beliefern, ist das aber, zumindest im Moment, noch völlig unerheblich. Die Änderungen erfolgen gemäß unserer Szenario-Beschreibung im ersten Beitrag ja sequentiell.

Also probieren wir einfach mal aus, was ein Push im momentanen ReositoryZustand bewirkt. Hierzu führen wir einen Klick mit dem rechten Mousebutton auf einer unserer angelegten Remote-Verbindungen aus; es öffnet sich ein Kontext-Menü, das u.a. die Push-Operation anbietet:

Ich habe die Push-Operation im abgebildeten Beispiel in Richtung auf einen Server durchgeführt, der sich in einem ähnlichen Zustand wie unser “debian8” aus der oben erläuterten Remote-Konfiguration befindet. Das führt dann zu folgender System-Reaktion und -Information:

Dieses Ergebnis war zu erwarten; das geklonte Repository befindet sich ja immer noch im selben Zustand wie das aktuelle auf dem PC unter Eclipse. Wir müssen lokal natürlich zuerst eine Änderung comitten; erst die lässt sich dann sinnvollerweise zum Server weiterreichen. Um die Änderung und ihren Hash lokal wie remote verfolgen zu können, lassen wir uns im Git-Repository-View unsere Branches anzeigen und öffnen dann per rechtem Mausklick das Kontextmenü des “Master”-Branches. Dort klicken wir auf den Menüpunkt “Show In => History”. Der graphische History-View sieht in meinem Beispiel wie folgt aus:

Übrigens: Die Abbildung zeigt für den obersten Knoten auch, dass die HEAD-Version des Branches bislang mit denen definierter Remote-Server-Branches “loc_deb8/master” und “strat_deb/master” übereinstimmt!

Nun führen wir – wie im letzten Artikel erläutert – eine Änderung auf einer Testdatei aus und committen die über den Commit-Button des Git-Staging-Dialogs:

Wir erhalten dann nach einem Refresh des History-Views:

Hier erkannt man, dass sich die lokale Version nun von den letzten bekannten Versionen auf den Servern “loc_deb8/master” und “strat_deb/master”
abweicht. (Wie das lokale Eclipse auf unserem PC erfährt, ob sich inzwischen möglicherweise durch andere Nutzer etwas auf den Server-Repositories geändert hat, behandle ich in einem anderen Artikel.) Man merke sich nun den Hash des letzten Knotens.

Nun führen wir nochmals die oben versuchte Push-Operation aus; ich nutze hier eine definierte Verbindung zu einem realen Server, die ich unter der Bezeichnung “loc_deb8” konserviert habe:

Wir klicken auf OK. Dann wechseln wir zur graphischen Oberfläche unseres Servers und refreshen das dort geöffnete Giggle (oder QGit, ..). Und tatsächlich:

Unsere lokale Änderung ist wohlbehalten im Remote Repository unseres Servers angekommen. Die Hashes der Knoten sind identisch.

Potentielle Probleme mit Push-Operation und Ausblick

Damit man lokale Änderungen so einfach wie oben beschrieben pushen kann, müssen diese von Git als echte Nachfolger des letzten Knotens im Remote-Branch identifiziert werden können. Es ergeben sich dann um sog. Fast-Forward-Merges, die mit keinen direkten formalen Konflikten zwischen verschiedenen Änderungen gleicher Code-Bereiche verbunden sind.

Für unser einfaches sequentielles Änderungsszenario, das wir im ersten Artikel beschrieben haben, sind Fast-Forward-Merges aus offensichtlichen Gründen immer möglich.

Man stelle sich aber eine Situation mit mehreren Anwendern vor. Dann können andere Entwickler unser zentrales Repository bereits mit ähnlichen Änderungen upgedated haben – bevor wir unsere Änderung pushen. Das führt dann potentiell zu Konflikten zwischen den verschiedenen Änderungen, die GIT nicht ohne unser Zutun auflösen kann. Unsere Push-Operation kann in einem echten Entwicklungsszenario deshalb auch schief gehen – genauer: in einen manuell zu bereinigenden Konflikt münden. (In der Praxis vermeidet man häufige Kollisionen mit den Inhalten zentraler Repositories übrigens auch durch organisatorische Maßnahmen; etwa dadurch, dass man nicht verschiedene Entwickler parallel an den gleichen Dateien bzw. gleichen Codebereichen arbeiten lässt.)

Konflikte können aber auch in einem 1-Personen-Szenario auftreten, in dem man vergessen hat, seine Änderungen auf verschiedenen Entwicklungssystemen (Laptop, PC) systematisch und sequentiell über zentrale Server abzugleichen.

Um eventuelle Konflikte vorab zu erkennen und ggf. durch Merges zu bereinigen, die man lokal vor einem Push ausführt, benötigt man eine Übertragung des Zustands eines Remote-Repositorys in das lokale System. Hierzu dienen Fetch- und Pull-Operationen; sie werden u.a. Thema unseres nächsten Artikels.

Dort wollen wir uns ferner damit befassen, wie wir den Stand unseres zentralen Repositorys auf einen Entwicklungs-Laptop übertragen.

Make PEAR IT-templates work on a PHP 7 server

Some of my older PHP programs use PEAR-IT-templates. At the core of this PHP template engine is the “IT.php” file defining a class “HTML_Template_IT” via an old fashioned “contructor” function of the same name (stemming from old PHP4’s way to define classes).

Yesterday, I needed to make some IT-templates work on an Apache2 server with PHP 7.1. This was easier than expected: Setting PHP to display all warnings and errors leads directly to the right code statements which must be corrected:

Correcting the call of preg_replace

In a first step we can ignore the warning about the old fashioned class declaration, which will sooner or later disappear from PHP. What absolutely needs to be changed, however, is an error that arises due to a special usage of the function preg_replace():

Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback

In my PEAR IT-installation the problem is located around line 956 of the file “IT.php”. Fortunately, some other clever people have already provided a method, how to replace the critical statement:

        // Replace the following lines by the subsequent statements
        /*
        return preg_replace(
            "#<!-- INCLUDE (.*) -->#ime", "\$this->getFile('\\1')", $content
        );
        */
	return preg_replace_callback(
	   "#<!-- INCLUDE (.*) -->#im",
	    array($this, 'getFile'),
	    $content
	);

See the contribution of A. Preuss in the following stack overflow post:
http://stackoverflow.com/questions/22597102/preg-replace-the-e-modifier-is-deprecated-error

Worked perfectly for me. Many thanks to A. Preuss!

Changing to a __construct() function

To get rid of the warning regarding the old fashioned class constructor function just replace the function definition around line 376 by

    // function HTML_Template_IT($root = "", $options=null) {
    function __construct($root = "", $options=null) {

With both the replacements described above I could use my old IT-template dependent PHP programs successfully on a PHP 7.1 system! This, hopefully, gives me enough time to replace the PEAR IT engine by the Smarty engine wherever reasonable :-).

PhpMyAdmin 4.7 on Opensuse Leap 42.2 – install PHP 7 and correct some code to avoid errors

Yesterday, I wanted to change to the latest version of PhpMyAdmin (4.7) on my development laptop which runs on Opensuse Leap 42.2. PHP 5.6 was provided via an Apache2 server and php-apache-modules. I downloaded the zipped code package for PhpMyAdmin and performed the usual setup procedure on my local web server. But I met some obstacles both under and after the phpmyadmin installation.

First, I got an error during installation of the following type:

phpmyadmin fatal error: call to undefined function phpseclib\crypt\random::string() in …/phpmyadmin/libraries/config/serverconfigchecks.php on line 226

Changing to PHP 7 – via using the Opensuse repository at http://download.opensuse.org/repositories/devel:/languages:/php/openSUSE_Leap_42.2/ helped to overcome this error.

However, be aware of the fact that changing to PHP 7 globally implies a lot of consequences – e.g changing database code in older programs from the the “mysql” to the “mysqli” interface. (Off topic: As long as one wants to use PHP via Apache modules I do not see a way to run both PHP versions in parallel on one Apache2 web server. Things are different with FCGI and PHP-FPM; but I did not experiment with these alternatives, yet. My way to support older programs for the time being actually includes the use of an independent 42.2 LAMP installation on a KVM machine – together with an older 4.3/4.4-version of PhpMyAdmin.]

Another error I stumbled across after installation of PhpMyAdmin 4.7 occured when I tried to use the drop-down boxes for changing pages during the display of large tables. Whenever you use the drop down box a small popup appears complaining about “unmatching tokens”.

The recipe to mend this bug is described by the Phpmyadmin developers on the following Internet page:
https://github.com/phpmyadmin/phpmyadmin/commit/5ee4320b7de345062ced7e02aca65417baa8a944

One just has to change some lines (at line nr 796) in the file “/InstallationDirOFPhpmyadminOnWebserver/libraries/DisplayResults.php” as described in the above article :

// Comment the following lines at position 796 and replace with the 2 lines shown 
// $table_navigation_html .= '<form action="sql.php'
// . URL::getCommon($_url_params)
// . '" method="post">';
$table_navigation_html .= '<form action="sql.php" method="post">';
$table_navigation_html .= URL::getHiddenInputs($_url_params);

Good luck with PhpMyAdmin 4.7!

KVM, video virtio, Debian 8 guest, host with Intel HD 4000 – install a 4.9 kernel on the guest for optimal 2D graphics performance !

Some time ago I wrote a post about the use of new virtio video driver for a KVM guest with a Debian 8 operative system. See:
KVM, video QXL und video virtio – Video-Auflösung des Gnome-Desktops eines Debian 8-Gastystems einstellen
The KVM host at that time was a PC with a native Nvidia graphics card. In my post I was very positive about the 2D-performance results of the spice/virtio combination for the KVM guest graphics.

Two days ago I had to perform the installation of a Debian 8 KVM guest – this time, however, the host was a laptop with an Optimus system: The internal graphics card of the i7-3632QM CPU was/is an Intel HD Graphics 4000. (The laptop has an additional Nvidia GT645 M, which can be used via Bumblebee.) Under normal conditions the Intel HD graphics (with the i915 kernel module) has sufficient power to support 2D and 3D accelerated GUIs. In my case the laptop ran on Opensuse Leap 42.2, qemu-kvm was of version 2.9, libvirt of version 3.3 (installed from the “virtualization”-repository: http://download.opensuse.org/repositories/Virtualization/openSUSE_Leap_42.2/). But this time I got a bit disappointed.

Disappointing 2D-graphics performance of the Debian8 KVM guest with kernel 3.6, with spice/QXL and spice/virtio

I experienced two problematic points with the Debian 8 guest and its original 3.6 kernel:

  • The performance with the Spice/QXL-graphics of the KVM guest was not at all convincing – especially not with GTK-applications (neither on a KDE or Gnome 3 GUI of the guest) at and above guest graphics resolutions 1400×900. I saw tearing of windows during fast movements across the spice terminal screen. Especially disappointing was the performance of Firefox ESR: Sluggish reactions of all kinds of window contents and slow reactions to scrolling of complicated web site contents – especially of running videos. But the QXL driver at least gave me the choice of many, many guest resolutions up to the maximum resolution of the host.
  • The performance was only slightly better with the new “virtio” driver. But the choice of guest resolutions was very limited with a maximum of 1280x768px.

Update to the latest kernel on the Debian 8 guest

I then read on some Internet websites that the virtio graphics driver on qemu/kvm requires a kernel later than version 4.x on the guest system, too. So why not try? The installation of newer kernels on Debian 8 is possible by adding the “backports” repository to apt’s configuration. We have to a add a line

deb http://mirror.one.com/debian/ jessie-backports main contrib non-free

to /etc/apt/sources.list on the Debian system. The we execute

apt-get update

and

apt-get install -t jessie-backports linux-image-amd64

to get the latest kernel installed. In my case this is a SMP kernel of version 4.9.18. Up to now this kernel lead to no conflicts or problems with any of the installed software on the Debian 8 guest.

Results of the updated guest with kernel 4.9

The graphical performance of the Debian guest with spice/virtio combination, however, changed dramatically to the better! Actually, the overall 2D-performance is now really convincing – even on the relatively weak Intel HD 4000. The tear free moving of window frames of all kinds of Qt- or Gtk3-applications across the spice terminal is just one point. The other is that the performance impression of e.g. Firefox ESR on the virtualized guest is almost not distinguishable from Firefox on the host’s
KDE interface. Below you see 2 FF windows on the Gnome GUI of the Debian 8 KVM guest plus a QGit window. One FF window plays a video.

And in addition I now get all resolutions I could wish for:

I love KVM! Even on laptops!