2023-02-23 08:04:44 +01:00
|
|
|
# to run these tests:
|
|
|
|
# nix-instantiate --eval --strict . -A tests.haproxy
|
|
|
|
|
|
|
|
{ lib
|
|
|
|
, stdenv
|
|
|
|
, pkgs
|
|
|
|
, utils
|
|
|
|
}:
|
|
|
|
|
|
|
|
let
|
2023-03-17 07:47:43 +01:00
|
|
|
configcreator = pkgs.callPackage ./../../haproxy/configcreator.nix { inherit utils; };
|
|
|
|
mksiteconfig = pkgs.callPackage ./../../haproxy/siteconfig.nix {};
|
2023-02-23 08:04:44 +01:00
|
|
|
|
|
|
|
diff = testResult:
|
|
|
|
with builtins;
|
|
|
|
with lib.strings;
|
|
|
|
if isString testResult.expected && isString testResult.result then
|
|
|
|
let
|
2023-03-17 07:47:43 +01:00
|
|
|
# Taken from nixpkgs master
|
|
|
|
commonPrefixLength = a: b:
|
|
|
|
let
|
|
|
|
m = lib.min (stringLength a) (stringLength b);
|
|
|
|
go = i: if i >= m then m else if substring i 1 a == substring i 1 b then go (i + 1) else i;
|
|
|
|
in go 0;
|
|
|
|
# Taken from nixpkgs master
|
|
|
|
commonSuffixLength = a: b:
|
|
|
|
let
|
|
|
|
m = lib.min (stringLength a) (stringLength b);
|
|
|
|
go = i: if i >= m then m else if substring (stringLength a - i - 1) 1 a == substring (stringLength b - i - 1) 1 b then go (i + 1) else i;
|
|
|
|
in go 0;
|
|
|
|
|
2023-02-23 08:04:44 +01:00
|
|
|
p = commonPrefixLength testResult.expected testResult.result;
|
|
|
|
s = commonSuffixLength testResult.expected testResult.result;
|
|
|
|
expectedSuffixLen = stringLength testResult.expected - s - p;
|
|
|
|
resultSuffixLen = stringLength testResult.result - s - p;
|
|
|
|
expectedDiff = substring p expectedSuffixLen testResult.expected;
|
|
|
|
resultDiff = substring p resultSuffixLen testResult.result;
|
|
|
|
omitted = len: if len == 0 then "" else "[... ${toString len} omitted]";
|
|
|
|
in
|
|
|
|
{inherit (testResult) name;
|
|
|
|
commonPrefix = substring 0 p testResult.expected;
|
|
|
|
commonSuffix = substring (stringLength testResult.expected - s) s testResult.expected;
|
|
|
|
expected = "${omitted p}${expectedDiff}${omitted s}";
|
|
|
|
result = "${omitted p}${resultDiff}${omitted s}";
|
|
|
|
allExpected = testResult.expected;
|
|
|
|
allResult = testResult.result;
|
|
|
|
}
|
|
|
|
else testResult;
|
|
|
|
|
|
|
|
runTests = x: map diff (lib.runTests x);
|
|
|
|
in
|
|
|
|
|
|
|
|
with lib.attrsets;
|
|
|
|
runTests {
|
|
|
|
testDiffSame = {
|
|
|
|
expr = "abdef";
|
|
|
|
expected = "abdef";
|
|
|
|
};
|
|
|
|
testUpdateByPath1 = {
|
|
|
|
expr = configcreator.updateByPath ["a"] (x: x+1) {
|
|
|
|
a = 1;
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
expected = {
|
|
|
|
a = 2;
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
testUpdateByPath2 = {
|
|
|
|
expr = configcreator.updateByPath ["a" "a"] (x: x+1) {
|
|
|
|
a = {
|
|
|
|
a = 1;
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
expected = {
|
|
|
|
a = {
|
|
|
|
a = 2;
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
testUpdateByPath3 = {
|
|
|
|
expr = configcreator.updateByPath ["a" "a" "a"] (x: x+1) {
|
|
|
|
a = {
|
|
|
|
a = {
|
|
|
|
a = 1;
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
expected = {
|
|
|
|
a = {
|
|
|
|
a = {
|
|
|
|
a = 2;
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
b = 1;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
testRecursiveMerge1 = {
|
|
|
|
expr = configcreator.recursiveMerge [
|
|
|
|
{a = 1;}
|
|
|
|
{b = 2;}
|
|
|
|
];
|
|
|
|
expected = {
|
|
|
|
a = 1;
|
|
|
|
b = 2;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
testRecursiveMerge2 = {
|
|
|
|
expr = configcreator.recursiveMerge [
|
|
|
|
{a = {a = 1; b = 2;};}
|
|
|
|
{a = {a = 2;};}
|
|
|
|
];
|
|
|
|
expected = {
|
|
|
|
a = {a = 2; b = 2;};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
tesFlattenArgs1 = {
|
|
|
|
expr = configcreator.flattenAttrs {
|
|
|
|
a = 1;
|
|
|
|
b = 2;
|
|
|
|
};
|
|
|
|
expected = {
|
|
|
|
a = 1;
|
|
|
|
b = 2;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
tesFlattenArgs2 = {
|
|
|
|
expr = configcreator.flattenAttrs {
|
|
|
|
a = {
|
|
|
|
a = 1;
|
|
|
|
b = {
|
|
|
|
c = 3;
|
|
|
|
d = 4;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
b = 2;
|
|
|
|
};
|
|
|
|
expected = {
|
|
|
|
"a.a" = 1;
|
|
|
|
"a.b.c" = 3;
|
|
|
|
"a.b.d" = 4;
|
|
|
|
b = 2;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
testHaproxyConfigDefaultRender = {
|
|
|
|
expr = configcreator.render (configcreator.default {
|
|
|
|
user = "me";
|
|
|
|
group = "mygroup";
|
|
|
|
certPath = "/cert/path";
|
|
|
|
plugins = {
|
|
|
|
zone = {
|
|
|
|
luapaths = "lib";
|
|
|
|
source = pkgs.writeText "one.lua" "a binary";
|
|
|
|
};
|
|
|
|
two = {
|
|
|
|
load = "right/two.lua";
|
|
|
|
luapaths = ".";
|
|
|
|
cpaths = "right";
|
|
|
|
source = pkgs.writeText "two.lua" "a binary";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
globalEnvs = {
|
|
|
|
ABC = "hello";
|
|
|
|
};
|
|
|
|
stats = null;
|
|
|
|
debug = false;
|
|
|
|
});
|
|
|
|
expected = ''
|
|
|
|
global
|
|
|
|
group mygroup
|
|
|
|
log /dev/log local0 info
|
|
|
|
maxconn 20000
|
|
|
|
lua-prepend-path /nix/store/ybcka9g095hp8s1hnm2ncfh1hp56v9yq-haproxyplugins/two/?.lua path
|
|
|
|
lua-prepend-path /nix/store/ybcka9g095hp8s1hnm2ncfh1hp56v9yq-haproxyplugins/two/right/?.so cpath
|
|
|
|
lua-prepend-path /nix/store/ybcka9g095hp8s1hnm2ncfh1hp56v9yq-haproxyplugins/zone/lib/?.lua path
|
|
|
|
lua-load /nix/store/ybcka9g095hp8s1hnm2ncfh1hp56v9yq-haproxyplugins/two/right/two.lua
|
|
|
|
setenv ABC hello
|
|
|
|
tune.ssl.default-dh-param 2048
|
|
|
|
user me
|
|
|
|
|
|
|
|
defaults
|
|
|
|
log global
|
|
|
|
option httplog
|
|
|
|
timeout client 15s
|
|
|
|
timeout connect 10s
|
|
|
|
timeout queue 100s
|
|
|
|
timeout server 30s
|
|
|
|
|
|
|
|
frontend http-to-https
|
|
|
|
bind *:80
|
|
|
|
mode http
|
|
|
|
redirect scheme https code 301 if !{ ssl_fc }
|
|
|
|
|
|
|
|
frontend https
|
|
|
|
bind *:443 ssl crt /cert/path
|
|
|
|
http-request add-header X-Forwarded-Proto https
|
|
|
|
http-request set-header X-Forwarded-Port %[dst_port]
|
|
|
|
http-request set-header X-Forwarded-For %[src]
|
|
|
|
http-response set-header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload;"
|
|
|
|
mode http
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
testHaproxyConfigDefaultRenderWithStatsAndDebug = {
|
|
|
|
expr = configcreator.render (configcreator.default {
|
|
|
|
user = "me";
|
|
|
|
group = "mygroup";
|
|
|
|
certPath = "/cert/path";
|
|
|
|
stats = {
|
|
|
|
port = 8405;
|
|
|
|
uri = "/stats";
|
|
|
|
refresh = "10s";
|
|
|
|
prometheusUri = "/prom/etheus";
|
|
|
|
hide-version = true;
|
|
|
|
};
|
|
|
|
debug = true;
|
|
|
|
});
|
|
|
|
expected = ''
|
|
|
|
global
|
|
|
|
group mygroup
|
|
|
|
log /dev/log local0 info
|
|
|
|
maxconn 20000
|
|
|
|
tune.ssl.default-dh-param 2048
|
|
|
|
user me
|
|
|
|
|
|
|
|
defaults
|
|
|
|
log global
|
|
|
|
option httplog
|
|
|
|
timeout client 15s
|
|
|
|
timeout connect 10s
|
|
|
|
timeout queue 100s
|
|
|
|
timeout server 30s
|
|
|
|
|
|
|
|
frontend http-to-https
|
|
|
|
bind *:80
|
|
|
|
mode http
|
|
|
|
redirect scheme https code 301 if !{ ssl_fc }
|
|
|
|
|
|
|
|
frontend https
|
|
|
|
bind *:443 ssl crt /cert/path
|
|
|
|
http-request add-header X-Forwarded-Proto https
|
|
|
|
http-request set-header X-Forwarded-Port %[dst_port]
|
|
|
|
http-request set-header X-Forwarded-For %[src]
|
|
|
|
http-response set-header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload;"
|
|
|
|
log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r %sslv %sslc %[ssl_fc_cipherlist_str]"
|
|
|
|
mode http
|
|
|
|
|
|
|
|
frontend stats
|
|
|
|
bind localhost:8405
|
|
|
|
http-request use-service prometheus-exporter if { path /prom/etheus }
|
|
|
|
mode http
|
|
|
|
stats enable
|
|
|
|
stats hide-version
|
|
|
|
stats refresh 10s
|
|
|
|
stats uri /stats
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
testRenderHaproxyConfigWithSite = {
|
|
|
|
expr = configcreator.render (configcreator.default {
|
|
|
|
user = "me";
|
|
|
|
group = "mygroup";
|
|
|
|
certPath = "/cert/path";
|
|
|
|
stats = null;
|
|
|
|
debug = false;
|
|
|
|
sites = {
|
|
|
|
siteName = {
|
|
|
|
frontend = {
|
|
|
|
capture = [
|
|
|
|
"request header origin len 128"
|
|
|
|
];
|
|
|
|
acl = {
|
|
|
|
acl_siteName = "hdr_beg(host) siteName.";
|
|
|
|
acl_siteName_path = "path_beg /siteName";
|
|
|
|
};
|
|
|
|
http-response = {
|
|
|
|
add-header = [
|
|
|
|
"Access-Control-Allow-Origin1 $[capture]"
|
|
|
|
"Access-Control-Allow-Origin2 $[capture]"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
use_backend = "if acl_siteName OR acl_siteName_path";
|
|
|
|
};
|
|
|
|
backend = {
|
|
|
|
servers = [
|
|
|
|
{
|
|
|
|
name = "serviceName1";
|
|
|
|
address = "serviceSocket";
|
|
|
|
}
|
|
|
|
];
|
|
|
|
options = [
|
|
|
|
"cookie JSESSIONID prefix"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
expected = ''
|
|
|
|
global
|
|
|
|
group mygroup
|
|
|
|
log /dev/log local0 info
|
|
|
|
maxconn 20000
|
|
|
|
tune.ssl.default-dh-param 2048
|
|
|
|
user me
|
|
|
|
|
|
|
|
defaults
|
|
|
|
log global
|
|
|
|
option httplog
|
|
|
|
timeout client 15s
|
|
|
|
timeout connect 10s
|
|
|
|
timeout queue 100s
|
|
|
|
timeout server 30s
|
|
|
|
|
|
|
|
frontend http-to-https
|
|
|
|
bind *:80
|
|
|
|
mode http
|
|
|
|
redirect scheme https code 301 if !{ ssl_fc }
|
|
|
|
|
|
|
|
frontend https
|
|
|
|
acl acl_siteName hdr_beg(host) siteName.
|
|
|
|
acl acl_siteName_path path_beg /siteName
|
|
|
|
bind *:443 ssl crt /cert/path
|
|
|
|
capture request header origin len 128
|
|
|
|
http-request add-header X-Forwarded-Proto https
|
|
|
|
http-request set-header X-Forwarded-Port %[dst_port]
|
|
|
|
http-request set-header X-Forwarded-For %[src]
|
|
|
|
http-response add-header Access-Control-Allow-Origin1 $[capture]
|
|
|
|
http-response add-header Access-Control-Allow-Origin2 $[capture]
|
|
|
|
http-response set-header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload;"
|
|
|
|
mode http
|
|
|
|
use_backend siteName if acl_siteName OR acl_siteName_path
|
|
|
|
|
|
|
|
backend siteName
|
|
|
|
cookie JSESSIONID prefix
|
|
|
|
mode http
|
|
|
|
option forwardfor
|
|
|
|
server serviceName1 serviceSocket
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
testRenderHaproxyConfigWith2Sites = {
|
|
|
|
expr = configcreator.render (configcreator.default {
|
|
|
|
user = "me";
|
|
|
|
group = "mygroup";
|
|
|
|
certPath = "/cert/path";
|
|
|
|
stats = null;
|
|
|
|
debug = false;
|
|
|
|
sites = {
|
|
|
|
siteName = {
|
|
|
|
frontend = {
|
|
|
|
capture = [
|
|
|
|
"request header origin len 128"
|
|
|
|
];
|
|
|
|
acl = {
|
|
|
|
acl_siteName = "hdr_beg(host) siteName.";
|
|
|
|
acl_siteName_path = "path_beg /siteName";
|
|
|
|
};
|
|
|
|
http-response = {
|
|
|
|
add-header = [
|
|
|
|
"Access-Control-Allow-Origin1 $[capture]"
|
|
|
|
"Access-Control-Allow-Origin2 $[capture]"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
use_backend = "if acl_siteName OR acl_siteName_path";
|
|
|
|
};
|
|
|
|
backend = {
|
|
|
|
servers = [
|
|
|
|
{
|
|
|
|
name = "serviceName1";
|
|
|
|
address = "serviceSocket";
|
|
|
|
}
|
|
|
|
];
|
|
|
|
options = [
|
|
|
|
"cookie JSESSIONID prefix"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
siteName2 = {
|
|
|
|
frontend = {
|
|
|
|
capture = [
|
|
|
|
"request header origin len 128"
|
|
|
|
];
|
|
|
|
acl = {
|
|
|
|
acl_siteName2 = "hdr_beg(host) siteName2.";
|
|
|
|
acl_siteName2_path = "path_beg /siteName2";
|
|
|
|
};
|
|
|
|
http-response = {
|
|
|
|
add-header = [
|
|
|
|
"Access-Control-Allow-Origin3 $[capture]"
|
|
|
|
"Access-Control-Allow-Origin4 $[capture]"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
use_backend = "if acl_siteName2 OR acl_siteName2_path";
|
|
|
|
};
|
|
|
|
backend = {
|
|
|
|
servers = [
|
|
|
|
{
|
|
|
|
name = "serviceName2";
|
|
|
|
address = "serviceSocket";
|
|
|
|
}
|
|
|
|
];
|
|
|
|
options = [
|
|
|
|
"cookie JSESSIONID prefix"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
expected = ''
|
|
|
|
global
|
|
|
|
group mygroup
|
|
|
|
log /dev/log local0 info
|
|
|
|
maxconn 20000
|
|
|
|
tune.ssl.default-dh-param 2048
|
|
|
|
user me
|
|
|
|
|
|
|
|
defaults
|
|
|
|
log global
|
|
|
|
option httplog
|
|
|
|
timeout client 15s
|
|
|
|
timeout connect 10s
|
|
|
|
timeout queue 100s
|
|
|
|
timeout server 30s
|
|
|
|
|
|
|
|
frontend http-to-https
|
|
|
|
bind *:80
|
|
|
|
mode http
|
|
|
|
redirect scheme https code 301 if !{ ssl_fc }
|
|
|
|
|
|
|
|
frontend https
|
|
|
|
acl acl_siteName hdr_beg(host) siteName.
|
|
|
|
acl acl_siteName2 hdr_beg(host) siteName2.
|
|
|
|
acl acl_siteName2_path path_beg /siteName2
|
|
|
|
acl acl_siteName_path path_beg /siteName
|
|
|
|
bind *:443 ssl crt /cert/path
|
|
|
|
capture request header origin len 128
|
|
|
|
capture request header origin len 128
|
|
|
|
http-request add-header X-Forwarded-Proto https
|
|
|
|
http-request set-header X-Forwarded-Port %[dst_port]
|
|
|
|
http-request set-header X-Forwarded-For %[src]
|
|
|
|
http-response add-header Access-Control-Allow-Origin1 $[capture]
|
|
|
|
http-response add-header Access-Control-Allow-Origin2 $[capture]
|
|
|
|
http-response add-header Access-Control-Allow-Origin3 $[capture]
|
|
|
|
http-response add-header Access-Control-Allow-Origin4 $[capture]
|
|
|
|
http-response set-header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload;"
|
|
|
|
mode http
|
|
|
|
use_backend siteName if acl_siteName OR acl_siteName_path
|
|
|
|
use_backend siteName2 if acl_siteName2 OR acl_siteName2_path
|
|
|
|
|
|
|
|
backend siteName
|
|
|
|
cookie JSESSIONID prefix
|
|
|
|
mode http
|
|
|
|
option forwardfor
|
|
|
|
server serviceName1 serviceSocket
|
|
|
|
|
|
|
|
backend siteName2
|
|
|
|
cookie JSESSIONID prefix
|
|
|
|
mode http
|
|
|
|
option forwardfor
|
|
|
|
server serviceName2 serviceSocket
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
testRenderHaproxyConfigWithSiteDebugHeaders = {
|
|
|
|
expr = configcreator.render (configcreator.default {
|
|
|
|
user = "me";
|
|
|
|
group = "mygroup";
|
|
|
|
certPath = "/cert/path";
|
|
|
|
stats = null;
|
|
|
|
debug = false;
|
|
|
|
sites = {
|
|
|
|
siteName = {
|
|
|
|
frontend = {
|
|
|
|
capture = [
|
|
|
|
"request header origin len 128"
|
|
|
|
];
|
|
|
|
acl = {
|
|
|
|
acl_siteName = "hdr_beg(host) siteName.";
|
|
|
|
acl_siteName_path = "path_beg /siteName";
|
|
|
|
};
|
|
|
|
http-response = {
|
|
|
|
add-header = [
|
|
|
|
"Access-Control-Allow-Origin1 $[capture]"
|
|
|
|
"Access-Control-Allow-Origin2 $[capture]"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
use_backend = "if acl_siteName OR acl_siteName_path";
|
|
|
|
};
|
|
|
|
backend = {
|
|
|
|
servers = [
|
|
|
|
{
|
|
|
|
name = "serviceName1";
|
|
|
|
address = "serviceSocket";
|
|
|
|
}
|
|
|
|
];
|
|
|
|
options = [
|
|
|
|
"cookie JSESSIONID prefix"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
debugHeaders = "acl_siteName";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
expected = ''
|
|
|
|
global
|
|
|
|
group mygroup
|
|
|
|
log /dev/log local0 info
|
|
|
|
maxconn 20000
|
|
|
|
tune.ssl.default-dh-param 2048
|
|
|
|
user me
|
|
|
|
|
|
|
|
defaults
|
|
|
|
log global
|
|
|
|
option httplog
|
|
|
|
timeout client 15s
|
|
|
|
timeout connect 10s
|
|
|
|
timeout queue 100s
|
|
|
|
timeout server 30s
|
|
|
|
|
|
|
|
frontend http-to-https
|
|
|
|
bind *:80
|
|
|
|
mode http
|
|
|
|
redirect scheme https code 301 if !{ ssl_fc }
|
|
|
|
|
|
|
|
frontend https
|
|
|
|
acl acl_siteName hdr_beg(host) siteName.
|
|
|
|
acl acl_siteName_path path_beg /siteName
|
|
|
|
bind *:443 ssl crt /cert/path
|
|
|
|
capture request header origin len 128
|
|
|
|
http-request add-header X-Forwarded-Proto https
|
|
|
|
http-request capture req.hdrs len 512 if acl_siteName
|
|
|
|
http-request set-header X-Forwarded-Port %[dst_port]
|
|
|
|
http-request set-header X-Forwarded-For %[src]
|
|
|
|
http-response add-header Access-Control-Allow-Origin1 $[capture]
|
|
|
|
http-response add-header Access-Control-Allow-Origin2 $[capture]
|
|
|
|
http-response set-header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload;"
|
|
|
|
log-format "%ci:%cp [%tr] %ft [[%hr]] %hs %{+Q}r"
|
|
|
|
mode http
|
|
|
|
option httplog
|
|
|
|
use_backend siteName if acl_siteName OR acl_siteName_path
|
|
|
|
|
|
|
|
backend siteName
|
|
|
|
cookie JSESSIONID prefix
|
|
|
|
mode http
|
|
|
|
option forwardfor
|
|
|
|
server serviceName1 serviceSocket
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
}
|