Merge pull request 'feat(inventory): remove tag settings for now' (#3158) from hsjobeki/clan-core:clan-services into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3158
This commit is contained in:
hsjobeki
2025-04-01 12:30:25 +00:00
5 changed files with 179 additions and 77 deletions

View File

@@ -14,7 +14,7 @@ in
}: }:
{ {
# Run: nix-unit --extra-experimental-features flakes --flake .#legacyPackages.x86_64-linux.<attrName> # Run: nix-unit --extra-experimental-features flakes --flake .#legacyPackages.x86_64-linux.<attrName>
legacyPackages.evalTest-distributedServices = import ./tests { legacyPackages.evalTests-distributedServices = import ./tests {
inherit lib self; inherit lib self;
}; };
@@ -24,7 +24,7 @@ in
nix-unit --eval-store "$HOME" \ nix-unit --eval-store "$HOME" \
--extra-experimental-features flakes \ --extra-experimental-features flakes \
${inputOverrides} \ ${inputOverrides} \
--flake ${self}#legacyPackages.${system}.evalTest-distributedServices --flake ${self}#legacyPackages.${system}.evalTests-distributedServices
touch $out touch $out
''; '';

View File

@@ -54,7 +54,7 @@ let
) [ ] members.tags or [ ]); ) [ ] members.tags or [ ]);
}; };
machineHasTag = machineName: tagName: lib.elem tagName inventory.machines.${machineName}.tags; # machineHasTag = machineName: tagName: lib.elem tagName inventory.machines.${machineName}.tags;
# map the instances into the module # map the instances into the module
importedModuleWithInstances = lib.mapAttrs ( importedModuleWithInstances = lib.mapAttrs (
@@ -119,9 +119,12 @@ let
machineName: machineName:
let let
machineSettings = instance.roles.${roleName}.machines.${machineName}.settings or { }; machineSettings = instance.roles.${roleName}.machines.${machineName}.settings or { };
settingsViaTags = lib.filterAttrs ( # TODO: tag settings
tagName: _: machineHasTag machineName tagName # Wait for this feature until option introspection for 'settings' is done.
) instance.roles.${roleName}.tags; # This might get too complex to handle otherwise.
# settingsViaTags = lib.filterAttrs (
# tagName: _: machineHasTag machineName tagName
# ) instance.roles.${roleName}.tags;
in in
{ {
# TODO: Do we want to wrap settings with # TODO: Do we want to wrap settings with
@@ -129,7 +132,7 @@ let
settings = { settings = {
imports = [ imports = [
machineSettings machineSettings
] ++ lib.attrValues (lib.mapAttrs (_tagName: v: v.settings) settingsViaTags); ]; # ++ lib.attrValues (lib.mapAttrs (_tagName: v: v.settings) settingsViaTags);
}; };
} }
); );
@@ -194,6 +197,10 @@ let
) { } evals; ) { } evals;
in in
{ {
inherit importedModuleWithInstances grouped; inherit
inherit evals allMachines; importedModuleWithInstances
grouped
evals
allMachines
;
} }

View File

@@ -258,70 +258,5 @@ in
}; };
per_machine_args = import ./per_machine_args.nix { inherit lib callInventoryAdapter; }; per_machine_args = import ./per_machine_args.nix { inherit lib callInventoryAdapter; };
# test_per_machine_receives_instances = per_instance_args = import ./per_instance_args.nix { inherit lib callInventoryAdapter; };
# let
# res = callInventoryAdapter {
# # Authored module
# # A minimal module looks like this
# # It isn't exactly doing anything but it's a valid module that produces an output
# modules."A" = {
# _class = "clan.service";
# manifest = {
# name = "network";
# };
# # Define a role without special behavior
# roles.peer = { };
# perMachine =
# { instances, ... }:
# {
# nixosModule = instances;
# };
# };
# machines = {
# jon = { };
# sara = { };
# };
# instances."instance_foo" = {
# module = {
# name = "A";
# };
# roles.peer.machines.jon = { };
# };
# instances."instance_bar" = {
# module = {
# name = "A";
# };
# roles.peer.machines.sara = { };
# };
# instances."instance_zaza" = {
# module = {
# name = "B";
# };
# roles.peer.tags.all = { };
# };
# };
# in
# {
# expr = {
# hasMachineSettings =
# res.evals.self-A.config.result.allMachines.jon.nixosModule. # { {instanceName} :: { roles :: { {roleName} :: { machines :: { {machineName} :: { settings :: {} } } } } } }
# instance_foo.roles.peer.machines.jon ? settings;
# machineSettingsEmpty =
# lib.filterAttrs (n: _v: n != "__functor" ) res.evals.self-A.config.result.allMachines.jon.nixosModule. # { {instanceName} :: { roles :: { {roleName} :: { machines :: { {machineName} :: { settings :: {} } } } } } }
# instance_foo.roles.peer.machines.jon.settings;
# hasRoleSettings =
# res.evals.self-A.config.result.allMachines.jon.nixosModule. # { {instanceName} :: { roles :: { {roleName} :: { machines :: { {machineName} :: { settings :: {} } } } } } }
# instance_foo.roles.peer ? settings;
# roleSettingsEmpty =
# lib.filterAttrs (n: _v: n != "__functor" ) res.evals.self-A.config.result.allMachines.jon.nixosModule. # { {instanceName} :: { roles :: { {roleName} :: { machines :: { {machineName} :: { settings :: {} } } } } } }
# instance_foo.roles.peer.settings;
# };
# expected = {
# hasMachineSettings = true;
# machineSettingsEmpty = {};
# hasRoleSettings = true;
# roleSettingsEmpty = {};
# };
# };
} }

