systemd: make the unit option type more robust

This should allow more sensible merging behavior. In particular, with
this change it is possible to use, for example, `mkForce` for greater
control of merging.

Fixes #543
This commit is contained in:
Robert Helgesson 2019-04-10 00:40:45 +02:00
parent d49b514aa6
commit 12cb82af91
No known key found for this signature in database
GPG key ID: 36BDAA14C2797E89
2 changed files with 44 additions and 8 deletions

View file

@ -1019,6 +1019,36 @@ in
A new module is available: 'services.xcape'.
'';
}
{
time = "2019-04-11T22:50:10+00:00";
condition = hostPlatform.isLinux;
message = ''
The type used for the systemd unit options under
systemd.user.services, systemd.user.sockets, etc.
has been changed to offer more robust merging of configurations.
If you don't override values within systemd units then you are not
affected by this change. Unfortunately, if you do override unit values
you may encounter errors due to this change.
In particular, if you get an error saying that a "unique option" is
"defined multiple times" then you need to use 'lib.mkForce'. For
example,
systemd.user.services.foo.Service.ExecStart = "/foo/bar";
becomes
systemd.user.services.foo.Service.ExecStart = lib.mkForce "/foo/bar";
We had to make this change because the old merging was causing too
many confusing situations for people. Apologies for potentially
breaking your configuration!
'';
}
];
};
}

View file

@ -58,9 +58,14 @@ let
servicesStartTimeoutMs = builtins.toString cfg.servicesStartTimeoutMs;
attrsRecursivelyMerged = types.attrs // {
merge = loc: foldl' (res: def: recursiveUpdate res def.value) {};
};
unitType = unitKind: with types;
let
primitive = either bool (either int str);
in
attrsOf (attrsOf (attrsOf (either primitive (listOf primitive))))
// {
description = "systemd ${unitKind} unit configuration";
};
unitDescription = type: ''
Definition of systemd per-user ${type} units. Attributes are
@ -78,6 +83,7 @@ let
{
Unit = {
Description = "Example description";
Documentation = [ "man:example(1)" "man:example(5)" ];
};
${type} = {
@ -113,35 +119,35 @@ in
services = mkOption {
default = {};
type = attrsRecursivelyMerged;
type = unitType "service";
description = unitDescription "service";
example = unitExample "Service";
};
sockets = mkOption {
default = {};
type = attrsRecursivelyMerged;
type = unitType "socket";
description = unitDescription "socket";
example = unitExample "Socket";
};
targets = mkOption {
default = {};
type = attrsRecursivelyMerged;
type = unitType "target";
description = unitDescription "target";
example = unitExample "Target";
};
timers = mkOption {
default = {};
type = attrsRecursivelyMerged;
type = unitType "timer";
description = unitDescription "timer";
example = unitExample "Timer";
};
paths = mkOption {
default = {};
type = attrsRecursivelyMerged;
type = unitType "path";
description = unitDescription "path";
example = unitExample "Path";
};