infrastructure/modules/nixos/nfs.nix
2024-05-13 15:31:34 -07:00

150 lines
4 KiB
Nix

{
pkgs,
config,
lib,
...
}: let
inherit (lib.options) mkOption;
inherit (lib.modules) mkMerge mkIf mkBefore mkForce mkOptionDefault;
inherit (lib.lists) optional;
inherit (lib.attrsets) mapAttrsToList;
inherit (lib.lists) toList;
inherit (lib.strings) optionalString concatStringsSep concatMapStringsSep;
cfg = config.services.nfs;
clientEnabled = config.boot.supportedFilesystems.nfs or config.boot.supportedFilesystems.nfs4 or false;
enabled = cfg.server.enable || clientEnabled;
openPorts = [
(mkIf cfg.server.enable 2049)
(mkIf config.services.rpcbind.enable 111)
(mkIf (cfg.server.statdPort != null) cfg.server.statdPort)
(mkIf (cfg.server.lockdPort != null) cfg.server.lockdPort)
(mkIf (cfg.server.mountdPort != null) cfg.server.mountdPort)
];
concatFlags = concatStringsSep ",";
clientModule = {
config,
name,
...
}: {
options = with lib.types; {
machine = mkOption {
type = oneOf [str (listOf str)];
default = name;
example = "*";
};
flags = mkOption {
type = listOf str;
default = [];
};
entry = mkOption {
type = str;
};
};
config = {
entry = let
flags = optionalString (config.flags != []) "(${concatFlags config.flags})";
machines = toList config.machine;
in
mkOptionDefault (concatMapStringsSep " " (machine: machine + flags) machines);
};
};
exportModule = {
config,
name,
...
}: {
options = with lib.types; {
path = mkOption {
type = path;
default = name;
};
flags = mkOption {
type = listOf str;
};
clients = mkOption {
type = attrsOf (submodule clientModule);
};
fileLine = mkOption {
type = str;
};
};
config = {
flags = mkOptionDefault (cfg.export.flagSets.common or []);
fileLine = let
parts =
[config.path]
++ optional (config.flags != []) "-${concatFlags config.flags}"
++ mapAttrsToList (_: client: client.entry) config.clients;
in
mkOptionDefault (concatStringsSep " " parts);
};
};
in {
options.services.nfs = with lib.types; {
export = {
flagSets = mkOption {
type = lazyAttrsOf (listOf str);
default = {
common = ["no_subtree_check"];
};
};
root = mkOption {
type = nullOr (submodule [
exportModule
({...}: {
flags = mkMerge [
(cfg.export.flagSets.common or [])
];
})
]);
default = null;
};
paths = mkOption {
type = attrsOf (submodule exportModule);
default = {};
};
};
};
config = {
services.nfs = {
server.exports = mkMerge (
optional (cfg.export.root != null) (mkBefore cfg.export.root.fileLine)
++ mapAttrsToList (_: export: export.fileLine) cfg.export.paths
);
};
networking.firewall.interfaces.local = mkIf enabled {
allowedTCPPorts = openPorts;
allowedUDPPorts = openPorts;
};
systemd.services = {
auth-rpcgss-module = mkIf (enabled && !config.boot.modprobeConfig.enable) {
serviceConfig.ExecStart = mkForce [
""
"${pkgs.coreutils}/bin/true"
];
};
rpc-svcgssd = mkIf enabled {
enable = mkIf (!cfg.server.enable) false;
wantedBy = mkIf (cfg.server.enable && (config.security.krb5.enable || config.security.ipa.enable)) [
"nfs-server.service"
];
};
nfs-mountd = mkIf cfg.server.enable {
environment.LD_LIBRARY_PATH = config.system.nssModules.path;
};
};
systemd.mounts = mkIf (cfg.server.enable && cfg.export.root != null) [
rec {
type = "tmpfs";
options = "rw,size=256k";
what = "none";
where = cfg.export.root.path;
requiredBy = [
"nfs-server.service"
"nfs-mountd.service"
];
before = requiredBy;
}
];
};
}