[tests] add tests
This commit is contained in:
parent
e2b3a1d944
commit
642f8e9793
10 changed files with 1470 additions and 0 deletions
26
default.nix
Normal file
26
default.nix
Normal file
|
@ -0,0 +1,26 @@
|
|||
{ pkgs ? import <nixpkgs> {}
|
||||
}:
|
||||
let
|
||||
utils = pkgs.callPackage ./utils.nix {};
|
||||
in
|
||||
with builtins;
|
||||
with pkgs.lib.attrsets;
|
||||
with pkgs.lib.lists;
|
||||
with pkgs.lib.strings;
|
||||
rec {
|
||||
tests = pkgs.callPackage ./tests { inherit utils; };
|
||||
|
||||
runtests =
|
||||
let
|
||||
onlytests = filterAttrs (name: value: name != "override" && name != "overrideDerivation") tests;
|
||||
failingtests = filterAttrs (name: value: length value > 0) onlytests;
|
||||
formatFailure = failure: toString failure; # TODO: make this more pretty
|
||||
formattedFailureGroups = mapAttrsToList (name: failures: "${name}:\n${concatMapStringsSep "\n" formatFailure failures}") failingtests;
|
||||
in
|
||||
if length formattedFailureGroups == 0 then
|
||||
"no failing test"
|
||||
else
|
||||
concatStringsSep "\n" formattedFailureGroups;
|
||||
|
||||
disnixtests = pkgs.callPackage ./tests/disnix/keycloak.nix {};
|
||||
}
|
12
tests/default.nix
Normal file
12
tests/default.nix
Normal file
|
@ -0,0 +1,12 @@
|
|||
# to run all tests:
|
||||
# nix-instantiate --eval --strict . -A tests
|
||||
|
||||
{ pkgs
|
||||
, utils
|
||||
}:
|
||||
|
||||
{
|
||||
haproxy = pkgs.callPackage ./haproxy.nix { inherit utils; };
|
||||
keycloak = pkgs.callPackage ./keycloak.nix {};
|
||||
keycloak-cli-config = pkgs.callPackage ./keycloak-cli-config.nix {};
|
||||
}
|
93
tests/disnix/keycloak.nix
Normal file
93
tests/disnix/keycloak.nix
Normal file
|
@ -0,0 +1,93 @@
|
|||
{ nixpkgs ? <nixpkgs>
|
||||
, system ? builtins.currentSystem
|
||||
}:
|
||||
|
||||
let
|
||||
pkgs = import nixpkgs {inherit system;};
|
||||
|
||||
disnixos = import "${pkgs.disnixos}/share/disnixos/testing.nix" {
|
||||
inherit nixpkgs system;
|
||||
};
|
||||
|
||||
version = "1.0";
|
||||
in
|
||||
|
||||
rec {
|
||||
tarball = disnixos.sourceTarball {
|
||||
name = "testproject-zip";
|
||||
inherit version;
|
||||
src = ./.;
|
||||
officialRelease = false;
|
||||
};
|
||||
|
||||
manifest =
|
||||
disnixos.buildManifest {
|
||||
name = "test-project-manifest";
|
||||
version = builtins.readFile ./version;
|
||||
inherit tarball;
|
||||
servicesFile = "keycloak/services.nix";
|
||||
networkFile = "keycloak/network.nix";
|
||||
distributionFile = "keycloak/distribution.nix";
|
||||
};
|
||||
|
||||
tests =
|
||||
disnixos.disnixTest {
|
||||
name = "test-project-tests";
|
||||
inherit tarball manifest;
|
||||
networkFile = "keycloak/network.nix";
|
||||
dysnomiaStateDir = /var/state/dysnomia;
|
||||
testScript =
|
||||
''
|
||||
# Wait until the front-end application is deployed
|
||||
$test1->waitForFile("/var/tomcat/webapps/testapp");
|
||||
|
||||
# Wait a little longer and capture the output of the entry page
|
||||
my $result = $test1->mustSucceed("sleep 10; curl --fail http://test2:8080/testapp");
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
# let
|
||||
# utils = import ../../utils.nix {
|
||||
# inherit pkgs;
|
||||
# inherit (pkgs) stdenv lib;
|
||||
# };
|
||||
# keycloak = import ../../pkgs/keycloak/unit.nix {
|
||||
# inherit pkgs utils;
|
||||
# inherit (pkgs) stdenv lib;
|
||||
# };
|
||||
# in
|
||||
# makeTest {
|
||||
# nodes = {
|
||||
# machine = {config, pkgs, ...}:
|
||||
# {
|
||||
# virtualisation.memorySize = 1024;
|
||||
# virtualisation.diskSize = 4096;
|
||||
|
||||
# environment.systemPackages = [ dysnomia pkgs.curl ];
|
||||
# };
|
||||
# };
|
||||
# testScript = ''
|
||||
# def check_keycloak_activated():
|
||||
# machine.succeed("sleep 5")
|
||||
# machine.succeed("curl --fail http://keycloak.test.tiserbox.com")
|
||||
|
||||
# def check_keycloak_deactivated():
|
||||
# machine.succeed("sleep 5")
|
||||
# machine.fail("curl --fail http://keycloak.test.tiserbox.com")
|
||||
|
||||
# start_all()
|
||||
|
||||
# # Test the keycloak module. Start keycloak and see if we can query the endpoint.
|
||||
# machine.succeed(
|
||||
# "dysnomia --type docker-container --operation activate --component ${keycloak} --environment"
|
||||
# )
|
||||
# check_keycloak_activated()
|
||||
|
||||
# # Deactivate keycloak. Check if it is not running anymore
|
||||
# machine.succeed(
|
||||
# "dysnomia --type docker-container --operation deactivate --component ${keycloak} --environment"
|
||||
# )
|
||||
# check_keycloak_deactivated()
|
||||
# '';
|
||||
# }
|
7
tests/disnix/keycloak/distribution.nix
Normal file
7
tests/disnix/keycloak/distribution.nix
Normal file
|
@ -0,0 +1,7 @@
|
|||
{ infrastructure }:
|
||||
|
||||
with infrastructure;
|
||||
{
|
||||
KeycloakPostgresDB = [ test1 ];
|
||||
KeycloakService = [ test1 ];
|
||||
}
|
75
tests/disnix/keycloak/network.nix
Normal file
75
tests/disnix/keycloak/network.nix
Normal file
|
@ -0,0 +1,75 @@
|
|||
rec {
|
||||
test1 = { system
|
||||
, pkgs
|
||||
, lib
|
||||
, ... }:
|
||||
let
|
||||
domain = "local";
|
||||
|
||||
utils = pkgs.lib.callPackageWith pkgs ../../../utils.nix { };
|
||||
|
||||
customPkgs = import ../../../pkgs/all-packages.nix {
|
||||
inherit system pkgs utils;
|
||||
};
|
||||
in
|
||||
rec {
|
||||
users.groups = {
|
||||
keycloak = {
|
||||
name = "keycloak";
|
||||
};
|
||||
};
|
||||
users.users = {
|
||||
keycloak = {
|
||||
name = "keycloak";
|
||||
group = "keycloak";
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
deployment.keys = {
|
||||
keycloakinitialadmin.text = ''
|
||||
KEYCLOAK_ADMIN_PASSWORD="${builtins.extraBuiltins.pass "keycloak.${domain}/admin"}"
|
||||
'';
|
||||
};
|
||||
|
||||
services = {
|
||||
openssh = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
disnix = {
|
||||
enable = true;
|
||||
# useWebServiceInterface = true;
|
||||
};
|
||||
|
||||
postgresql = {
|
||||
enable = true;
|
||||
package = pkgs.postgresql_14;
|
||||
|
||||
port = 5432;
|
||||
enableTCPIP = true;
|
||||
authentication = pkgs.lib.mkOverride 10 ''
|
||||
local all all trust
|
||||
host all all 127.0.0.1/32 trust
|
||||
host all all ::1/128 trust
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
dysnomia = {
|
||||
enable = true;
|
||||
enableLegacyModules = false;
|
||||
extraContainerProperties = {
|
||||
system = {
|
||||
inherit domain;
|
||||
};
|
||||
postgresql-database = {
|
||||
service_name = "postgresql.service";
|
||||
port = builtins.toString services.postgresql.port;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ services.postgresql.port ];
|
||||
};
|
||||
}
|
45
tests/disnix/keycloak/services.nix
Normal file
45
tests/disnix/keycloak/services.nix
Normal file
|
@ -0,0 +1,45 @@
|
|||
{ system, pkgs, distribution, invDistribution }:
|
||||
|
||||
let
|
||||
utils = pkgs.lib.callPackageWith pkgs ../../../utils.nix { };
|
||||
|
||||
customPkgs = import ../../../pkgs/all-packages.nix {
|
||||
inherit system pkgs utils;
|
||||
};
|
||||
in
|
||||
{
|
||||
KeycloakPostgresDB = customPkgs.mkPostgresDB {
|
||||
name = "KeycloakPostgresDB";
|
||||
database = "keycloak";
|
||||
username = "keycloak";
|
||||
# TODO: use passwordFile
|
||||
password = "keycloak";
|
||||
};
|
||||
|
||||
KeycloakService = customPkgs.mkKeycloakService {
|
||||
name = "KeycloakService";
|
||||
|
||||
# Get these from infrastructure.nix
|
||||
user = "keycloak";
|
||||
group = "keycloak";
|
||||
|
||||
postgresServiceName = (utils.getTarget "KeycloakPostgresDB").containers.postgresql-database.service_name;
|
||||
initialAdminUsername = "admin";
|
||||
|
||||
keys = {
|
||||
dbPassword = "keycloakdbpassword";
|
||||
initialAdminPassword = "keycloakinitialadmin";
|
||||
};
|
||||
|
||||
logLevel = "INFO";
|
||||
hostname = "keycloak.${getDomain "KeycloakService"}";
|
||||
|
||||
dbType = "postgres";
|
||||
dbDatabase = KeycloakPostgresDB.database;
|
||||
dbUsername = KeycloakPostgresDB.username;
|
||||
dbHost = {KeycloakPostgresDB}: KeycloakPostgresDB.target.properties.hostname;
|
||||
dbPort = (getTarget "KeycloakPostgresDB").containers.postgresql-database.port;
|
||||
|
||||
inherit KeycloakPostgresDB;
|
||||
};
|
||||
}
|
549
tests/haproxy.nix
Normal file
549
tests/haproxy.nix
Normal file
|
@ -0,0 +1,549 @@
|
|||
# to run these tests:
|
||||
# nix-instantiate --eval --strict . -A tests.haproxy
|
||||
|
||||
{ lib
|
||||
, stdenv
|
||||
, pkgs
|
||||
, utils
|
||||
}:
|
||||
|
||||
let
|
||||
configcreator = pkgs.callPackage ./../haproxy/configcreator.nix { inherit utils; };
|
||||
mksiteconfig = pkgs.callPackage ./../haproxy/siteconfig.nix {};
|
||||
|
||||
diff = testResult:
|
||||
with builtins;
|
||||
with lib.strings;
|
||||
if isString testResult.expected && isString testResult.result then
|
||||
let
|
||||
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
|
||||
'';
|
||||
};
|
||||
}
|
343
tests/keycloak-cli-config.nix
Normal file
343
tests/keycloak-cli-config.nix
Normal file
|
@ -0,0 +1,343 @@
|
|||
# to run these tests:
|
||||
# nix-instantiate --eval --strict . -A tests.keycloak-cli-config
|
||||
|
||||
{ lib
|
||||
, stdenv
|
||||
, pkgs
|
||||
}:
|
||||
|
||||
let
|
||||
configcreator = pkgs.callPackage ./../keycloak-cli-config/configcreator.nix { };
|
||||
|
||||
default_config = {
|
||||
realm = "myrealm";
|
||||
domain = "mydomain.com";
|
||||
};
|
||||
|
||||
keep_fields = fields:
|
||||
lib.filterAttrs (n: v: lib.any (n_: n_ == n) fields);
|
||||
in
|
||||
|
||||
lib.runTests {
|
||||
testDefault = {
|
||||
expr = configcreator default_config;
|
||||
|
||||
expected = {
|
||||
id = "myrealm";
|
||||
realm = "myrealm";
|
||||
enabled = true;
|
||||
clients = [];
|
||||
roles = {
|
||||
realm = [];
|
||||
client = {};
|
||||
};
|
||||
groups = [];
|
||||
users = [];
|
||||
};
|
||||
};
|
||||
|
||||
testUsers = {
|
||||
expr = (configcreator (default_config // {
|
||||
users = {
|
||||
me = {
|
||||
email = "me@mydomain.com";
|
||||
firstName = "me";
|
||||
lastName = "stillme";
|
||||
};
|
||||
};
|
||||
})).users;
|
||||
|
||||
expected = [
|
||||
{
|
||||
username = "me";
|
||||
enabled = true;
|
||||
email = "me@mydomain.com";
|
||||
emailVerified = true;
|
||||
firstName = "me";
|
||||
lastName = "stillme";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
testUsersWithGroups = {
|
||||
expr = (configcreator (default_config // {
|
||||
users = {
|
||||
me = {
|
||||
email = "me@mydomain.com";
|
||||
firstName = "me";
|
||||
lastName = "stillme";
|
||||
groups = [ "MyGroup" ];
|
||||
};
|
||||
};
|
||||
})).users;
|
||||
|
||||
expected = [
|
||||
{
|
||||
username = "me";
|
||||
enabled = true;
|
||||
email = "me@mydomain.com";
|
||||
emailVerified = true;
|
||||
firstName = "me";
|
||||
lastName = "stillme";
|
||||
groups = [ "MyGroup" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
testUsersWithRoles = {
|
||||
expr = (configcreator (default_config // {
|
||||
users = {
|
||||
me = {
|
||||
email = "me@mydomain.com";
|
||||
firstName = "me";
|
||||
lastName = "stillme";
|
||||
roles = [ "MyRole" ];
|
||||
};
|
||||
};
|
||||
})).users;
|
||||
|
||||
expected = [
|
||||
{
|
||||
username = "me";
|
||||
enabled = true;
|
||||
email = "me@mydomain.com";
|
||||
emailVerified = true;
|
||||
firstName = "me";
|
||||
lastName = "stillme";
|
||||
realmRoles = [ "MyRole" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
testUsersWithInitialPassword = {
|
||||
expr = (configcreator (default_config // {
|
||||
users = {
|
||||
me = {
|
||||
email = "me@mydomain.com";
|
||||
firstName = "me";
|
||||
lastName = "stillme";
|
||||
initialPassword = true;
|
||||
};
|
||||
};
|
||||
})).users;
|
||||
|
||||
expected = [
|
||||
{
|
||||
username = "me";
|
||||
enabled = true;
|
||||
email = "me@mydomain.com";
|
||||
emailVerified = true;
|
||||
firstName = "me";
|
||||
lastName = "stillme";
|
||||
credentials = [
|
||||
{
|
||||
type = "password";
|
||||
userLabel = "initial";
|
||||
value = "$(keycloak.users.me.password)";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
testGroups = {
|
||||
expr = (configcreator (default_config // {
|
||||
groups = [ "MyGroup" ];
|
||||
})).groups;
|
||||
|
||||
expected = [
|
||||
{
|
||||
name = "MyGroup";
|
||||
path = "/MyGroup";
|
||||
attributes = {};
|
||||
realmRoles = [];
|
||||
clientRoles = {};
|
||||
subGroups = [];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
testRealmRoles = {
|
||||
expr = (configcreator (default_config // {
|
||||
roles = {
|
||||
A = [ "B" ];
|
||||
B = [ ];
|
||||
};
|
||||
})).roles;
|
||||
|
||||
expected = {
|
||||
client = {};
|
||||
realm = [
|
||||
{
|
||||
name = "A";
|
||||
composite = true;
|
||||
composites = {
|
||||
realm = [ "B" ];
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "B";
|
||||
composite = false;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testClientRoles = {
|
||||
expr = (configcreator (default_config // {
|
||||
clients = {
|
||||
clientA = {
|
||||
roles = [ "cA" ];
|
||||
};
|
||||
};
|
||||
})).roles;
|
||||
|
||||
expected = {
|
||||
client = {
|
||||
clientA = [
|
||||
{
|
||||
name = "cA";
|
||||
clientRole = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
realm = [];
|
||||
};
|
||||
};
|
||||
|
||||
testClient = {
|
||||
expr = map (keep_fields [
|
||||
"clientId"
|
||||
"rootUrl"
|
||||
"redirectUris"
|
||||
"webOrigins"
|
||||
"authorizationSettings"
|
||||
]) (configcreator (default_config // {
|
||||
clients = {
|
||||
clientA = {};
|
||||
};
|
||||
})).clients;
|
||||
expected = [
|
||||
{
|
||||
clientId = "clientA";
|
||||
rootUrl = "https://clientA.mydomain.com";
|
||||
redirectUris = ["https://clientA.mydomain.com/oauth2/callback"];
|
||||
webOrigins = ["https://clientA.mydomain.com"];
|
||||
authorizationSettings = {
|
||||
policyEnforcementMode = "ENFORCING";
|
||||
resources = [];
|
||||
policies = [];
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
testClientAuthorization = with builtins; {
|
||||
expr = (head (configcreator (default_config // {
|
||||
clients = {
|
||||
clientA = {
|
||||
resourcesUris = {
|
||||
adminPath = ["/admin/*"];
|
||||
userPath = ["/*"];
|
||||
};
|
||||
access = {
|
||||
admin = {
|
||||
roles = [ "admin" ];
|
||||
resources = [ "adminPath" ];
|
||||
};
|
||||
user = {
|
||||
roles = [ "user" ];
|
||||
resources = [ "userPath" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
})).clients).authorizationSettings;
|
||||
expected = {
|
||||
policyEnforcementMode = "ENFORCING";
|
||||
resources = [
|
||||
{
|
||||
name = "adminPath";
|
||||
type = "urn:clientA:resources:adminPath";
|
||||
ownerManagedAccess = false;
|
||||
uris = ["/admin/*"];
|
||||
}
|
||||
{
|
||||
name = "userPath";
|
||||
type = "urn:clientA:resources:userPath";
|
||||
ownerManagedAccess = false;
|
||||
uris = ["/*"];
|
||||
}
|
||||
];
|
||||
policies = [
|
||||
{
|
||||
name = "admin has access";
|
||||
type = "role";
|
||||
logic = "POSITIVE";
|
||||
decisionStrategy = "UNANIMOUS";
|
||||
config = {
|
||||
roles = ''[{"id":"admin","required":true}]'';
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "user has access";
|
||||
type = "role";
|
||||
logic = "POSITIVE";
|
||||
decisionStrategy = "UNANIMOUS";
|
||||
config = {
|
||||
roles = ''[{"id":"user","required":true}]'';
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "admin has access to adminPath";
|
||||
type = "resource";
|
||||
logic = "POSITIVE";
|
||||
decisionStrategy = "UNANIMOUS";
|
||||
config = {
|
||||
resources = ''["adminPath"]'';
|
||||
applyPolicies = ''["admin has access"]'';
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "user has access to userPath";
|
||||
type = "resource";
|
||||
logic = "POSITIVE";
|
||||
decisionStrategy = "UNANIMOUS";
|
||||
config = {
|
||||
resources = ''["userPath"]'';
|
||||
applyPolicies = ''["user has access"]'';
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testClientAudience =
|
||||
let
|
||||
audienceProtocolMapper = config:
|
||||
with builtins;
|
||||
let
|
||||
protocolMappers = (head config.clients).protocolMappers;
|
||||
protocolMapperByName = name: protocolMappers: head (filter (x: x.name == name) protocolMappers);
|
||||
in
|
||||
protocolMapperByName "Audience" protocolMappers;
|
||||
in
|
||||
{
|
||||
expr = audienceProtocolMapper (configcreator (default_config // {
|
||||
clients = {
|
||||
clientA = {};
|
||||
};
|
||||
}));
|
||||
expected = {
|
||||
name = "Audience";
|
||||
protocol = "openid-connect";
|
||||
protocolMapper = "oidc-audience-mapper";
|
||||
config = {
|
||||
"included.client.audience" = "clientA";
|
||||
"id.token.claim" = "false";
|
||||
"access.token.claim" = "true";
|
||||
"included.custom.audience" = "clientA";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
232
tests/keycloak.nix
Normal file
232
tests/keycloak.nix
Normal file
|
@ -0,0 +1,232 @@
|
|||
# to run these tests:
|
||||
# nix-instantiate --eval --strict . -A tests.keycloak
|
||||
|
||||
{ lib
|
||||
, stdenv
|
||||
, pkgs
|
||||
}:
|
||||
|
||||
let
|
||||
configcreator = pkgs.callPackage ./../keycloak-cli-config/configcreator.nix {};
|
||||
in
|
||||
|
||||
with lib.attrsets;
|
||||
lib.runTests {
|
||||
testConfigEmpty = {
|
||||
expr = configcreator {
|
||||
realm = "myrealm";
|
||||
domain = "domain.com";
|
||||
};
|
||||
expected = {
|
||||
id = "myrealm";
|
||||
realm = "myrealm";
|
||||
enabled = true;
|
||||
clients = [];
|
||||
groups = [];
|
||||
roles = {
|
||||
client = {};
|
||||
realm = [];
|
||||
};
|
||||
users = [];
|
||||
};
|
||||
};
|
||||
|
||||
testConfigRole = {
|
||||
expr = configcreator {
|
||||
realm = "myrealm";
|
||||
domain = "domain.com";
|
||||
roles = {
|
||||
user = [];
|
||||
admin = ["user"];
|
||||
};
|
||||
};
|
||||
expected = {
|
||||
id = "myrealm";
|
||||
realm = "myrealm";
|
||||
enabled = true;
|
||||
clients = [];
|
||||
groups = [];
|
||||
roles = {
|
||||
realm = [
|
||||
{
|
||||
name = "admin";
|
||||
composite = true;
|
||||
composites = {
|
||||
realm = ["user"];
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "user";
|
||||
composite = false;
|
||||
}
|
||||
];
|
||||
client = {};
|
||||
};
|
||||
users = [];
|
||||
};
|
||||
};
|
||||
|
||||
testConfigClient = {
|
||||
expr =
|
||||
let
|
||||
c = configcreator {
|
||||
realm = "myrealm";
|
||||
domain = "domain.com";
|
||||
clients = {
|
||||
myclient = {};
|
||||
myclient2 = {
|
||||
roles = ["uma"];
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
updateManyAttrsByPath [
|
||||
{
|
||||
path = [ "clients" ];
|
||||
# We don't care about the value of the protocolMappers
|
||||
# field because its value is hardcoded.
|
||||
update = clients: map (filterAttrs (n: v: n != "protocolMappers")) clients;
|
||||
}
|
||||
] c;
|
||||
expected = {
|
||||
id = "myrealm";
|
||||
realm = "myrealm";
|
||||
enabled = true;
|
||||
clients = [
|
||||
{
|
||||
clientId = "myclient";
|
||||
rootUrl = "https://myclient.domain.com";
|
||||
clientAuthenticatorType = "client-secret";
|
||||
redirectUris = [
|
||||
"https://myclient.domain.com/oauth2/callback"
|
||||
];
|
||||
webOrigins = [
|
||||
"https://myclient.domain.com"
|
||||
];
|
||||
authorizationServicesEnabled = true;
|
||||
serviceAccountsEnabled = true;
|
||||
protocol = "openid-connect";
|
||||
publicClient = false;
|
||||
authorizationSettings = {
|
||||
policyEnforcementMode = "ENFORCING";
|
||||
resources = [];
|
||||
policies = [];
|
||||
};
|
||||
}
|
||||
{
|
||||
clientId = "myclient2";
|
||||
rootUrl = "https://myclient2.domain.com";
|
||||
clientAuthenticatorType = "client-secret";
|
||||
redirectUris = [
|
||||
"https://myclient2.domain.com/oauth2/callback"
|
||||
];
|
||||
webOrigins = [
|
||||
"https://myclient2.domain.com"
|
||||
];
|
||||
authorizationServicesEnabled = true;
|
||||
serviceAccountsEnabled = true;
|
||||
protocol = "openid-connect";
|
||||
publicClient = false;
|
||||
authorizationSettings = {
|
||||
policyEnforcementMode = "ENFORCING";
|
||||
resources = [];
|
||||
policies = [];
|
||||
};
|
||||
}
|
||||
];
|
||||
groups = [];
|
||||
roles = {
|
||||
client = {
|
||||
myclient = [];
|
||||
myclient2 = [
|
||||
{
|
||||
name = "uma";
|
||||
clientRole = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
realm = [];
|
||||
};
|
||||
users = [];
|
||||
};
|
||||
};
|
||||
|
||||
testConfigUser = {
|
||||
expr = configcreator {
|
||||
realm = "myrealm";
|
||||
domain = "domain.com";
|
||||
users = {
|
||||
me = {
|
||||
email = "me@me.com";
|
||||
firstName = null;
|
||||
lastName = "Me";
|
||||
realmRoles = [ "role" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
expected = {
|
||||
id = "myrealm";
|
||||
realm = "myrealm";
|
||||
enabled = true;
|
||||
clients = [];
|
||||
groups = [];
|
||||
roles = {
|
||||
client = {};
|
||||
realm = [];
|
||||
};
|
||||
users = [
|
||||
{
|
||||
enabled = true;
|
||||
username = "me";
|
||||
email = "me@me.com";
|
||||
emailVerified = true;
|
||||
firstName = null;
|
||||
lastName = "Me";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testConfigUserInitialPassword = {
|
||||
expr = configcreator {
|
||||
realm = "myrealm";
|
||||
domain = "domain.com";
|
||||
users = {
|
||||
me = {
|
||||
email = "me@me.com";
|
||||
firstName = null;
|
||||
lastName = "Me";
|
||||
initialPassword = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
expected = {
|
||||
id = "myrealm";
|
||||
realm = "myrealm";
|
||||
enabled = true;
|
||||
clients = [];
|
||||
groups = [];
|
||||
roles = {
|
||||
client = {};
|
||||
realm = [];
|
||||
};
|
||||
users = [
|
||||
{
|
||||
enabled = true;
|
||||
username = "me";
|
||||
email = "me@me.com";
|
||||
emailVerified = true;
|
||||
firstName = null;
|
||||
lastName = "Me";
|
||||
credentials = [
|
||||
{
|
||||
type = "password";
|
||||
userLabel = "initial";
|
||||
value = "$(keycloak.users.me.password)";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
88
utils.nix
Normal file
88
utils.nix
Normal file
|
@ -0,0 +1,88 @@
|
|||
{ stdenv
|
||||
, pkgs
|
||||
, lib
|
||||
}:
|
||||
|
||||
with lib;
|
||||
with lib.lists;
|
||||
with lib.attrsets;
|
||||
rec {
|
||||
tmpFilesFromDirectories = user: group: d:
|
||||
let
|
||||
wrapTmpfiles = dir: mode: "d '${dir}' ${mode} ${user} ${group} - -";
|
||||
in
|
||||
mapAttrsToList wrapTmpfiles d;
|
||||
|
||||
systemd = {
|
||||
mkService = {name, content, timer ? null}: stdenv.mkDerivation {
|
||||
inherit name;
|
||||
|
||||
src = pkgs.writeTextDir "${name}.service" content;
|
||||
timerSrc = pkgs.writeTextDir "${name}.timer" timer;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/etc/systemd/system
|
||||
cp $src/*.service $out/etc/systemd/system
|
||||
'' + (if timer == null then "" else ''
|
||||
cp $timerSrc/*.timer $out/etc/systemd/system
|
||||
'');
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
mkConfigFile = {dir, name, content}: stdenv.mkDerivation rec {
|
||||
inherit name;
|
||||
|
||||
src = pkgs.writeTextDir name content;
|
||||
|
||||
buildCommand = ''
|
||||
mkdir -p $out
|
||||
cp ${src}/${name} $out/${name}
|
||||
|
||||
echo "${dir}" > $out/.dysnomia-targetdir
|
||||
|
||||
cat > $out/.dysnomia-fileset <<FILESET
|
||||
symlink $out/${name}
|
||||
target .
|
||||
FILESET
|
||||
'';
|
||||
|
||||
};
|
||||
|
||||
dnsmasqConfig = domain: subdomains:
|
||||
''
|
||||
${concatMapStringsSep "\n" (x: "address=/${x}.${domain}/127.0.0.1") subdomains}
|
||||
domain=${domain}
|
||||
'';
|
||||
|
||||
keyEnvironmentFile = path: "EnvironmentFile=/run/keys/${path}";
|
||||
keyEnvironmentFiles = names: concatMapStrings (path: "${keyEnvironmentFile path}\n") (attrValues names);
|
||||
keyServiceDependencies = names: concatMapStringsSep " " (path: "${path}-key.service") (attrValues names);
|
||||
|
||||
recursiveMerge = attrList:
|
||||
let f = attrPath:
|
||||
zipAttrsWith (n: values:
|
||||
if all isList values then
|
||||
concatLists values
|
||||
else if all isAttrs values then
|
||||
f (attrPath ++ [n]) values
|
||||
else
|
||||
last values
|
||||
);
|
||||
in f [] attrList;
|
||||
|
||||
getTarget = distribution: name: builtins.elemAt (builtins.getAttr name distribution) 0;
|
||||
|
||||
getDomain = distribution: name: (getTarget distribution name).containers.system.domain;
|
||||
|
||||
unitDepends = verb: dependsOn:
|
||||
let
|
||||
withSystemdUnitFile = filter (hasAttr "systemdUnitFile") (attrValues dependsOn);
|
||||
|
||||
systemdUnitFiles = map (x: x.systemdUnitFile) withSystemdUnitFile;
|
||||
in
|
||||
if length systemdUnitFiles == 0 then
|
||||
""
|
||||
else
|
||||
"${verb}=${concatStringsSep " " systemdUnitFiles}";
|
||||
}
|
Loading…
Reference in a new issue