View File

@@ -0,0 +1,160 @@
{ lib, callInventoryAdapter }:
let
# Authored module
# A minimal module looks like this
# It isn't exactly doing anything but it's a valid module that produces an output
modules."A" = {
_class = "clan.service";
manifest = {
name = "network";
};
# Define two roles with unmergeable interfaces
# Both define some 'timeout' but with completely different types.
roles.peer.interface =
{ lib, ... }:
{
options.timeout = lib.mkOption {
type = lib.types.str;
};
};
roles.peer.perInstance =
{
instanceName,
settings,
machine,
...
}:
let
settings1 = settings {
# Sometimes we want to create a default settings set depending on the machine config.
# Note: Other machines cannot depend on this settings. We must assign a new name to the settings.
# And thus the new value is not accessible by other machines.
timeout = lib.mkOverride 10 "config.blah";
};
in
{
nixosModule = {
inherit instanceName settings machine;
# We are double vendoring the settings
# To test that we can do it indefinitely
vendoredSettings = settings1 {
# Sometimes we want to create a default settings set depending on the machine config.
# Note: Other machines cannot depend on this settings. We must assign a new name to the settings.
# And thus the new value is not accessible by other machines.
timeout = lib.mkOverride 5 "config.thing";
};
};
};
};
machines = {
jon = { };
sara = { };
};
res = callInventoryAdapter {
inherit modules machines;
instances."instance_foo" = {
module = {
name = "A";
};
roles.peer.machines.jon = {
settings.timeout = lib.mkForce "foo-peer-jon";
};
roles.peer = {
settings.timeout = "foo-peer";
};
};
instances."instance_bar" = {
module = {
name = "A";
};
roles.peer.machines.jon = {
settings.timeout = "bar-peer-jon";
};
};
# import the module "B" (undefined)
# All machines have this instance
instances."instance_zaza" = {
module = {
name = "B";
};
roles.peer.tags.all = { };
};
};
filterInternals = lib.filterAttrs (n: _v: !lib.hasPrefix "_" n);
# Replace internal attributes ('_' prefix)
# So we catch their presence but don't check the value
mapInternalsRecursive = lib.mapAttrsRecursive (
path: v:
let
name = lib.last path;
in
if !lib.hasPrefix "_" name then v else name
);
in
{
# settings should evaluate
test_per_instance_arguments = {
expr = {
instanceName =
res.evals.self-A.config.result.allRoles.peer.allInstances."instance_foo".allMachines.jon.nixosModule.instanceName;
# settings are specific.
# Below we access:
# instance = instance_foo
# roles = peer
# machines = jon
settings = filterInternals res.evals.self-A.config.result.allRoles.peer.allInstances.instance_foo.allMachines.jon.nixosModule.settings;
machine = mapInternalsRecursive res.evals.self-A.config.result.allRoles.peer.allInstances.instance_foo.allMachines.jon.nixosModule.machine;
# hasRoleSettings =
# res.evals.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer ? settings;
# # settings are specific.
# # Below we access:
# # instance = instance_foo
# # roles = peer
# # machines = *
# specificRoleSettings = filterInternals res.evals.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.settings;
};
expected = {
instanceName = "instance_foo";
settings = {
timeout = "foo-peer-jon";
};
machine = {
name = "jon";
roles = {
peer = {
machines = {
jon = {
settings = {
__functor = "__functor";
timeout = "foo-peer-jon";
};
};
};
settings = {
__functor = "__functor";
timeout = "foo-peer";
};
};
};
};
};
};
test_per_instance_settings_vendoring = {
expr =
mapInternalsRecursive
res.evals.self-A.config.result.allRoles.peer.allInstances."instance_foo".allMachines.jon.nixosModule.vendoredSettings;
expected = {
# Returns another override
__functor = "__functor";
timeout = "config.thing";
};
};
}

View File

@@ -1,6 +1,6 @@
{ lib, callInventoryAdapter }: { lib, callInventoryAdapter }:
let
let # Authored module # Authored module
# A minimal module looks like this # A minimal module looks like this
# It isn't exactly doing anything but it's a valid module that produces an output # It isn't exactly doing anything but it's a valid module that produces an output
modules."A" = { modules."A" = {