Add assertions and warnings to modular services

This commit is contained in:
Robert Hensing
2025-07-20 01:35:14 +02:00
parent 1acabeebed
commit 109a6a9d1e
5 changed files with 147 additions and 8 deletions

View File

@@ -32,5 +32,7 @@
};
};
# impl of assertions is in <nixpkgs/nixos/modules/system/activation/top-level.nix>
# impl of assertions is in
# - <nixpkgs/nixos/modules/system/activation/top-level.nix>
# - <nixpkgs/nixos/modules/system/service/portable/lib.nix>
}

View File

@@ -0,0 +1,33 @@
{ lib, ... }:
let
inherit (lib) concatLists mapAttrsToList showOption;
in
rec {
flattenMapServicesConfigToList =
f: loc: config:
f loc config
++ concatLists (
mapAttrsToList (
k: v:
flattenMapServicesConfigToList f (
loc
++ [
"services"
k
]
) v
) config.services
);
getWarnings = flattenMapServicesConfigToList (
loc: config: map (msg: "in ${showOption loc}: ${msg}") config.warnings
);
getAssertions = flattenMapServicesConfigToList (
loc: config:
map (ass: {
message = "in ${showOption loc}: ${ass.message}";
assertion = ass.assertion;
}) config.assertions
);
}

View File

@@ -21,6 +21,11 @@ let
};
in
{
# https://nixos.org/manual/nixos/unstable/#modular-services
_class = "service";
imports = [
../../../misc/assertions.nix
];
options = {
services = mkOption {
type = types.attrsOf (

View File

@@ -5,6 +5,8 @@ let
inherit (lib) mkOption types;
portable-lib = import ./lib.nix { inherit lib; };
dummyPkg =
name:
derivation {
@@ -21,6 +23,15 @@ let
executable = "/usr/bin/echo"; # *giggles*
args = [ "hello" ];
};
assertions = [
{
assertion = false;
message = "you can't enable this for that reason";
}
];
warnings = [
"The `foo' service is deprecated and will go away soon!"
];
};
service2 = {
process = {
@@ -32,10 +43,25 @@ let
};
service3 = {
process = {
executable = dummyPkg "cowsay-ng" // {
meta.mainProgram = "cowsay";
executable = "/bin/false";
args = [ ];
};
services.exclacow = {
process = {
executable = dummyPkg "cowsay-ng" // {
meta.mainProgram = "cowsay";
};
args = [ "!" ];
};
args = [ "!" ];
assertions = [
{
assertion = false;
message = "you can't enable this for such reason";
}
];
warnings = [
"The `bar' service is deprecated and will go away soon!"
];
};
};
};
@@ -69,6 +95,15 @@ let
args = [ "hello" ];
};
services = { };
assertions = [
{
assertion = false;
message = "you can't enable this for that reason";
}
];
warnings = [
"The `foo' service is deprecated and will go away soon!"
];
};
service2 = {
process = {
@@ -76,17 +111,59 @@ let
args = [ "world" ];
};
services = { };
assertions = [ ];
warnings = [ ];
};
service3 = {
process = {
executable = "${dummyPkg "cowsay-ng"}/bin/cowsay";
args = [ "!" ];
executable = "/bin/false";
args = [ ];
};
services = { };
services.exclacow = {
process = {
executable = "${dummyPkg "cowsay-ng"}/bin/cowsay";
args = [ "!" ];
};
services = { };
assertions = [
{
assertion = false;
message = "you can't enable this for such reason";
}
];
warnings = [ "The `bar' service is deprecated and will go away soon!" ];
};
assertions = [ ];
warnings = [ ];
};
};
};
assert
portable-lib.getWarnings [ "service1" ] exampleEval.config.services.service1 == [
"in service1: The `foo' service is deprecated and will go away soon!"
];
assert
portable-lib.getAssertions [ "service1" ] exampleEval.config.services.service1 == [
{
message = "in service1: you can't enable this for that reason";
assertion = false;
}
];
assert
portable-lib.getWarnings [ "service3" ] exampleEval.config.services.service3 == [
"in service3.services.exclacow: The `bar' service is deprecated and will go away soon!"
];
assert
portable-lib.getAssertions [ "service3" ] exampleEval.config.services.service3 == [
{
message = "in service3.services.exclacow: you can't enable this for such reason";
assertion = false;
}
];
"ok";
in

View File

@@ -1,12 +1,21 @@
{
lib,
config,
options,
pkgs,
...
}:
let
inherit (lib) concatMapAttrs mkOption types;
inherit (lib)
concatMapAttrs
mkOption
types
concatLists
mapAttrsToList
;
portable-lib = import ../portable/lib.nix { inherit lib; };
dash =
before: after:
@@ -57,6 +66,19 @@ in
# Second half of the magic: siphon units that were defined in isolation to the system
config = {
assertions = concatLists (
mapAttrsToList (
name: cfg: portable-lib.getAssertions (options.system.services.loc ++ [ name ]) cfg
) config.system.services
);
warnings = concatLists (
mapAttrsToList (
name: cfg: portable-lib.getWarnings (options.system.services.loc ++ [ name ]) cfg
) config.system.services
);
systemd.services = concatMapAttrs (
serviceName: topLevelService: makeUnits "services" serviceName topLevelService
) config.system.services;