chore(lib/treewide): cleanup directory struture of lib. See lib/readme.md for details

This commit is contained in:
Johannes Kirschbauer
2025-04-02 10:32:58 +02:00
parent ee96df8c53
commit 2ab53b05fe
21 changed files with 92 additions and 94 deletions

View File

@@ -45,15 +45,15 @@ Example filetree
. .
├── default.nix ├── default.nix
├── build-clan ├── build-clan
│ ├── impl.nix │ ├── default.nix
│ └── test.nix │ └── test.nix
└── inventory └── inventory
├── impl.nix ├── default.nix
├── services-subfeature ├── services-subfeature
│ ├── impl.nix │ ├── default.nix
│ └── test.nix │ └── test.nix
├── instances-subfeature # <- We immediately see that this feature is not tested on itself. ├── instances-subfeature # <- We immediately see that this feature is not tested on itself.
│ └── impl.nix │ └── default.nix
└── test.nix └── test.nix
``` ```

View File

@@ -79,7 +79,7 @@ in
}; };
inventory = lib.mkOption { inventory = lib.mkOption {
type = types.submodule { imports = [ ../inventory/build-inventory/interface.nix ]; }; type = types.submodule { imports = [ self.clanLib.inventory.interface ]; };
description = '' description = ''
The `Inventory` submodule. The `Inventory` submodule.

View File

@@ -201,9 +201,9 @@ in
clanInternals = { clanInternals = {
moduleSchemas = clan-core.lib.modules.getModulesSchema config.inventory.modules; moduleSchemas = clan-core.lib.modules.getModulesSchema config.inventory.modules;
inherit inventoryClass; inherit inventoryClass;
distributedServices = import ../distributed-service/inventory-adapter.nix { distributedServices = clan-core.clanLib.inventory.mapInstances {
inherit lib inventory; inherit inventory;
flake = config.self; flakeInputs = config.self.inputs;
}; };
# TODO: unify this interface # TODO: unify this interface
# We should have only clan.modules. (consistent with clan.templates) # We should have only clan.modules. (consistent with clan.templates)

View File

@@ -13,14 +13,13 @@ lib.fix (clanLib: {
# We should reduce the dependency on 'self' aka the 'flake' object # We should reduce the dependency on 'self' aka the 'flake' object
# This makes it easier to test # This makes it easier to test
# most of the time passing the whole flake is unnecessary # most of the time passing the whole flake is unnecessary
callLib = file: args: import file { inherit lib clanLib; } // args; callLib = file: args: import file ({ inherit lib clanLib; } // args);
evalClan = import ./eval-clan-modules { evalClan = import ./inventory/eval-clan-modules {
inherit lib; inherit lib;
clan-core = self; clan-core = self;
pkgs = nixpkgs.legacyPackages.x86_64-linux; pkgs = nixpkgs.legacyPackages.x86_64-linux;
}; };
buildClanModule = import ./build-clan { buildClanModule = import ./build-clan {
inherit lib nixpkgs; inherit lib nixpkgs;
}; };
@@ -28,9 +27,9 @@ lib.fix (clanLib: {
# ------------------------------------ # ------------------------------------
# Lib functions that don't depend on 'self' # Lib functions that don't depend on 'self'
inventory = clanLib.callLib ./inventory { }; inventory = clanLib.callLib ./inventory { };
modules = clanLib.callLib ./frontmatter { }; modules = clanLib.callLib ./inventory/frontmatter { };
facts = import ./facts.nix { inherit lib; }; values = import ./introspection { inherit lib; };
values = import ./values { inherit lib; };
jsonschema = import ./jsonschema { inherit lib; }; jsonschema = import ./jsonschema { inherit lib; };
select = import ./select.nix; select = import ./select.nix;
facts = import ./facts.nix { inherit lib; };
}) })

View File

@@ -4,21 +4,13 @@
self, self,
... ...
}: }:
let
inherit (lib)
filter
pathExists
;
in
rec { rec {
# We should remove this. # TODO: automatically generate this from the directory conventions
# It would enforce treating at least 'lib' as a module in a whole imports = [
imports = filter pathExists [
./jsonschema/flake-module.nix
./inventory/flake-module.nix
./build-clan/flake-module.nix ./build-clan/flake-module.nix
./values/flake-module.nix ./inventory/flake-module.nix
./distributed-service/flake-module.nix ./jsonschema/flake-module.nix
./introspection/flake-module.nix
]; ];
flake.clanLib = import ./default.nix { flake.clanLib = import ./default.nix {
inherit lib inputs self; inherit lib inputs self;

View File

@@ -2,4 +2,41 @@
{ {
inherit (import ./build-inventory { inherit lib clanLib; }) buildInventory; inherit (import ./build-inventory { inherit lib clanLib; }) buildInventory;
interface = ./build-inventory/interface.nix; interface = ./build-inventory/interface.nix;
mapInstances = clanLib.callLib ./distributed-service/inventory-adapter.nix {};
# Returns the list of machine names
# { ... } -> [ string ]
resolveTags =
{
# Available InventoryMachines :: { {name} :: { tags = [ string ]; }; }
machines,
# Requested members :: { machines, tags }
# Those will be resolved against the available machines
members,
# Not needed for resolution - only for error reporting
roleName,
instanceName,
}:
{
machines =
members.machines or [ ]
++ (builtins.foldl' (
acc: tag:
let
# For error printing
availableTags = lib.foldlAttrs (
acc: _: v:
v.tags or [ ] ++ acc
) [ ] (machines);
tagMembers = builtins.attrNames (lib.filterAttrs (_n: v: builtins.elem tag v.tags or [ ]) machines);
in
if tagMembers == [ ] then
lib.warn ''
Service instance '${instanceName}': - ${roleName} tags: no machine with tag '${tag}' found.
Available tags: ${builtins.toJSON (lib.unique availableTags)}
'' acc
else
acc ++ tagMembers
) [ ] members.tags or [ ]);
};
} }

View File

@@ -15,7 +15,8 @@ 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.evalTests-distributedServices = import ./tests { legacyPackages.evalTests-distributedServices = import ./tests {
inherit lib self; inherit lib;
clanLib = self.clanLib;
}; };
checks = { checks = {

View File

@@ -11,49 +11,16 @@
# Also combines the settings for 'machines' and 'tags'. # Also combines the settings for 'machines' and 'tags'.
{ {
lib, lib,
clanLib,
...
}:
{
# This is used to resolve the module imports from 'flake.inputs' # This is used to resolve the module imports from 'flake.inputs'
flake, flakeInputs,
# The clan inventory # The clan inventory
inventory, inventory,
}: }:
let let
# Returns the list of machine names
# { ... } -> [ string ]
resolveTags =
{
# Available InventoryMachines :: { {name} :: { tags = [ string ]; }; }
machines,
# Requested members :: { machines, tags }
# Those will be resolved against the available machines
members,
# Not needed for resolution - only for error reporting
roleName,
instanceName,
}:
{
machines =
members.machines or [ ]
++ (builtins.foldl' (
acc: tag:
let
# For error printing
availableTags = lib.foldlAttrs (
acc: _: v:
v.tags or [ ] ++ acc
) [ ] (machines);
tagMembers = builtins.attrNames (lib.filterAttrs (_n: v: builtins.elem tag v.tags or [ ]) machines);
in
if tagMembers == [ ] then
lib.warn ''
Service instance '${instanceName}': - ${roleName} tags: no machine with tag '${tag}' found.
Available tags: ${builtins.toJSON (lib.unique availableTags)}
'' acc
else
acc ++ tagMembers
) [ ] 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
@@ -69,13 +36,13 @@ let
else else
let let
input = input =
flake.inputs.${instance.module.input} or (throw '' flakeInputs.${instance.module.input} or (throw ''
Flake doesn't provide input with name '${instance.module.input}' Flake doesn't provide input with name '${instance.module.input}'
Choose one of the following inputs: Choose one of the following inputs:
- ${ - ${
builtins.concatStringsSep "\n- " ( builtins.concatStringsSep "\n- " (
lib.attrNames (lib.filterAttrs (_name: input: input ? clan) flake.inputs) lib.attrNames (lib.filterAttrs (_name: input: input ? clan) flakeInputs)
) )
} }
@@ -102,7 +69,7 @@ let
instanceRoles = lib.mapAttrs ( instanceRoles = lib.mapAttrs (
roleName: role: roleName: role:
let let
resolvedMachines = resolveTags { resolvedMachines = clanLib.inventory.resolveTags {
members = { members = {
# Explicit members # Explicit members
machines = lib.attrNames role.machines; machines = lib.attrNames role.machines;
@@ -150,7 +117,7 @@ let
) inventory.instances; ) inventory.instances;
# TODO: Eagerly check the _class of the resolved module # TODO: Eagerly check the _class of the resolved module
evals = lib.mapAttrs ( importedModulesEvaluated = lib.mapAttrs (
_module_ident: instances: _module_ident: instances:
(lib.evalModules { (lib.evalModules {
class = "clan.service"; class = "clan.service";
@@ -189,18 +156,18 @@ let
# TODO: Return an attribute set of resources instead of a plain list of nixosModules # TODO: Return an attribute set of resources instead of a plain list of nixosModules
allMachines = lib.foldlAttrs ( allMachines = lib.foldlAttrs (
acc: _name: eval: acc: _module_ident: eval:
acc acc
// lib.mapAttrs ( // lib.mapAttrs (
machineName: result: acc.${machineName} or [ ] ++ [ result.nixosModule ] machineName: result: acc.${machineName} or [ ] ++ [ result.nixosModule ]
) eval.config.result.final ) eval.config.result.final
) { } evals; ) { } importedModulesEvaluated;
in in
{ {
inherit inherit
importedModuleWithInstances importedModuleWithInstances
grouped grouped
evals
allMachines allMachines
; importedModulesEvaluated;
} }

View File

@@ -1,5 +1,6 @@
{ {
lib, lib,
clanLib,
... ...
}: }:
let let
@@ -12,7 +13,7 @@ let
(evalModules { (evalModules {
# Static modules # Static modules
modules = [ modules = [
../../inventory/build-inventory/interface.nix clanLib.inventory.interface
{ {
modules.test = { }; modules.test = { };
} }
@@ -20,15 +21,13 @@ let
]; ];
}).config; }).config;
flakeFixture = { flakeInputsFixture = {
inputs = { };
}; };
callInventoryAdapter = callInventoryAdapter =
inventoryModule: inventoryModule:
import ../inventory-adapter.nix { clanLib.inventory.mapInstances {
inherit lib; flakeInputs = flakeInputsFixture;
flake = flakeFixture;
inventory = evalInventory inventoryModule; inventory = evalInventory inventoryModule;
}; };
in in
@@ -56,7 +55,7 @@ in
{ {
# Test that the module is mapped into the output # Test that the module is mapped into the output
# We might change the attribute name in the future # We might change the attribute name in the future
expr = res.evals ? "self-simple-module"; expr = res.importedModulesEvaluated ? "self-simple-module";
expected = true; expected = true;
}; };
@@ -148,7 +147,7 @@ in
{ {
# Test that the module is mapped into the output # Test that the module is mapped into the output
# We might change the attribute name in the future # We might change the attribute name in the future
expr = lib.attrNames res.evals.self-A.config.instances; expr = lib.attrNames res.importedModulesEvaluated.self-A.config.instances;
expected = [ expected = [
"instance_bar" "instance_bar"
"instance_foo" "instance_foo"
@@ -200,7 +199,7 @@ in
{ {
# Test that the module is mapped into the output # Test that the module is mapped into the output
# We might change the attribute name in the future # We might change the attribute name in the future
expr = lib.attrNames res.evals.self-A.config.result.allMachines; expr = lib.attrNames res.importedModulesEvaluated.self-A.config.result.allMachines;
expected = [ expected = [
"jon" "jon"
"sara" "sara"
@@ -250,7 +249,7 @@ in
{ {
# Test that the module is mapped into the output # Test that the module is mapped into the output
# We might change the attribute name in the future # We might change the attribute name in the future
expr = lib.attrNames res.evals.self-A.config.result.allMachines; expr = lib.attrNames res.importedModulesEvaluated.self-A.config.result.allMachines;
expected = [ expected = [
"jon" "jon"
"sara" "sara"

View File

@@ -100,25 +100,25 @@ in
test_per_instance_arguments = { test_per_instance_arguments = {
expr = { expr = {
instanceName = instanceName =
res.evals.self-A.config.result.allRoles.peer.allInstances."instance_foo".allMachines.jon.nixosModule.instanceName; res.importedModulesEvaluated.self-A.config.result.allRoles.peer.allInstances."instance_foo".allMachines.jon.nixosModule.instanceName;
# settings are specific. # settings are specific.
# Below we access: # Below we access:
# instance = instance_foo # instance = instance_foo
# roles = peer # roles = peer
# machines = jon # machines = jon
settings = filterInternals res.evals.self-A.config.result.allRoles.peer.allInstances.instance_foo.allMachines.jon.nixosModule.settings; settings = filterInternals res.importedModulesEvaluated.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; machine = mapInternalsRecursive res.importedModulesEvaluated.self-A.config.result.allRoles.peer.allInstances.instance_foo.allMachines.jon.nixosModule.machine;
# hasRoleSettings = # hasRoleSettings =
# res.evals.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer ? settings; # res.importedModulesEvaluated.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer ? settings;
# # settings are specific. # # settings are specific.
# # Below we access: # # Below we access:
# # instance = instance_foo # # instance = instance_foo
# # roles = peer # # roles = peer
# # machines = * # # machines = *
# specificRoleSettings = filterInternals res.evals.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.settings; # specificRoleSettings = filterInternals res.importedModulesEvaluated.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.settings;
}; };
expected = { expected = {
instanceName = "instance_foo"; instanceName = "instance_foo";
@@ -150,7 +150,7 @@ in
test_per_instance_settings_vendoring = { test_per_instance_settings_vendoring = {
expr = expr =
mapInternalsRecursive mapInternalsRecursive
res.evals.self-A.config.result.allRoles.peer.allInstances."instance_foo".allMachines.jon.nixosModule.vendoredSettings; res.importedModulesEvaluated.self-A.config.result.allRoles.peer.allInstances."instance_foo".allMachines.jon.nixosModule.vendoredSettings;
expected = { expected = {
# Returns another override # Returns another override
__functor = "__functor"; __functor = "__functor";

View File

@@ -73,7 +73,7 @@ in
test_per_machine_receives_instance_settings = { test_per_machine_receives_instance_settings = {
expr = { expr = {
hasMachineSettings = hasMachineSettings =
res.evals.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.machines.jon res.importedModulesEvaluated.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.machines.jon
? settings; ? settings;
# settings are specific. # settings are specific.
@@ -81,17 +81,17 @@ in
# instance = instance_foo # instance = instance_foo
# roles = peer # roles = peer
# machines = jon # machines = jon
specificMachineSettings = filterInternals res.evals.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.machines.jon.settings; specificMachineSettings = filterInternals res.importedModulesEvaluated.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.machines.jon.settings;
hasRoleSettings = hasRoleSettings =
res.evals.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer ? settings; res.importedModulesEvaluated.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer ? settings;
# settings are specific. # settings are specific.
# Below we access: # Below we access:
# instance = instance_foo # instance = instance_foo
# roles = peer # roles = peer
# machines = * # machines = *
specificRoleSettings = filterInternals res.evals.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.settings; specificRoleSettings = filterInternals res.importedModulesEvaluated.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.settings;
}; };
expected = { expected = {
hasMachineSettings = true; hasMachineSettings = true;

View File

@@ -5,6 +5,9 @@ let
); );
in in
{ {
imports = [
./distributed-service/flake-module.nix
];
perSystem = perSystem =
{ {
pkgs, pkgs,