clanServices: remove recursive services

Initially added in #3972 we've decided to remove them, because they are to complex to use correctly
This commit is contained in:
Johannes Kirschbauer
2025-07-01 17:03:58 +02:00
parent a052f30b10
commit 8d15a7ed62
6 changed files with 22 additions and 463 deletions

View File

@@ -412,27 +412,6 @@ in
``` ```
''; '';
}; };
options.services = mkOption {
visible = false;
type = attrsWith {
placeholder = "serviceName";
elemType = submoduleWith {
modules = [
{
_module.args._ctx = _ctx ++ [
config.manifest.name
"roles"
roleName
"perInstance"
"services"
];
}
./service-module.nix
];
};
};
default = { };
};
}) })
]; ];
}; };
@@ -537,25 +516,6 @@ in
``` ```
''; '';
}; };
options.services = mkOption {
visible = false;
type = attrsWith {
placeholder = "serviceName";
elemType = submoduleWith {
modules = [
{
_module.args._ctx = _ctx ++ [
config.manifest.name
"perMachine"
"services"
];
}
./service-module.nix
];
};
};
default = { };
};
}) })
]; ];
}; };
@@ -727,40 +687,18 @@ in
instanceAcc: instanceName: instance: instanceAcc: instanceName: instance:
instanceAcc instanceAcc
// { // {
nixosModules = nixosModules = (
( if instance.allMachines.${machineName}.nixosModule or { } != { } then
(lib.mapAttrsToList ( instanceAcc.nixosModules
nestedServiceName: serviceModule: ++ [
let (lib.setDefaultModuleLocation
unmatchedMachines = lib.attrNames ( "Via instances.${instanceName}.roles.${roleName}.machines.${machineName}"
lib.removeAttrs serviceModule.result.final (lib.attrNames config.result.allMachines) instance.allMachines.${machineName}.nixosModule
); )
in ]
if unmatchedMachines != [ ] then else
throw '' instanceAcc.nixosModules
The following machines are not part of the parent service: ${builtins.toJSON unmatchedMachines} );
Either remove the machines, or include them into the parent via a role.
(Added via roles.${roleName}.perInstance.services.${nestedServiceName})
${errorContext}
''
else
serviceModule.result.final.${machineName}.nixosModule
) instance.allMachines.${machineName}.services or { })
)
++ (
if instance.allMachines.${machineName}.nixosModule or { } != { } then
instanceAcc.nixosModules
++ [
(lib.setDefaultModuleLocation
"Via instances.${instanceName}.roles.${roleName}.machines.${machineName}"
instance.allMachines.${machineName}.nixosModule
)
]
else
instanceAcc.nixosModules
);
} }
) roleAcc role.allInstances ) roleAcc role.allInstances
) )
@@ -773,38 +711,18 @@ in
{ {
inherit instanceResults machineResult; inherit instanceResults machineResult;
nixosModule = { nixosModule = {
imports = imports = [
[ # include service assertions:
# include service assertions: (
(
let
failedAssertions = (lib.filterAttrs (_: v: !v.assertion) config.result.assertions);
in
{
assertions = lib.attrValues failedAssertions;
}
)
(lib.setDefaultModuleLocation "Via ${config.manifest.name}.perMachine - machine='${machineName}';" machineResult.nixosModule)
]
++ (lib.mapAttrsToList (
nestedServiceName: serviceModule:
let let
unmatchedMachines = lib.attrNames ( failedAssertions = (lib.filterAttrs (_: v: !v.assertion) config.result.assertions);
lib.removeAttrs serviceModule.result.final (lib.attrNames config.result.allMachines)
);
in in
if unmatchedMachines != [ ] then {
throw '' assertions = lib.attrValues failedAssertions;
The following machines are not part of the parent service: ${builtins.toJSON unmatchedMachines} }
Either remove the machines, or include them into the parent via a role. )
(Added via perMachine.services.${nestedServiceName}) (lib.setDefaultModuleLocation "Via ${config.manifest.name}.perMachine - machine='${machineName}';" machineResult.nixosModule)
] ++ instanceResults.nixosModules;
${errorContext}
''
else
serviceModule.result.final.${machineName}.nixosModule
) machineResult.services)
++ instanceResults.nixosModules;
}; };
} }
) config.result.allMachines; ) config.result.allMachines;

View File

@@ -288,5 +288,4 @@ in
per_machine_args = import ./per_machine_args.nix { inherit lib callInventoryAdapter; }; per_machine_args = import ./per_machine_args.nix { inherit lib callInventoryAdapter; };
per_instance_args = import ./per_instance_args.nix { inherit lib callInventoryAdapter; }; per_instance_args = import ./per_instance_args.nix { inherit lib callInventoryAdapter; };
nested = import ./nested_services { inherit lib clanLib; };
} }

View File

@@ -1,8 +0,0 @@
{ clanLib, lib, ... }:
{
test_simple = import ./simple.nix { inherit clanLib lib; };
test_multi_machine = import ./multi_machine.nix { inherit clanLib lib; };
test_multi_import_duplication = import ./multi_import_duplication.nix { inherit clanLib lib; };
}

View File

