diff --git a/checks/mycelium/default.nix b/checks/mycelium/default.nix index 7c3f2b297..abc0aec39 100644 --- a/checks/mycelium/default.nix +++ b/checks/mycelium/default.nix @@ -16,7 +16,6 @@ nixosLib.runTest ( name = "service-mycelium"; clan = { - test.useContainers = false; directory = ./.; modules."@clan/mycelium" = ../../clanServices/mycelium/default.nix; diff --git a/clanServices/hello-world/tests/eval-tests.nix b/clanServices/hello-world/tests/eval-tests.nix index 5194ff4e0..becd0f169 100644 --- a/clanServices/hello-world/tests/eval-tests.nix +++ b/clanServices/hello-world/tests/eval-tests.nix @@ -5,6 +5,7 @@ }: let testFlake = clanLib.clan { + self = { }; # Point to the folder of the module # TODO: make this optional directory = ./..; diff --git a/clanServices/mycelium/tests/vm/default.nix b/clanServices/mycelium/tests/vm/default.nix index d5cfd2c08..28ff0c8a6 100644 --- a/clanServices/mycelium/tests/vm/default.nix +++ b/clanServices/mycelium/tests/vm/default.nix @@ -6,7 +6,6 @@ name = "service-mycelium"; clan = { - test.useContainers = false; directory = ./.; inventory = { diff --git a/clanServices/wifi/tests/eval-tests.nix b/clanServices/wifi/tests/eval-tests.nix index b4d33c6f8..981c85cc3 100644 --- a/clanServices/wifi/tests/eval-tests.nix +++ b/clanServices/wifi/tests/eval-tests.nix @@ -5,6 +5,7 @@ }: let testFlake = clanLib.clan { + self = { }; # Point to the folder of the module # TODO: make this optional directory = ./..; diff --git a/clanServices/zerotier/tests/eval-tests.nix b/clanServices/zerotier/tests/eval-tests.nix index 3f57eafa7..0feddfe0b 100644 --- a/clanServices/zerotier/tests/eval-tests.nix +++ b/clanServices/zerotier/tests/eval-tests.nix @@ -6,6 +6,7 @@ let testFlake = (clanLib.clan { + self = { }; directory = ./vm; machines.jon = { diff --git a/lib/clanTest/flake-module.nix b/lib/clanTest/flake-module.nix index af5636343..ad55dac56 100644 --- a/lib/clanTest/flake-module.nix +++ b/lib/clanTest/flake-module.nix @@ -149,6 +149,14 @@ in modules = [ clan-core.modules.clan.default { + self = { + inputs = { + # Simulate flake: 'self.inputs.self' + # Needed because local modules are imported from inputs.self + self = config; + set_inputs_in_tests_fixture_warning = throw "'self.inputs' within test needs to be set manually. Set 'clan.self.inputs' to mock inputs=`{}`"; + }; + }; _prefix = [ "checks" "" diff --git a/lib/default.nix b/lib/default.nix index 093ccd12d..bf797c264 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -1,5 +1,8 @@ { lib, + # TODO: Get rid of self here. + # DONT add any new functions that depend on self here. + # If a lib function depends on a piece in clan-core add that piece to the function arguments self, ... }: @@ -31,7 +34,7 @@ lib.fix ( # ------------------------------------ # ClanLib functions evalClan = clanLib.callLib ./modules/inventory/eval-clan-modules { }; - inventory = clanLib.callLib ./modules/inventory { clan-core = self; }; + inventory = clanLib.callLib ./modules/inventory { }; modules = clanLib.callLib ./modules/inventory/frontmatter { }; test = clanLib.callLib ./test { }; # Custom types diff --git a/lib/modules/clan/interface.nix b/lib/modules/clan/interface.nix index 1c637d308..02cbc7eb4 100644 --- a/lib/modules/clan/interface.nix +++ b/lib/modules/clan/interface.nix @@ -2,6 +2,7 @@ lib, clanLib, self, + config, # TODO: Use dependency injection to allow for testing # inventoryInterface, ... @@ -24,6 +25,18 @@ in description = '' This is used to import external clan modules. ''; + # Workaround for lib.clan + apply = + s: + if lib.isAttrs s then + s + // { + inputs = (s.inputs or { }) // { + self.clan = config; + }; + } + else + s; }; directory = lib.mkOption { diff --git a/lib/modules/clan/module.nix b/lib/modules/clan/module.nix index 795e3f079..6f47050cb 100644 --- a/lib/modules/clan/module.nix +++ b/lib/modules/clan/module.nix @@ -248,7 +248,8 @@ in { distributedServices = clanLib.inventory.mapInstances { inherit (config) inventory; - inherit localModuleSet flakeInputs; + inherit flakeInputs; + clanCoreModules = clan-core.clan.modules; prefix = [ "distributedServices" ]; }; machines = config.distributedServices.allMachines; diff --git a/lib/modules/inventory/default.nix b/lib/modules/inventory/default.nix index 2eb17d793..7904d0ebe 100644 --- a/lib/modules/inventory/default.nix +++ b/lib/modules/inventory/default.nix @@ -1,12 +1,9 @@ { lib, clanLib, - clan-core, }: let - services = clanLib.callLib ./distributed-service/inventory-adapter.nix { - inherit clan-core; - }; + services = clanLib.callLib ./distributed-service/inventory-adapter.nix { }; in { inherit (services) mapInstances; diff --git a/lib/modules/inventory/distributed-service/flake-module.nix b/lib/modules/inventory/distributed-service/flake-module.nix index 3940c44ed..630accb69 100644 --- a/lib/modules/inventory/distributed-service/flake-module.nix +++ b/lib/modules/inventory/distributed-service/flake-module.nix @@ -18,6 +18,9 @@ in inherit lib; clanLib = self.clanLib; }; + legacyPackages.eval-tests-resolve-module = import ./test-resolve-module.nix { + inherit lib; + }; checks = { eval-lib-distributedServices = pkgs.runCommand "tests" { nativeBuildInputs = [ pkgs.nix-unit ]; } '' @@ -30,6 +33,16 @@ in touch $out ''; + eval-tests-resolve-module = pkgs.runCommand "tests" { nativeBuildInputs = [ pkgs.nix-unit ]; } '' + export HOME="$(realpath .)" + nix-unit --eval-store "$HOME" \ + --extra-experimental-features flakes \ + --show-trace \ + ${inputOverrides} \ + --flake ${self}#legacyPackages.${system}.eval-tests-resolve-module + + touch $out + ''; }; }; } diff --git a/lib/modules/inventory/distributed-service/inventory-adapter.nix b/lib/modules/inventory/distributed-service/inventory-adapter.nix index 5b73c9328..15120bed3 100644 --- a/lib/modules/inventory/distributed-service/inventory-adapter.nix +++ b/lib/modules/inventory/distributed-service/inventory-adapter.nix @@ -12,11 +12,10 @@ { lib, clanLib, - clan-core, ... }: let - resolveModule = import ./resolveModule.nix { inherit lib clan-core; }; + resolveModule = import ./resolveModule.nix { inherit lib; }; in { mapInstances = @@ -25,7 +24,7 @@ in flakeInputs, # The clan inventory inventory, - localModuleSet, + clanCoreModules, prefix ? [ ], }: let @@ -37,8 +36,7 @@ in let resolvedModule = resolveModule { moduleSpec = instance.module; - inherit localModuleSet; - inherit flakeInputs; + inherit flakeInputs clanCoreModules; }; # Every instance includes machines via roles diff --git a/lib/modules/inventory/distributed-service/resolveModule.nix b/lib/modules/inventory/distributed-service/resolveModule.nix index 4e09bfe0b..b4ba548e4 100644 --- a/lib/modules/inventory/distributed-service/resolveModule.nix +++ b/lib/modules/inventory/distributed-service/resolveModule.nix @@ -1,11 +1,10 @@ -{ lib, clan-core }: +{ lib }: { moduleSpec, flakeInputs, - localModuleSet, + clanCoreModules, }: let - inputName = if moduleSpec.input == null then "" else moduleSpec.input; inputError = throw '' Flake doesn't provide input with name '${moduleSpec.input}' @@ -29,21 +28,28 @@ let let input = if moduleSpec.input == null then - clan-core - else if moduleSpec.input == "self" then - { clan.modules = localModuleSet; } + { clan.modules = clanCoreModules; } else flakeInputs.${moduleSpec.input} or inputError; in input.clan.modules - or (throw "flake input ${moduleSpec.input} doesn't export any clan services via the `clan.modules` output attribute"); + or (throw "flake input '${moduleSpec.input}' doesn't export any clan services via the `clan.modules` output attribute"); resolvedModule = resolvedModuleSet.${moduleSpec.name} or (throw '' - flake input '${inputName}' doesn't provide clan-module with name ${moduleSpec.name}. + ${ + lib.optionalString ( + moduleSpec.input != null + ) "flake input '${moduleSpec.input}' doesn't provide clan-module with name '${moduleSpec.name}'." + }${ + lib.optionalString ( + moduleSpec.input == null + ) "clan-core doesn't provide clan-module with name '${moduleSpec.name}'." + } - Set `module.name = "self"` if the module is defined in your own flake. + Set `module.input = "self"` if the module is defined in your own flake. Set `module.input = "" if the module is defined by a flake input called ``. + Unset `module.input` (or set module.input = null) - to use the clan-core module '${moduleSpec.name}' ''); in resolvedModule diff --git a/lib/modules/inventory/distributed-service/test-resolve-module.nix b/lib/modules/inventory/distributed-service/test-resolve-module.nix new file mode 100644 index 000000000..59c72ecb0 --- /dev/null +++ b/lib/modules/inventory/distributed-service/test-resolve-module.nix @@ -0,0 +1,69 @@ +# Run: nix-unit ./test-resolve-module.nix +{ + lib ? import , +}: +let + resolveModule = import ./resolveModule.nix { inherit lib; }; + + fromSpec = + moduleSpec: + resolveModule { + inherit moduleSpec; + flakeInputs = { + self.clan.modules = { + foo = { + name = "self/foo"; + }; + }; + }; + clanCoreModules = { + foo = { + name = "clan/foo"; + }; + bar = { + name = "clan/bar"; + }; + }; + }; + +in +{ + test_default_clan_core = { + expr = fromSpec { + name = "foo"; + input = null; + }; + expected = { + name = "clan/foo"; + }; + }; + test_self_module = { + expr = fromSpec { + name = "foo"; + input = "self"; + }; + expected = { + name = "self/foo"; + }; + }; + test_missing_self_module = { + expr = fromSpec { + name = "bar"; + input = "self"; + }; + expectedError = { + type = "ThrownError"; + msg = "flake input 'self' doesn't provide clan-module with name 'bar'"; + }; + }; + test_missing_core_module = { + expr = fromSpec { + name = "nana"; + input = null; + }; + expectedError = { + type = "ThrownError"; + msg = "clan-core doesn't provide clan-module with name 'nana'"; + }; + }; +} diff --git a/lib/modules/inventory/distributed-service/tests/default.nix b/lib/modules/inventory/distributed-service/tests/default.nix index a764ab58b..0ccbe3d7f 100644 --- a/lib/modules/inventory/distributed-service/tests/default.nix +++ b/lib/modules/inventory/distributed-service/tests/default.nix @@ -27,27 +27,27 @@ let ]; }).config; - flakeInputsFixture = { - # Example upstream module - upstream.clan.modules = { - uzzi = { - _class = "clan.service"; - manifest = { - name = "uzzi-from-upstream"; - }; - }; - }; - }; - callInventoryAdapter = inventoryModule: let inventory = evalInventory inventoryModule; + flakeInputsFixture = { + self.clan.modules = inventory.modules; + # Example upstream module + upstream.clan.modules = { + uzzi = { + _class = "clan.service"; + manifest = { + name = "uzzi-from-upstream"; + }; + }; + }; + }; in clanLib.inventory.mapInstances { + clanCoreModules = { }; flakeInputs = flakeInputsFixture; inherit inventory; - localModuleSet = inventory.modules; }; in {