(This is an English translation of a previous post)
We use HAProxy for all our incoming HTTP and other TCP connections.
Its configuration is the most complex we have. That’s why we do not write it by hand, but rather generate it from metadata and includes. Such a generator makes the configuration easier — but it also makes it harder to see what the actual changes will be in the end.
For situations like that, we like tooling that will show us a diff of the generated configuration. Because the HAProxy configuration is a single text file, we could use the diff program to compare two versions.
The downside of a textual diff is that it shows meaningless differences, for example if only order or comments change.
For example, if we compare these two files:
global
log stdout format raw local0 info
defaults
timeout connect 5s
timeout server 10s
timeout client 20s
# Example config
frontend fe_proxy
bind 0.0.0.0:80
default_backend be_proxy
backend be_proxy
server localhost 127.0.0.1:8080
with
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
# Example config with a different comment
frontend fe_proxy
bind 0.0.0.0:80
default_backend be_proxy
Then diff will give us this output:
$ 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
-# Example config
+
+backend be_proxy
+ server localhost 127.0.0.1:8080
+
+
+# Example config with a different comment
frontend fe_proxy
bind 0.0.0.0:80
default_backend be_proxy
-
-backend be_proxy
- server localhost 127.0.0.1:8080
There is a relevant change here – but it’s lost between multiple textual changes that have no effect.
Therefore we have created a small Go program which roughly reads the configuration into data structures and then compares them:
$ 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"}}},
}
In this output we can clearly see what actually changed. Of course this is a contrived example – usually you would do these unrelated changes in different commits. But even then the tool can be helpful; to ensure that one did not make actual changes when one just meant to rearrange.
The program can be found on GitHub. Please be advised, that it is only meant as an example – we have no plans to maintain the repository.
If you’re located in Germany, we’re hiring (up to 100% remote work from Germany).
(Header-Bild: Prtksxna, CC BY-SA 4.0 , via Wikimedia Commons)