feat(registry): validate unique addresses and routes #66
127
flake.nix
127
flake.nix
@@ -403,6 +403,38 @@
|
||||
touch $out
|
||||
'';
|
||||
|
||||
address-registry-duplicate-value-fails =
|
||||
let
|
||||
alpha = lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
specialArgs.my = self.lib;
|
||||
modules = [
|
||||
self.lib.registry.module
|
||||
{
|
||||
registry.address.alpha.self = "10.23.50.146";
|
||||
system.stateVersion = "26.11";
|
||||
}
|
||||
];
|
||||
};
|
||||
beta = lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
specialArgs.my = self.lib;
|
||||
modules = [
|
||||
self.lib.registry.module
|
||||
{
|
||||
registry.address.beta.self = "10.23.50.146";
|
||||
system.stateVersion = "26.11";
|
||||
}
|
||||
];
|
||||
};
|
||||
registry = self.lib.registry.collect { hosts = { inherit alpha beta; }; };
|
||||
result = builtins.tryEval (builtins.deepSeq registry.address true);
|
||||
in
|
||||
pkgs.runCommand "address-registry-duplicate-value-fails-check" { } ''
|
||||
${lib.optionalString result.success "exit 1"}
|
||||
touch $out
|
||||
'';
|
||||
|
||||
ssh-targets-use-address-registry =
|
||||
let
|
||||
neogaiaConfig = self.nixosConfigurations.neogaia.config;
|
||||
@@ -434,7 +466,7 @@
|
||||
modules = [
|
||||
self.lib.registry.module
|
||||
{
|
||||
registry.address.routeHost.app = "10.23.20.126";
|
||||
registry.address.routeHost.app = "10.23.20.127";
|
||||
registry.route.routeHost.app = {
|
||||
domain = "worker.alexion.dev";
|
||||
port = 3923;
|
||||
@@ -472,7 +504,7 @@
|
||||
registry.route ? routeHost
|
||||
&& registry.route.routeHost ? app
|
||||
&& registry.route.pikachu ? actualbudget
|
||||
&& vhosts."worker.alexion.dev".locations."/".proxyPass == "http://10.23.20.126:3923"
|
||||
&& vhosts."worker.alexion.dev".locations."/".proxyPass == "http://10.23.20.127:3923"
|
||||
&& vhosts."budget.alexion.dev".locations."/".proxyPass == "http://10.23.20.42:5006"
|
||||
&& vhosts."files.alexion.dev".locations."/".proxyPass == "http://10.23.20.126:3923"
|
||||
)
|
||||
@@ -481,6 +513,44 @@
|
||||
touch $out
|
||||
'';
|
||||
|
||||
route-registry-duplicate-domain-fails =
|
||||
let
|
||||
alpha = lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
specialArgs.my = self.lib;
|
||||
modules = [
|
||||
self.lib.registry.module
|
||||
{
|
||||
registry.route.alpha.app = {
|
||||
domain = "files.alexion.dev";
|
||||
port = 3923;
|
||||
};
|
||||
system.stateVersion = "26.11";
|
||||
}
|
||||
];
|
||||
};
|
||||
beta = lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
specialArgs.my = self.lib;
|
||||
modules = [
|
||||
self.lib.registry.module
|
||||
{
|
||||
registry.route.beta.app = {
|
||||
domain = "files.alexion.dev";
|
||||
port = 3923;
|
||||
};
|
||||
system.stateVersion = "26.11";
|
||||
}
|
||||
];
|
||||
};
|
||||
registry = self.lib.registry.collect { hosts = { inherit alpha beta; }; };
|
||||
result = builtins.tryEval (builtins.deepSeq registry.route true);
|
||||
in
|
||||
pkgs.runCommand "route-registry-duplicate-domain-fails-check" { } ''
|
||||
${lib.optionalString result.success "exit 1"}
|
||||
touch $out
|
||||
'';
|
||||
|
||||
reverse-proxy-address-backends =
|
||||
let
|
||||
workerHost =
|
||||
@@ -603,59 +673,6 @@
|
||||
touch $out
|
||||
'';
|
||||
|
||||
reverse-proxy-duplicate-domain-fails =
|
||||
let
|
||||
pikachu = lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
specialArgs.my = self.lib;
|
||||
modules = [
|
||||
self.lib.registry.module
|
||||
{
|
||||
registry.address.pikachu.copyparty = "10.23.20.126";
|
||||
registry.route.pikachu.copyparty = {
|
||||
domain = "files.alexion.dev";
|
||||
port = 3923;
|
||||
};
|
||||
system.stateVersion = "26.11";
|
||||
}
|
||||
];
|
||||
};
|
||||
raichu = lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
specialArgs.my = self.lib;
|
||||
modules = [
|
||||
self.lib.registry.module
|
||||
{
|
||||
registry.address.raichu.files = "10.23.20.10";
|
||||
registry.route.raichu.files = {
|
||||
domain = "files.alexion.dev";
|
||||
port = 3923;
|
||||
};
|
||||
system.stateVersion = "26.11";
|
||||
}
|
||||
];
|
||||
};
|
||||
registry = self.lib.registry.collect { hosts = { inherit pikachu raichu; }; };
|
||||
testConfig = lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
specialArgs = {
|
||||
my = self.lib;
|
||||
inherit registry;
|
||||
};
|
||||
modules = [
|
||||
./modules/reverse-proxy.nix
|
||||
{
|
||||
modules.reverse-proxy.enable = true;
|
||||
system.stateVersion = "26.11";
|
||||
}
|
||||
];
|
||||
};
|
||||
result = builtins.tryEval (builtins.deepSeq testConfig.config.services.nginx.virtualHosts true);
|
||||
in
|
||||
pkgs.runCommand "reverse-proxy-duplicate-domain-fails-check" { } ''
|
||||
${lib.optionalString result.success "exit 1"}
|
||||
touch $out
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,26 +16,37 @@ let
|
||||
nameValuePair
|
||||
removeSuffix
|
||||
types
|
||||
unique
|
||||
;
|
||||
|
||||
assertionType = types.submodule {
|
||||
checkType = types.submodule {
|
||||
options = {
|
||||
assertion = mkOption {
|
||||
type = types.bool;
|
||||
type = types.functionTo types.bool;
|
||||
description = ''
|
||||
Whether this registry validation assertion passed.
|
||||
Predicate run against this registry's flattened collected entries.
|
||||
'';
|
||||
};
|
||||
|
||||
message = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Error message shown when this registry validation assertion fails.
|
||||
Error message shown when this registry validation check fails.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
predicates = {
|
||||
uniqueValue = value: entries: builtins.length (unique (map value entries)) == builtins.length entries;
|
||||
};
|
||||
|
||||
registryLib = lib // {
|
||||
registry = (lib.registry or { }) // {
|
||||
inherit predicates;
|
||||
};
|
||||
};
|
||||
|
||||
registryDefinitionModule = {
|
||||
options = {
|
||||
type = mkOption {
|
||||
@@ -53,11 +64,11 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
validate = mkOption {
|
||||
type = types.functionTo (types.listOf assertionType);
|
||||
default = _entries: [ ];
|
||||
checks = mkOption {
|
||||
type = types.listOf checkType;
|
||||
default = [ ];
|
||||
description = ''
|
||||
Validate this registry's flattened collected entries.
|
||||
Validation checks for this registry's flattened collected entries.
|
||||
'';
|
||||
};
|
||||
};
|
||||
@@ -76,7 +87,7 @@ let
|
||||
mkRegistry = path:
|
||||
let
|
||||
evaluated = lib.evalModules {
|
||||
specialArgs = { inherit lib; };
|
||||
specialArgs.lib = registryLib;
|
||||
modules = [
|
||||
registryDefinitionModule
|
||||
path
|
||||
@@ -84,7 +95,7 @@ let
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit (evaluated.config) type replicate validate;
|
||||
inherit (evaluated.config) type replicate checks;
|
||||
};
|
||||
|
||||
definitions = mapAttrs' (
|
||||
@@ -149,7 +160,13 @@ let
|
||||
concatLists (
|
||||
mapAttrsToList (
|
||||
registryName: registry:
|
||||
registry.validate (flattenRegistryEntries registryName data.${registryName})
|
||||
let
|
||||
entries = flattenRegistryEntries registryName data.${registryName};
|
||||
in
|
||||
map (check: {
|
||||
assertion = check.assertion entries;
|
||||
inherit (check) message;
|
||||
}) registry.checks
|
||||
) definitions
|
||||
);
|
||||
|
||||
@@ -189,7 +206,7 @@ let
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit definitions;
|
||||
inherit definitions predicates;
|
||||
|
||||
module = {
|
||||
options.registry = mapAttrs (_name: registry: registryOption registry) definitions;
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
type = lib.types.str;
|
||||
|
||||
checks = [
|
||||
{
|
||||
assertion = lib.registry.predicates.uniqueValue (entry: entry.value);
|
||||
message = "Address registry values must be unique.";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
checks = [
|
||||
{
|
||||
assertion = lib.registry.predicates.uniqueValue (entry: entry.value.domain);
|
||||
message = "Route domains must be unique.";
|
||||
}
|
||||
];
|
||||
|
||||
type = lib.types.submodule {
|
||||
options = {
|
||||
domain = lib.mkOption {
|
||||
|
||||
@@ -22,9 +22,9 @@ in
|
||||
|
||||
type = lib.types.ints.positive;
|
||||
|
||||
validate = entries: [
|
||||
checks = [
|
||||
{
|
||||
assertion = duplicateUids entries == { };
|
||||
assertion = entries: duplicateUids entries == { };
|
||||
message = "Stable UID allocations must be unique.";
|
||||
}
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user