Merge pull request 'services: allow inline modules' (#5652) from inline into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5652
This commit is contained in:
hsjobeki
2025-10-23 16:48:06 +00:00
5 changed files with 38 additions and 16 deletions

View File

@@ -216,7 +216,7 @@ in
options.extraModules = lib.mkOption { options.extraModules = lib.mkOption {
default = [ ]; default = [ ];
type = types.listOf (types.either types.deferredModule types.str); type = types.listOf types.deferredModule;
}; };
} }
) )

View File

@@ -40,12 +40,11 @@ let
name: name:
let let
v = set.${name}; v = set.${name};
loc = path ++ [ name ];
in in
if pred path v then if pred loc v then
[ [
(lib.nameValuePair name ( (lib.nameValuePair name (if lib.isAttrs v then filterAttrsRecursive' loc pred v else v))
if lib.isAttrs v then filterAttrsRecursive' (path ++ [ name ]) pred v else v
))
] ]
else else
[ ] [ ]
@@ -56,8 +55,7 @@ let
# Remove extraModules from serialization, # Remove extraModules from serialization,
# identified by: prefix + pathLength + name # identified by: prefix + pathLength + name
# inventory.instances.*.roles.*.extraModules # inventory.instances.*.roles.*.extraModules
path: _value: path: _value: !(lib.length path == 5 && ((lib.last path)) == "extraModules")
lib.length path <= 5 || lib.head path != "instances" || (lib.elemAt path 5) != "extraModules"
) exposedInventory; ) exposedInventory;
in in
{ {

View File

@@ -73,15 +73,8 @@ in
} }
``` ```
''; '';
apply = value: if lib.isString value then value else builtins.seq (builtins.toJSON value) value;
default = [ ]; default = [ ];
type = types.listOf ( type = types.listOf types.deferredModule;
types.oneOf [
types.str
types.path
(types.attrsOf types.anything)
]
);
}; };
}; };
} }

View File

@@ -28,7 +28,7 @@ class InventoryInstanceRoleMachine(TypedDict):
InventoryInstanceRoleExtramodulesType = list[dict[str, Any] | str] InventoryInstanceRoleExtramodulesType = list[Unknown]
InventoryInstanceRoleMachinesType = dict[str, InventoryInstanceRoleMachine] InventoryInstanceRoleMachinesType = dict[str, InventoryInstanceRoleMachine]
InventoryInstanceRoleSettingsType = Unknown InventoryInstanceRoleSettingsType = Unknown
InventoryInstanceRoleTagsType = dict[str, Any] | list[str] InventoryInstanceRoleTagsType = dict[str, Any] | list[str]

View File

@@ -316,3 +316,34 @@ def test_delete_static_service_instance(
# TODO: improve error message # TODO: improve error message
assert "Cannot delete path 'instances.static" in str(excinfo.value) assert "Cannot delete path 'instances.static" in str(excinfo.value)
@pytest.mark.with_core
def test_inline_extra_modules(clan_flake: Callable[..., Flake]) -> None:
"""ExtraModules are excluded from serialization to allow arbitrary inlining"""
# Data that can be mutated via API calls
mutable_inventory_json: Inventory = {
"instances": {
"static": {"module": {"name": "admin"}},
}
}
nix = r"""
{
inventory.instances.static = {
roles.default.extraModules = [
(_: { }) # non-serializable inline module
];
};
}
"""
flake = clan_flake(
{},
raw=nix,
mutable_inventory_json=mutable_inventory_json,
)
# Ensure preconditions
instances = list_service_instances(flake)
assert set(instances.keys()) == {"static"}