diff --git a/lib/inventory/distributed-service/service-module.nix b/lib/inventory/distributed-service/service-module.nix index 1dcf61719..dc597fdf4 100644 --- a/lib/inventory/distributed-service/service-module.nix +++ b/lib/inventory/distributed-service/service-module.nix @@ -746,7 +746,7 @@ in '' else serviceModule.result.final.${machineName}.nixosModule - ) instance.allMachines.${machineName}.services) + ) instance.allMachines.${machineName}.services or { }) ) ++ ( diff --git a/lib/inventory/distributed-service/tests/nested_services/default.nix b/lib/inventory/distributed-service/tests/nested_services/default.nix index 509276c9b..eb066bd68 100644 --- a/lib/inventory/distributed-service/tests/nested_services/default.nix +++ b/lib/inventory/distributed-service/tests/nested_services/default.nix @@ -1,4 +1,8 @@ { 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; }; } diff --git a/lib/inventory/distributed-service/tests/nested_services/multi_import_duplication.nix b/lib/inventory/distributed-service/tests/nested_services/multi_import_duplication.nix new file mode 100644 index 000000000..2d5184e78 --- /dev/null +++ b/lib/inventory/distributed-service/tests/nested_services/multi_import_duplication.nix @@ -0,0 +1,125 @@ +{ 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.inventory.evalClanService { + modules = [ + (consumer-A) + ]; + prefix = [ ]; + }; + eval2 = clanLib.inventory.evalClanService { + 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" + ]; + }; +} diff --git a/lib/inventory/distributed-service/tests/nested_services/multi_machine.nix b/lib/inventory/distributed-service/tests/nested_services/multi_machine.nix new file mode 100644 index 000000000..520a41941 --- /dev/null +++ b/lib/inventory/distributed-service/tests/nested_services/multi_machine.nix @@ -0,0 +1,108 @@ +{ 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.inventory.evalClanService { + 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"; + }; + }; + }; + }; +}