add support for systemd mount units
This is mainly useful for specifying mounts that depend on other units. For example sshfs or davfs need network (and possibly nameservices). While systemd makes a distinction between local and remote filesystems, this only works for in-kernel filesystems such as nfs and cifs. fuse-based filesystems (such as sshfs and davs) are classified as local, so they fail without networking. By explicitly declaring these mounts as full systemd units (as opposed to having systemd generate them automatically from /etc/fstab), dependencies can be specified as on every other unit. In the future, we can probably port NixOS' filesystems handling to use these native systemd.mount units and skip /etc/fstab altogether, but this probably requires additional changes, such as starting systemd even earlier during boot (stage 1).
This commit is contained in:
parent
19e8ffc43f
commit
16a9bcfe81
@ -202,4 +202,51 @@ rec {
|
||||
|
||||
};
|
||||
|
||||
mountOptions = unitOptions // {
|
||||
|
||||
what = mkOption {
|
||||
default = "";
|
||||
example = "/dev/sda1";
|
||||
type = types.uniq types.string;
|
||||
description = "Absolute path of device node, file or other resource. (Mandatory)";
|
||||
};
|
||||
|
||||
where = mkOption {
|
||||
default = "";
|
||||
example = "/mnt";
|
||||
type = types.uniq types.string;
|
||||
description = ''
|
||||
Absolute path of a directory of the mount point.
|
||||
Will be created if it doesn't exist. (Mandatory)
|
||||
'';
|
||||
};
|
||||
|
||||
type = mkOption {
|
||||
default = "";
|
||||
example = "ext4";
|
||||
type = types.uniq types.string;
|
||||
description = "File system type.";
|
||||
};
|
||||
|
||||
options = mkOption {
|
||||
default = "";
|
||||
example = "noatime";
|
||||
type = types.string;
|
||||
merge = concatStringsSep ",";
|
||||
description = "Options used to mount the file system.";
|
||||
};
|
||||
|
||||
mountConfig = mkOption {
|
||||
default = {};
|
||||
example = { DirectoryMode = "0775"; };
|
||||
type = types.attrs;
|
||||
description = ''
|
||||
Each attribute in this set specifies an option in the
|
||||
<literal>[Mount]</literal> section of the unit. See
|
||||
<citerefentry><refentrytitle>systemd.mount</refentrytitle>
|
||||
<manvolnum>5</manvolnum></citerefentry> for details.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
}
|
@ -198,6 +198,19 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
mountConfig = { name, config, ... }: {
|
||||
config = {
|
||||
mountConfig =
|
||||
{ What = config.what;
|
||||
Where = config.where;
|
||||
} // optionalAttrs (config.type != "") {
|
||||
Type = config.type;
|
||||
} // optionalAttrs (config.options != "") {
|
||||
Options = config.options;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
toOption = x:
|
||||
if x == true then "true"
|
||||
else if x == false then "false"
|
||||
@ -277,6 +290,29 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
# this is by no means the full escaping-logic systemd uses
|
||||
# so feel free to extend this further.
|
||||
mountName = path:
|
||||
let escaped = replaceChars [ "-" " " "/" ]
|
||||
[ "\x2d" "\x20" "-" ] (toString path);
|
||||
in if (substring 0 1 escaped == "-")
|
||||
then substring 1 (sub (stringLength escaped) 1) escaped
|
||||
else escaped;
|
||||
|
||||
mountToUnit = name: def:
|
||||
assert def.mountConfig.What != "";
|
||||
assert def.mountConfig.Where != "";
|
||||
{ inherit (def) wantedBy enable;
|
||||
text =
|
||||
''
|
||||
[Unit]
|
||||
${attrsToSection def.unitConfig}
|
||||
|
||||
[Mount]
|
||||
${attrsToSection def.mountConfig}
|
||||
'';
|
||||
};
|
||||
|
||||
nixosUnits = mapAttrsToList makeUnit cfg.units;
|
||||
|
||||
units = pkgs.runCommand "units" { preferLocalBuild = true; }
|
||||
@ -387,6 +423,17 @@ in
|
||||
description = "Definition of systemd socket units.";
|
||||
};
|
||||
|
||||
boot.systemd.mounts = mkOption {
|
||||
default = [];
|
||||
type = types.listOf types.optionSet;
|
||||
options = [ mountOptions unitConfig mountConfig ];
|
||||
description = ''
|
||||
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.
|
||||
'';
|
||||
};
|
||||
|
||||
boot.systemd.defaultUnit = mkOption {
|
||||
default = "multi-user.target";
|
||||
type = types.uniq types.string;
|
||||
@ -501,7 +548,10 @@ in
|
||||
{ "rescue.service".text = rescueService; }
|
||||
// mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets
|
||||
// mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services
|
||||
// mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.sockets;
|
||||
// mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.sockets
|
||||
// listToAttrs (map
|
||||
(v: let n = mountName v.where;
|
||||
in nameValuePair "${n}.mount" (mountToUnit n v)) cfg.mounts);
|
||||
|
||||
system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled [
|
||||
"CGROUPS" "AUTOFS4_FS" "DEVTMPFS"
|
||||
|
Loading…
Reference in New Issue
Block a user