Major overhaul of the nix side of things.
This commit is contained in:
parent
9aaa5e58f7
commit
9759c2da12
6 changed files with 418 additions and 210 deletions
47
README.md
47
README.md
|
|
@ -56,36 +56,31 @@ which should contain a `default.nix` file which functions as the entrance point.
|
||||||
A simple System Manager module could look something like this:
|
A simple System Manager module could look something like this:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ config, lib, pkgs, ... }:
|
{ config
|
||||||
let
|
, lib
|
||||||
etcFiles = {
|
, pkgs
|
||||||
"foo.conf".text = ''
|
, ... }:
|
||||||
launch_the_rockets = true
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
{
|
||||||
foo = {
|
config.system-manager = {
|
||||||
enable = true;
|
environment.etc = {
|
||||||
serviceConfig = {
|
"foo.conf".text = ''
|
||||||
Type = "oneshot";
|
launch_the_rockets = true
|
||||||
RemainAfterExit = true;
|
|
||||||
};
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
script = ''
|
|
||||||
echo "We launched the rockets!"
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
systemd.services = {
|
||||||
in
|
foo = {
|
||||||
{
|
enable = true;
|
||||||
config = {
|
serviceConfig = {
|
||||||
system-manager = {
|
Type = "oneshot";
|
||||||
etcFiles = lib.attrNames etcFiles;
|
RemainAfterExit = true;
|
||||||
services = lib.attrNames services;
|
};
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
script = ''
|
||||||
|
echo "We launched the rockets!"
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
environment.etc = etcFiles;
|
|
||||||
systemd = { inherit services; };
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
25
nix/lib.nix
25
nix/lib.nix
|
|
@ -16,6 +16,7 @@ in
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
inherit (self.packages.${system}) system-manager;
|
inherit (self.packages.${system}) system-manager;
|
||||||
|
|
||||||
|
# TODO can we call lib.evalModules directly instead of building a NixOS system?
|
||||||
nixosConfig = (lib.nixosSystem {
|
nixosConfig = (lib.nixosSystem {
|
||||||
inherit system;
|
inherit system;
|
||||||
modules = [
|
modules = [
|
||||||
|
|
@ -33,17 +34,13 @@ in
|
||||||
else lib.showWarnings nixosConfig.warnings drv;
|
else lib.showWarnings nixosConfig.warnings drv;
|
||||||
|
|
||||||
services =
|
services =
|
||||||
lib.listToAttrs
|
lib.mapAttrs'
|
||||||
(map
|
(unitName: unit:
|
||||||
(name:
|
lib.nameValuePair unitName {
|
||||||
let
|
storePath =
|
||||||
serviceName = "${name}.service";
|
''${unit.unit}/${unitName}'';
|
||||||
in
|
})
|
||||||
lib.nameValuePair serviceName {
|
nixosConfig.system-manager.systemd.units;
|
||||||
storePath =
|
|
||||||
''${nixosConfig.systemd.units."${serviceName}".unit}/${serviceName}'';
|
|
||||||
})
|
|
||||||
nixosConfig.system-manager.services);
|
|
||||||
|
|
||||||
servicesPath = pkgs.writeTextFile {
|
servicesPath = pkgs.writeTextFile {
|
||||||
name = "services";
|
name = "services";
|
||||||
|
|
@ -54,8 +51,6 @@ in
|
||||||
# TODO: handle globbing
|
# TODO: handle globbing
|
||||||
etcFiles =
|
etcFiles =
|
||||||
let
|
let
|
||||||
isManaged = name: lib.elem name nixosConfig.system-manager.etcFiles;
|
|
||||||
|
|
||||||
addToStore = name: file: pkgs.runCommandLocal "${name}-etc-link" { } ''
|
addToStore = name: file: pkgs.runCommandLocal "${name}-etc-link" { } ''
|
||||||
mkdir -p "$out/$(dirname "${file.target}")"
|
mkdir -p "$out/$(dirname "${file.target}")"
|
||||||
ln -s "${file.source}" "$out/${file.target}"
|
ln -s "${file.source}" "$out/${file.target}"
|
||||||
|
|
@ -68,8 +63,8 @@ in
|
||||||
'';
|
'';
|
||||||
|
|
||||||
filteredEntries = lib.filterAttrs
|
filteredEntries = lib.filterAttrs
|
||||||
(name: etcFile: etcFile.enable && isManaged name)
|
(_name: etcFile: etcFile.enable)
|
||||||
nixosConfig.environment.etc;
|
nixosConfig.system-manager.environment.etc;
|
||||||
|
|
||||||
srcDrvs = lib.mapAttrs addToStore filteredEntries;
|
srcDrvs = lib.mapAttrs addToStore filteredEntries;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,84 +2,81 @@
|
||||||
, pkgs
|
, pkgs
|
||||||
, ...
|
, ...
|
||||||
}:
|
}:
|
||||||
let
|
|
||||||
services =
|
|
||||||
lib.listToAttrs
|
|
||||||
(lib.flip lib.genList 10 (ix:
|
|
||||||
lib.nameValuePair "service-${toString ix}"
|
|
||||||
{
|
|
||||||
enable = true;
|
|
||||||
description = "service-${toString ix}";
|
|
||||||
wants = [ "network-online.target" ];
|
|
||||||
after = [
|
|
||||||
"network-online.target"
|
|
||||||
"avahi-daemon.service"
|
|
||||||
"chrony.service"
|
|
||||||
"nss-lookup.target"
|
|
||||||
"tinc.service"
|
|
||||||
"pulseaudio.service"
|
|
||||||
];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
ExecReload = "${lib.getBin pkgs.coreutils}/bin/true";
|
|
||||||
};
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
requiredBy = lib.mkIf (ix > 5) [ "service-0.service" ];
|
|
||||||
script = ''
|
|
||||||
sleep ${if ix > 5 then "2" else "1"}
|
|
||||||
'';
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
etcFiles = {
|
|
||||||
foo = {
|
|
||||||
text = ''
|
|
||||||
This is just a test!
|
|
||||||
'';
|
|
||||||
target = "foo_test";
|
|
||||||
};
|
|
||||||
|
|
||||||
"baz/bar/foo2" = {
|
|
||||||
text = ''
|
|
||||||
Another test!
|
|
||||||
'';
|
|
||||||
mode = "symlink";
|
|
||||||
};
|
|
||||||
|
|
||||||
foo3 = {
|
|
||||||
text = "boo!";
|
|
||||||
mode = "0700";
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
};
|
|
||||||
|
|
||||||
"a/nested/example/foo3" = {
|
|
||||||
text = "boo!";
|
|
||||||
mode = "0764";
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
};
|
|
||||||
|
|
||||||
"a/nested/example2/foo3" = {
|
|
||||||
text = "boo!";
|
|
||||||
mode = "0764";
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
};
|
|
||||||
|
|
||||||
out-of-store = {
|
|
||||||
source = "/run/systemd/system/";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
config = {
|
config = {
|
||||||
system-manager = {
|
system-manager = {
|
||||||
etcFiles = lib.attrNames etcFiles;
|
environment.etc = {
|
||||||
services = lib.attrNames services;
|
foo = {
|
||||||
|
text = ''
|
||||||
|
This is just a test!
|
||||||
|
'';
|
||||||
|
target = "foo_test";
|
||||||
|
};
|
||||||
|
|
||||||
|
"foo.conf".text = ''
|
||||||
|
launch_the_rockets = true
|
||||||
|
'';
|
||||||
|
|
||||||
|
"baz/bar/foo2" = {
|
||||||
|
text = ''
|
||||||
|
Another test!
|
||||||
|
'';
|
||||||
|
mode = "symlink";
|
||||||
|
};
|
||||||
|
|
||||||
|
foo3 = {
|
||||||
|
text = "boo!";
|
||||||
|
mode = "0700";
|
||||||
|
user = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
"a/nested/example/foo3" = {
|
||||||
|
text = "boo!";
|
||||||
|
mode = "0764";
|
||||||
|
user = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
"a/nested/example2/foo3" = {
|
||||||
|
text = "boo!";
|
||||||
|
mode = "0764";
|
||||||
|
user = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
out-of-store = {
|
||||||
|
source = "/run/systemd/system/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
systemd.services =
|
||||||
|
lib.listToAttrs
|
||||||
|
(lib.flip lib.genList 10 (ix:
|
||||||
|
lib.nameValuePair "service-${toString ix}"
|
||||||
|
{
|
||||||
|
enable = true;
|
||||||
|
description = "service-${toString ix}";
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
after = [
|
||||||
|
"network-online.target"
|
||||||
|
"avahi-daemon.service"
|
||||||
|
"chrony.service"
|
||||||
|
"nss-lookup.target"
|
||||||
|
"tinc.service"
|
||||||
|
"pulseaudio.service"
|
||||||
|
];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
ExecReload = "${lib.getBin pkgs.coreutils}/bin/true";
|
||||||
|
};
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
requiredBy = lib.mkIf (ix > 5) [ "service-0.service" ];
|
||||||
|
script = ''
|
||||||
|
sleep ${if ix > 5 then "2" else "1"}
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
environment.etc = etcFiles;
|
|
||||||
systemd = { inherit services; };
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
118
nix/modules/etc.nix
Normal file
118
nix/modules/etc.nix
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
{ lib
|
||||||
|
, pkgs
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
options.system-manager = {
|
||||||
|
environment.etc = lib.mkOption {
|
||||||
|
default = { };
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
{ example-configuration-file =
|
||||||
|
{ source = "/nix/store/.../etc/dir/file.conf.example";
|
||||||
|
mode = "0440";
|
||||||
|
};
|
||||||
|
"default/useradd".text = "GROUP=100 ...";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Set of files that have to be linked in {file}`/etc`.
|
||||||
|
'';
|
||||||
|
|
||||||
|
type = lib.types.attrsOf (lib.types.submodule (
|
||||||
|
{ name, config, options, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
|
||||||
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Whether this /etc file should be generated. This
|
||||||
|
option allows specific /etc files to be disabled.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
target = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Name of symlink (relative to
|
||||||
|
{file}`/etc`). Defaults to the attribute
|
||||||
|
name.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
text = lib.mkOption {
|
||||||
|
default = null;
|
||||||
|
type = lib.types.nullOr lib.types.lines;
|
||||||
|
description = lib.mdDoc "Text of the file.";
|
||||||
|
};
|
||||||
|
|
||||||
|
source = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
description = lib.mdDoc "Path of the source file.";
|
||||||
|
};
|
||||||
|
|
||||||
|
mode = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "symlink";
|
||||||
|
example = "0600";
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
If set to something else than `symlink`,
|
||||||
|
the file is copied instead of symlinked, with the given
|
||||||
|
file mode.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
uid = lib.mkOption {
|
||||||
|
default = 0;
|
||||||
|
type = lib.types.int;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
UID of created file. Only takes effect when the file is
|
||||||
|
copied (that is, the mode is not 'symlink').
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
gid = lib.mkOption {
|
||||||
|
default = 0;
|
||||||
|
type = lib.types.int;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
GID of created file. Only takes effect when the file is
|
||||||
|
copied (that is, the mode is not 'symlink').
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
user = lib.mkOption {
|
||||||
|
default = "+${toString config.uid}";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
User name of created file.
|
||||||
|
Only takes effect when the file is copied (that is, the mode is not 'symlink').
|
||||||
|
Changing this option takes precedence over `uid`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
group = lib.mkOption {
|
||||||
|
default = "+${toString config.gid}";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Group name of created file.
|
||||||
|
Only takes effect when the file is copied (that is, the mode is not 'symlink').
|
||||||
|
Changing this option takes precedence over `gid`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
target = lib.mkDefault name;
|
||||||
|
source = lib.mkIf (config.text != null) (
|
||||||
|
let name' = "etc-" + baseNameOf name;
|
||||||
|
in lib.mkDerivedConfig options.text (pkgs.writeText name')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,20 +1,14 @@
|
||||||
{ lib
|
{ lib
|
||||||
, config
|
, config
|
||||||
, pkgs
|
|
||||||
, ...
|
, ...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
imports = [
|
||||||
|
./etc.nix
|
||||||
|
./systemd.nix
|
||||||
|
];
|
||||||
|
|
||||||
options.system-manager = {
|
options.system-manager = {
|
||||||
services = lib.mkOption {
|
|
||||||
type = with lib.types; listOf str;
|
|
||||||
default = [ ];
|
|
||||||
};
|
|
||||||
|
|
||||||
etcFiles = lib.mkOption {
|
|
||||||
type = with lib.types; listOf str;
|
|
||||||
default = [ ];
|
|
||||||
};
|
|
||||||
|
|
||||||
allowAnyDistro = lib.mkEnableOption "the usage of system-manager on untested distributions";
|
allowAnyDistro = lib.mkEnableOption "the usage of system-manager on untested distributions";
|
||||||
|
|
||||||
preActivationAssertions = lib.mkOption {
|
preActivationAssertions = lib.mkOption {
|
||||||
|
|
@ -44,28 +38,6 @@
|
||||||
};
|
};
|
||||||
system.stateVersion = lib.mkDefault lib.trivial.release;
|
system.stateVersion = lib.mkDefault lib.trivial.release;
|
||||||
|
|
||||||
assertions =
|
|
||||||
lib.flip map config.system-manager.etcFiles
|
|
||||||
(entry:
|
|
||||||
{
|
|
||||||
assertion = lib.hasAttr entry config.environment.etc;
|
|
||||||
message = lib.concatStringsSep " " [
|
|
||||||
"The entry ${entry} that was passed to system-manager.etcFiles"
|
|
||||||
"is not present in environment.etc"
|
|
||||||
];
|
|
||||||
}
|
|
||||||
) ++
|
|
||||||
lib.flip map config.system-manager.services
|
|
||||||
(entry:
|
|
||||||
{
|
|
||||||
assertion = lib.hasAttr entry config.systemd.services;
|
|
||||||
message = lib.concatStringsSep " " [
|
|
||||||
"The entry ${entry} that was passed to system-manager.services"
|
|
||||||
"is not present in systemd.services"
|
|
||||||
];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
system-manager.preActivationAssertions = {
|
system-manager.preActivationAssertions = {
|
||||||
osVersion =
|
osVersion =
|
||||||
let
|
let
|
||||||
|
|
@ -86,66 +58,5 @@
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Add the system directory for systemd
|
|
||||||
system-manager.etcFiles = [ "systemd/system" ];
|
|
||||||
|
|
||||||
environment.etc =
|
|
||||||
let
|
|
||||||
allowCollisions = false;
|
|
||||||
|
|
||||||
enabledUnits =
|
|
||||||
lib.filterAttrs
|
|
||||||
(name: _: lib.elem
|
|
||||||
name
|
|
||||||
(map (name: "${name}.service") config.system-manager.services))
|
|
||||||
config.systemd.units;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
"systemd/system".source = lib.mkForce (pkgs.runCommand "system-manager-units"
|
|
||||||
{
|
|
||||||
preferLocalBuild = true;
|
|
||||||
allowSubstitutes = false;
|
|
||||||
}
|
|
||||||
''
|
|
||||||
mkdir -p $out
|
|
||||||
|
|
||||||
for i in ${toString (lib.mapAttrsToList (n: v: v.unit) enabledUnits)}; do
|
|
||||||
fn=$(basename $i/*)
|
|
||||||
if [ -e $out/$fn ]; then
|
|
||||||
if [ "$(readlink -f $i/$fn)" = /dev/null ]; then
|
|
||||||
ln -sfn /dev/null $out/$fn
|
|
||||||
else
|
|
||||||
${if allowCollisions then ''
|
|
||||||
mkdir -p $out/$fn.d
|
|
||||||
ln -s $i/$fn $out/$fn.d/overrides.conf
|
|
||||||
'' else ''
|
|
||||||
echo "Found multiple derivations configuring $fn!"
|
|
||||||
exit 1
|
|
||||||
''}
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
ln -fs $i/$fn $out/
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
${lib.concatStrings (
|
|
||||||
lib.mapAttrsToList (name: unit:
|
|
||||||
lib.concatMapStrings (name2: ''
|
|
||||||
mkdir -p $out/'${name2}.wants'
|
|
||||||
ln -sfn '../${name}' $out/'${name2}.wants'/
|
|
||||||
'') (unit.wantedBy or [])
|
|
||||||
) enabledUnits)}
|
|
||||||
|
|
||||||
${lib.concatStrings (
|
|
||||||
lib.mapAttrsToList (name: unit:
|
|
||||||
lib.concatMapStrings (name2: ''
|
|
||||||
mkdir -p $out/'${name2}.requires'
|
|
||||||
ln -sfn '../${name}' $out/'${name2}.requires'/
|
|
||||||
'') (unit.requiredBy or [])
|
|
||||||
) enabledUnits)}
|
|
||||||
''
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
192
nix/modules/systemd.nix
Normal file
192
nix/modules/systemd.nix
Normal file
|
|
@ -0,0 +1,192 @@
|
||||||
|
{ lib
|
||||||
|
, config
|
||||||
|
, pkgs
|
||||||
|
, utils
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.system-manager.systemd;
|
||||||
|
|
||||||
|
inherit (utils) systemdUtils;
|
||||||
|
systemd-lib = utils.systemdUtils.lib;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.system-manager.systemd = {
|
||||||
|
|
||||||
|
units = lib.mkOption {
|
||||||
|
description = lib.mdDoc "Definition of systemd units.";
|
||||||
|
default = { };
|
||||||
|
type = systemdUtils.types.units;
|
||||||
|
};
|
||||||
|
|
||||||
|
packages = lib.mkOption {
|
||||||
|
default = [ ];
|
||||||
|
type = lib.types.listOf lib.types.package;
|
||||||
|
example = lib.literalExpression "[ pkgs.systemd-cryptsetup-generator ]";
|
||||||
|
description = lib.mdDoc "Packages providing systemd units and hooks.";
|
||||||
|
};
|
||||||
|
|
||||||
|
targets = lib.mkOption {
|
||||||
|
default = { };
|
||||||
|
type = systemdUtils.types.targets;
|
||||||
|
description = lib.mdDoc "Definition of systemd target units.";
|
||||||
|
};
|
||||||
|
|
||||||
|
services = lib.mkOption {
|
||||||
|
default = { };
|
||||||
|
type = systemdUtils.types.services;
|
||||||
|
description = lib.mdDoc "Definition of systemd service units.";
|
||||||
|
};
|
||||||
|
|
||||||
|
sockets = lib.mkOption {
|
||||||
|
default = { };
|
||||||
|
type = systemdUtils.types.sockets;
|
||||||
|
description = lib.mdDoc "Definition of systemd socket units.";
|
||||||
|
};
|
||||||
|
|
||||||
|
timers = lib.mkOption {
|
||||||
|
default = { };
|
||||||
|
type = systemdUtils.types.timers;
|
||||||
|
description = lib.mdDoc "Definition of systemd timer units.";
|
||||||
|
};
|
||||||
|
|
||||||
|
paths = lib.mkOption {
|
||||||
|
default = { };
|
||||||
|
type = systemdUtils.types.paths;
|
||||||
|
description = lib.mdDoc "Definition of systemd path units.";
|
||||||
|
};
|
||||||
|
|
||||||
|
mounts = lib.mkOption {
|
||||||
|
default = [ ];
|
||||||
|
type = systemdUtils.types.mounts;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Definition of systemd mount units.
|
||||||
|
This is a list instead of an attrSet, because systemd mandates the names to be derived from
|
||||||
|
the 'where' attribute.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
automounts = lib.mkOption {
|
||||||
|
default = [ ];
|
||||||
|
type = systemdUtils.types.automounts;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Definition of systemd automount units.
|
||||||
|
This is a list instead of an attrSet, because systemd mandates the names to be derived from
|
||||||
|
the 'where' attribute.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
slices = lib.mkOption {
|
||||||
|
default = { };
|
||||||
|
type = systemdUtils.types.slices;
|
||||||
|
description = lib.mdDoc "Definition of slice configurations.";
|
||||||
|
};
|
||||||
|
|
||||||
|
generators = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf lib.types.path;
|
||||||
|
default = { };
|
||||||
|
example = { systemd-gpt-auto-generator = "/dev/null"; };
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Definition of systemd generators.
|
||||||
|
For each `NAME = VALUE` pair of the attrSet, a link is generated from
|
||||||
|
`/etc/systemd/system-generators/NAME` to `VALUE`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
shutdown = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf lib.types.path;
|
||||||
|
default = { };
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Definition of systemd shutdown executables.
|
||||||
|
For each `NAME = VALUE` pair of the attrSet, a link is generated from
|
||||||
|
`/etc/systemd/system-shutdown/NAME` to `VALUE`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
system-manager = {
|
||||||
|
systemd = {
|
||||||
|
timers =
|
||||||
|
lib.mapAttrs
|
||||||
|
(name: service:
|
||||||
|
{
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig.OnCalendar = service.startAt;
|
||||||
|
})
|
||||||
|
(lib.filterAttrs (name: service: service.enable && service.startAt != [ ]) cfg.services);
|
||||||
|
|
||||||
|
units =
|
||||||
|
lib.mapAttrs' (n: v: lib.nameValuePair "${n}.path" (systemd-lib.pathToUnit n v)) cfg.paths
|
||||||
|
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.service" (systemd-lib.serviceToUnit n v)) cfg.services
|
||||||
|
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.slice" (systemd-lib.sliceToUnit n v)) cfg.slices
|
||||||
|
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.socket" (systemd-lib.socketToUnit n v)) cfg.sockets
|
||||||
|
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.target" (systemd-lib.targetToUnit n v)) cfg.targets
|
||||||
|
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.timer" (systemd-lib.timerToUnit n v)) cfg.timers
|
||||||
|
// lib.listToAttrs (map
|
||||||
|
(v:
|
||||||
|
let n = utils.escapeSystemdPath v.where;
|
||||||
|
in lib.nameValuePair "${n}.mount" (systemd-lib.mountToUnit n v))
|
||||||
|
cfg.mounts)
|
||||||
|
// lib.listToAttrs (map
|
||||||
|
(v:
|
||||||
|
let n = utils.escapeSystemdPath v.where;
|
||||||
|
in lib.nameValuePair "${n}.automount" (systemd-lib.automountToUnit n v))
|
||||||
|
cfg.automounts);
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.etc =
|
||||||
|
let
|
||||||
|
allowCollisions = false;
|
||||||
|
|
||||||
|
enabledUnits = cfg.units;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"systemd/system".source = pkgs.runCommand "system-manager-units"
|
||||||
|
{
|
||||||
|
preferLocalBuild = true;
|
||||||
|
allowSubstitutes = false;
|
||||||
|
}
|
||||||
|
''
|
||||||
|
mkdir -p $out
|
||||||
|
|
||||||
|
for i in ${toString (lib.mapAttrsToList (n: v: v.unit) enabledUnits)}; do
|
||||||
|
fn=$(basename $i/*)
|
||||||
|
if [ -e $out/$fn ]; then
|
||||||
|
if [ "$(readlink -f $i/$fn)" = /dev/null ]; then
|
||||||
|
ln -sfn /dev/null $out/$fn
|
||||||
|
else
|
||||||
|
${if allowCollisions then ''
|
||||||
|
mkdir -p $out/$fn.d
|
||||||
|
ln -s $i/$fn $out/$fn.d/overrides.conf
|
||||||
|
'' else ''
|
||||||
|
echo "Found multiple derivations configuring $fn!"
|
||||||
|
exit 1
|
||||||
|
''}
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ln -fs $i/$fn $out/
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
${lib.concatStrings (
|
||||||
|
lib.mapAttrsToList (name: unit:
|
||||||
|
lib.concatMapStrings (name2: ''
|
||||||
|
mkdir -p $out/'${name2}.wants'
|
||||||
|
ln -sfn '../${name}' $out/'${name2}.wants'/
|
||||||
|
'') (unit.wantedBy or [])
|
||||||
|
) enabledUnits)}
|
||||||
|
|
||||||
|
${lib.concatStrings (
|
||||||
|
lib.mapAttrsToList (name: unit:
|
||||||
|
lib.concatMapStrings (name2: ''
|
||||||
|
mkdir -p $out/'${name2}.requires'
|
||||||
|
ln -sfn '../${name}' $out/'${name2}.requires'/
|
||||||
|
'') (unit.requiredBy or [])
|
||||||
|
) enabledUnits)}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue