test(inventory/instances): add tests for per machine resolution
This commit is contained in:
@@ -59,4 +59,269 @@ in
|
|||||||
expr = res.evals ? "self-simple-module";
|
expr = res.evals ? "self-simple-module";
|
||||||
expected = true;
|
expected = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# A module can be imported multiple times
|
||||||
|
# A module can also have multiple instances within the same module
|
||||||
|
# This mean modules must be grouped together, imported once
|
||||||
|
# All instances should be included within one evaluation to make all of them available
|
||||||
|
test_module_grouping =
|
||||||
|
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 = "A-name";
|
||||||
|
};
|
||||||
|
|
||||||
|
perMachine = { }: { };
|
||||||
|
};
|
||||||
|
modules."B" = {
|
||||||
|
_class = "clan.service";
|
||||||
|
manifest = {
|
||||||
|
name = "B-name";
|
||||||
|
};
|
||||||
|
|
||||||
|
perMachine = { }: { };
|
||||||
|
};
|
||||||
|
# User config
|
||||||
|
instances."instance_foo" = {
|
||||||
|
module = {
|
||||||
|
name = "A";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
instances."instance_bar" = {
|
||||||
|
module = {
|
||||||
|
name = "B";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
instances."instance_baz" = {
|
||||||
|
module = {
|
||||||
|
name = "A";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Test that the module is mapped into the output
|
||||||
|
# We might change the attribute name in the future
|
||||||
|
expr = lib.mapAttrs (_n: v: builtins.length v) res.grouped;
|
||||||
|
expected = {
|
||||||
|
self-A = 2;
|
||||||
|
self-B = 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test_creates_all_instances =
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
|
||||||
|
perMachine = { }: { };
|
||||||
|
};
|
||||||
|
instances."instance_foo" = {
|
||||||
|
module = {
|
||||||
|
name = "A";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
instances."instance_bar" = {
|
||||||
|
module = {
|
||||||
|
name = "A";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
instances."instance_zaza" = {
|
||||||
|
module = {
|
||||||
|
name = "B";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Test that the module is mapped into the output
|
||||||
|
# We might change the attribute name in the future
|
||||||
|
expr = lib.attrNames res.evals.self-A.config.instances;
|
||||||
|
expected = [
|
||||||
|
"instance_bar"
|
||||||
|
"instance_foo"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Membership via roles
|
||||||
|
test_add_machines_directly =
|
||||||
|
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 = {}: {};
|
||||||
|
};
|
||||||
|
machines = {
|
||||||
|
jon = { };
|
||||||
|
sara = { };
|
||||||
|
hxi = { };
|
||||||
|
};
|
||||||
|
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
|
||||||
|
{
|
||||||
|
# Test that the module is mapped into the output
|
||||||
|
# We might change the attribute name in the future
|
||||||
|
expr = lib.attrNames res.evals.self-A.config.result.allMachines;
|
||||||
|
expected = [
|
||||||
|
"jon"
|
||||||
|
"sara"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Membership via tags
|
||||||
|
test_add_machines_via_tags =
|
||||||
|
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 = {}: {};
|
||||||
|
};
|
||||||
|
machines = {
|
||||||
|
jon = {
|
||||||
|
tags = [ "foo" ];
|
||||||
|
};
|
||||||
|
sara = {
|
||||||
|
tags = [ "foo" ];
|
||||||
|
};
|
||||||
|
hxi = { };
|
||||||
|
};
|
||||||
|
instances."instance_foo" = {
|
||||||
|
module = {
|
||||||
|
name = "A";
|
||||||
|
};
|
||||||
|
roles.peer.tags.foo = { };
|
||||||
|
};
|
||||||
|
instances."instance_zaza" = {
|
||||||
|
module = {
|
||||||
|
name = "B";
|
||||||
|
};
|
||||||
|
roles.peer.tags.all = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Test that the module is mapped into the output
|
||||||
|
# We might change the attribute name in the future
|
||||||
|
expr = lib.attrNames res.evals.self-A.config.result.allMachines;
|
||||||
|
expected = [
|
||||||
|
"jon"
|
||||||
|
"sara"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
per_machine_args = import ./per_machine_args.nix { inherit lib callInventoryAdapter; };
|
||||||
|
# test_per_machine_receives_instances =
|
||||||
|
# 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 = {};
|
||||||
|
# };
|
||||||
|
# };
|
||||||
}
|
}
|
||||||
|
|||||||
107
lib/distributed-service/tests/per_machine_args.nix
Normal file
107
lib/distributed-service/tests/per_machine_args.nix
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
{ 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.server.interface =
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
options.timeout = lib.mkOption {
|
||||||
|
type = lib.types.submodule;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
perMachine =
|
||||||
|
{ instances, ... }:
|
||||||
|
{
|
||||||
|
nixosModule = instances;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
instances."instance_zaza" = {
|
||||||
|
module = {
|
||||||
|
name = "B";
|
||||||
|
};
|
||||||
|
roles.peer.tags.all = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
filterInternals = lib.filterAttrs (n: _v: !lib.hasPrefix "_" n);
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
# settings should evaluate
|
||||||
|
test_per_machine_receives_instance_settings = {
|
||||||
|
expr = {
|
||||||
|
hasMachineSettings =
|
||||||
|
res.evals.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.machines.jon
|
||||||
|
? settings;
|
||||||
|
|
||||||
|
# settings are specific.
|
||||||
|
# Below we access:
|
||||||
|
# instance = instance_foo
|
||||||
|
# roles = peer
|
||||||
|
# machines = jon
|
||||||
|
specificMachineSettings = filterInternals res.evals.self-A.config.result.allMachines.jon.nixosModule.instance_foo.roles.peer.machines.jon.settings;
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
hasMachineSettings = true;
|
||||||
|
specificMachineSettings = {
|
||||||
|
timeout = "foo-peer-jon";
|
||||||
|
};
|
||||||
|
hasRoleSettings = true;
|
||||||
|
specificRoleSettings = {
|
||||||
|
timeout = "foo-peer";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user