@@ -1,125 +0,0 @@
{ clanLib, lib, ... }:
let
# Potentially imported many times
# To add the ssh key
example-admin = (
{ lib, ... }:
{
manifest.name = "example-admin";
roles.client.interface = {
options.keys = lib.mkOption { };
};
roles.client.perInstance =
{ settings, ... }:
{
nixosModule = {
inherit (settings) keys;
};
};
}
);
consumer-A =
{ ... }:
{
manifest.name = "consumer-A";
instances.foo = {
roles.server.machines."jon" = { };
};
instances.bar = {
roles.server.machines."jon" = { };
};
roles.server = {
perInstance =
{ machine, instanceName, ... }:
{
services."example-admin" = {
imports = [
example-admin
];
instances."${instanceName}" = {
roles.client.machines.${machine.name} = {
settings.keys = [ "pubkey-1" ];
};
};
};
};
};
};
consumer-B =
{ ... }:
{
manifest.name = "consumer-A";
instances.foo = {
roles.server.machines."jon" = { };
};
instances.bar = {
roles.server.machines."jon" = { };
};
roles.server = {
perInstance =
{ machine, instanceName, ... }:
{
services."example-admin" = {
imports = [
example-admin
];
instances."${instanceName}" = {
roles.client.machines.${machine.name} = {
settings.keys = [
"pubkey-1"
];
};
};
};
};
};
};
eval = clanLib.evalService {
modules = [
(consumer-A)
];
prefix = [ ];
};
eval2 = clanLib.evalService {
modules = [
(consumer-B)
];
prefix = [ ];
};
evalNixos = lib.evalModules {
modules = [
{
options.assertions = lib.mkOption { };
# This is suboptimal
options.keys = lib.mkOption { };
}
eval.config.result.final.jon.nixosModule
eval2.config.result.final.jon.nixosModule
];
};
in
{
# Check that the nixos system has the settings from the nested module, as well as those from the "perMachine" and "perInstance"
inherit eval;
expr = evalNixos.config;
expected = {
assertions = [ ];
# TODO: Some deduplication mechanism is nice
# Could add types.set or do 'apply = unique', or something else ?
keys = [
"pubkey-1"
"pubkey-1"
"pubkey-1"
"pubkey-1"
];
};
}

View File

@@ -1,108 +0,0 @@
{ clanLib, lib, ... }:
let
service-B = (
{ lib, ... }:
{
manifest.name = "service-B";
roles.client.interface = {
options.user = lib.mkOption { };
options.host = lib.mkOption { };
};
roles.client.perInstance =
{ settings, instanceName, ... }:
{
nixosModule = {
units.${instanceName} = {
script = settings.user + "@" + settings.host;
};
};
};
perMachine =
{ ... }:
{
nixosModule = {
ssh.enable = true;
};
};
}
);
service-A =
{ ... }:
{
manifest.name = "service-A";
instances.foo = {
roles.server.machines."jon" = { };
roles.server.machines."sara" = { };
};
roles.server = {
perInstance =
{ machine, instanceName, ... }:
{
services."B" = {
imports = [
service-B
];
instances."A-${instanceName}-B" = {
roles.client.machines.${machine.name} = {
settings.user = "johnny";
settings.host = machine.name;
};
};
};
};
};
};
eval = clanLib.evalService {
modules = [
(service-A)
];
prefix = [ ];
};
evalNixos = lib.mapAttrs (
_n: v:
(lib.evalModules {
modules = [
{
options.assertions = lib.mkOption { };
options.units = lib.mkOption { };
options.ssh = lib.mkOption { };
}
v.nixosModule
];
}).config
) eval.config.result.final;
in
{
# Check that the nixos system has the settings from the nested module, as well as those from the "perMachine" and "perInstance"
inherit eval;
expr = evalNixos;
expected = {
jon = {
assertions = [ ];
ssh = {
enable = true;
};
units = {
A-foo-B = {
script = "johnny@jon";
};
};
};
sara = {
assertions = [ ];
ssh = {
enable = true;
};
units = {
A-foo-B = {
script = "johnny@sara";
};
};
};
};
}

View File

@@ -1,117 +0,0 @@
/*
service-B :: Service
exports a nixosModule which set "address" and "hostname"
Note: How we use null together with mkIf to create optional values.
This is a method, to create mergable modules
service-A :: Service
service-A.roles.server.perInstance.services."B"
imports service-B
configures a client with hostname = "johnny"
service-A.perMachine.services."B"
imports service-B
configures a client with address = "root"
*/
{ clanLib, lib, ... }:
let
service-B = (
{ lib, ... }:
{
manifest.name = "service-B";
roles.client.interface = {
options.hostname = lib.mkOption { default = null; };
options.address = lib.mkOption { default = null; };
};
roles.client.perInstance =
{ settings, ... }:
{
nixosModule = {
imports = [
# Only export the value that is actually set.
(lib.mkIf (settings.hostname != null) {
hostname = settings.hostname;
})
(lib.mkIf (settings.address != null) {
address = settings.address;
})
];
};
};
}
);
service-A =
{ ... }:
{
manifest.name = "service-A";
instances.foo = {
roles.server.machines."jon" = { };
};
instances.bar = {
roles.server.machines."jon" = { };
};
roles.server = {
perInstance =
{ machine, instanceName, ... }:
{
services."B" = {
imports = [
service-B
];
instances."B-for-A" = {
roles.client.machines.${machine.name} = {
settings.hostname = instanceName + "+johnny";
};
};
};
};
};
perMachine =
{ machine, ... }:
{
services."B" = {
imports = [
service-B
];
instances."B-for-A" = {
roles.client.machines.${machine.name} = {
settings.address = "root";
};
};
};
};
};
eval = clanLib.evalService {
modules = [
(service-A)
];
prefix = [ ];
};
evalNixos = lib.evalModules {
modules = [
{
options.assertions = lib.mkOption { };
options.hostname = lib.mkOption { type = lib.types.separatedString " "; };
options.address = lib.mkOption { type = lib.types.str; };
}
eval.config.result.final."jon".nixosModule
];
};
in
{
# Check that the nixos system has the settings from the nested module, as well as those from the "perMachine" and "perInstance"
inherit eval;
expr = evalNixos.config;
expected = {
address = "root";
assertions = [ ];
# Concatenates hostnames from both instances
hostname = "bar+johnny foo+johnny";
};
}