HAProxy-Konfiguration strukturell diffen

(This post is also available in English)

Wir benutzen HAProxy für alle unsere eingehenden HTTP- und sonstigen TCP-Verbindungen.

Die Konfiguration ist die komplexeste, die wir haben. Daher wird die Konfiguration nicht von Hand erstellt, sondern aus Metadaten und Includes generiert. Ein solcher Generator vereinfacht die Konfiguration — aber kann es erschweren zu sehen, was man nun wirklich ändert.

Für solche Fälle mögen wir Tooling, dass uns einen Diff der generierten Konfiguration anzeigen kann. Da die HAProxy-Konfiguration eine einzelne Textdatei ist, könnten wir das diff-Programm benutzen um zwei Versionen zu vergleichen.

Das Problem mit einem rein textuellen Diff ist, dass dort auch Unterschiede auftauchen, die gar keine Auswirkung auf HAProxy haben, z.B. wenn sich nur die Reihenfolge oder Kommentare ändern.

Wenn wir zum Beispiel diese beiden Dateien vergleichen:

global
	log stdout format raw local0 info

defaults
	timeout connect 5s
	timeout server 10s
	timeout client 20s

# Beispielconfig
frontend fe_proxy
	bind 0.0.0.0:80

	default_backend be_proxy

backend be_proxy
	server localhost 127.0.0.1:8080

mit

global
	log stdout format raw local0 info

defaults
	timeout client 10s
	timeout server 10s
	timeout connect 5s


backend be_proxy
	server localhost 127.0.0.1:8080


# Beispielconfig mit anderem Kommentar
frontend fe_proxy
	bind 0.0.0.0:80

	default_backend be_proxy

Dann bekommen wir von diff diese Ausgabe:

$ diff -u examples/old.cfg examples/new.cfg
--- examples/old.cfg    2024-02-19 15:53:45
+++ examples/new.cfg    2024-02-19 15:54:09
@@ -2,15 +2,17 @@
    log stdout format raw local0 info
 
 defaults
-   timeout connect 5s
+   timeout client 10s
    timeout server 10s
-   timeout client 20s
+   timeout connect 5s
 
-# Beispielconfig
+
+backend be_proxy
+   server localhost 127.0.0.1:8080
+
+
+# Beispielconfig mit anderem Kommentar
 frontend fe_proxy
    bind 0.0.0.0:80
 
    default_backend be_proxy
-
-backend be_proxy
-   server localhost 127.0.0.1:8080

Wir haben eine inhaltliche Änderung – aber diese geht unter in diversen strukturellen Änderungen, die keinen Effekt haben.

Deswegen haben wir ein kleines Go-Programm erstellt, welches HAProxy-Konfigurationsdateien grob in Datenstrukturen überträgt, und dann diese difft:

$ go run . examples/old.cfg examples/new.cfg 
&main.config{
    "backend": {"be_proxy": {"server": {"localhost 127.0.0.1:8080"}}},
    "defaults": {
        "": {
            "timeout": {
-               "client 20s",
+               "client 10s",
                "connect 5s",
                "server 10s",
            },
        },
    },
    "frontend": {"fe_proxy": {"bind": {"0.0.0.0:80"}, "default_backend": {"be_proxy"}}},
    "global":   {"": {"log": {"stdout format raw local0 info"}}},
  }

Jetzt können wir deutlich sehen, was sich tatsächlich geändert hat. Dieses Beispiel ist natürlich konstruiert – normalerweise würde man diese mehreren Änderungen in separaten Commits machen und nicht vermischen. Aber auch dann ist das Tool hilfreich um sicherzustellen, dass man beim reinen Umräumen einer Config keine inhaltlichen Änderungen gemacht hat.

Das Programm ist auf GitHub zu finden. Bitte beachte, dass das Programm nur als Beispiel dienen soll – wir planen nicht, das Repo zu maintainen.

Falls du auch Interesse hast solche Lösungen zu finden und an diesen zu arbeiten, bewirb dich doch bei uns.

(Header-Bild: Prtksxna, CC BY-SA 4.0 , via Wikimedia Commons)