refactor: separate out conditional and unconditional modules for nfs and samba

This commit is contained in:
Ceferino Patino 2026-06-29 22:39:17 -05:00
commit 224176d2d2
Signed by: c4patino
SSH key fingerprint: SHA256:Wu+cU1t+7zVT9wzew/4meNmeulo66NzMqc22MdDBgXI
4 changed files with 139 additions and 105 deletions

View file

@ -3,13 +3,17 @@
lib, lib,
namespace, namespace,
... ...
}: let } @ args: let
inherit (lib) types mkIf mkEnableOption mkOption mapAttrs' concatStringsSep; inherit (lib) types mkIf mkEnableOption mkMerge concatStringsSep;
inherit (lib.${namespace}) getAttrByNamespace mkOptionsWithNamespace resolveHostIP mkOpt mkRequiredOpt mkNullableOpt mkListOpt mkOptAttrset; inherit (lib.${namespace}) getAttrByNamespace mkOptionsWithNamespace resolveHostIP mkOpt mkRequiredOpt mkNullableOpt mkListOpt mkOptAttrset;
base = "${namespace}.services.storage.nfs"; base = "${namespace}.services.storage.nfs";
cfg = getAttrByNamespace config base; cfg = getAttrByNamespace config base;
networkCfg = getAttrByNamespace config "${namespace}.services.networking"; networkCfg = getAttrByNamespace config "${namespace}.services.networking";
in { in {
imports = [
(import ./mount.nix args)
];
options = with types; options = with types;
mkOptionsWithNamespace base { mkOptionsWithNamespace base {
enable = mkEnableOption "nfs"; enable = mkEnableOption "nfs";
@ -29,30 +33,8 @@ in {
}) {} "Set of NFS mounts with custom configuration."; }) {} "Set of NFS mounts with custom configuration.";
}; };
config = { config = mkIf cfg.enable {
fileSystems = let services.nfs.server = {
mapFolderToMount = name: mntCfg: let
hostIP = resolveHostIP networkCfg.devices mntCfg.host;
localPath =
if mntCfg.mountPath != null
then mntCfg.mountPath
else "/mnt/nfs/${name}";
in {
name = localPath;
value = {
device = "${hostIP}:${mntCfg.folder}";
fsType = "nfs";
options = [
"_netdev"
"nofail"
"x-systemd.automount"
];
};
};
in
cfg.mounts |> mapAttrs' mapFolderToMount;
services.nfs.server = mkIf cfg.enable {
enable = true; enable = true;
exports = let exports = let
mapMountToPermissions = mount: let mapMountToPermissions = mount: let
@ -68,10 +50,11 @@ in {
|> concatStringsSep "\n"; |> concatStringsSep "\n";
}; };
${namespace}.services.storage.impermanence.folders = mkIf (cfg.enable && cfg.shares != []) ( ${namespace}.services.storage.impermanence.folders = mkMerge [
["/var/lib/nfs"] ++ (cfg.shares |> map (s: "/mnt/nfs/${s.name}")) ["/var/lib/nfs"]
); (mkIf (cfg.shares != []) (cfg.shares |> map (s: "/mnt/nfs/${s.name}")))
];
networking.firewall.allowedTCPPorts = mkIf cfg.enable [2049]; networking.firewall.allowedTCPPorts = [2049];
}; };
} }

View file

@ -0,0 +1,35 @@
{
config,
lib,
namespace,
...
}: let
inherit (lib) mapAttrs';
inherit (lib.${namespace}) getAttrByNamespace resolveHostIP;
cfg = getAttrByNamespace config "${namespace}.services.storage.nfs";
networkCfg = getAttrByNamespace config "${namespace}.services.networking";
in {
config = {
fileSystems = let
mapFolderToMount = name: mntCfg: let
hostIP = resolveHostIP networkCfg.devices mntCfg.host;
localPath =
if mntCfg.mountPath != null
then mntCfg.mountPath
else "/mnt/nfs/${name}";
in {
name = localPath;
value = {
device = "${hostIP}:${mntCfg.folder}";
fsType = "nfs";
options = [
"_netdev"
"nofail"
"x-systemd.automount"
];
};
};
in
cfg.mounts |> mapAttrs' mapFolderToMount;
};
}

View file

@ -1,17 +1,20 @@
{ {
config, config,
inputs,
lib, lib,
namespace, namespace,
... ...
}: let } @ args: let
inherit (lib) types mkIf mkEnableOption mkOption mapAttrs' mkMerge map; inherit (lib) types mkIf mkEnableOption mkMerge;
inherit (lib.${namespace}) getAttrByNamespace mkOptionsWithNamespace resolveHostIP readJsonOrEmpty getIn mkOpt mkRequiredOpt mkNullableOpt mkListOpt mkOptAttrset; inherit (lib.${namespace}) getAttrByNamespace mkOptionsWithNamespace mkRequiredOpt mkNullableOpt mkListOpt mkOptAttrset;
inherit (config.users) users; inherit (config.users) users;
base = "${namespace}.services.storage.samba"; base = "${namespace}.services.storage.samba";
cfg = getAttrByNamespace config base; cfg = getAttrByNamespace config base;
networkCfg = getAttrByNamespace config "${namespace}.services.networking";
in { in {
imports = [
(import ./mount.nix args)
];
options = with types; options = with types;
mkOptionsWithNamespace base { mkOptionsWithNamespace base {
enable = mkEnableOption "Samba"; enable = mkEnableOption "Samba";
@ -25,80 +28,55 @@ in {
}) {} "Set of Samba mounts with custom configuration."; }) {} "Set of Samba mounts with custom configuration.";
}; };
config = { config = mkIf cfg.enable {
fileSystems = let services = {
processMount = name: mountCfg: let samba = {
hostIP = resolveHostIP networkCfg.devices mountCfg.host; enable = true;
localPath = openFirewall = true;
if mountCfg.mountPath != null settings = let
then mountCfg.mountPath mkShare = folderPath: {
else "/mnt/samba/${name}"; "path" = "/mnt/samba/${folderPath}";
automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s"; "browsable" = "yes";
in { "read only" = "no";
name = localPath; "guest ok" = "no";
value = { "create mask" = "0644";
device = "//${hostIP}/${mountCfg.folder}"; "directory mask" = "0755";
fsType = "cifs"; "force user" = users.c4patino.name;
options = [ "force group" = users.c4patino.group;
"${automount_opts},credentials=/etc/samba/.credentials,uid=1000,gid=100" };
mapFolderToShare = folderPath: {
name = folderPath;
value = mkShare folderPath;
};
shareConfigs =
cfg.shares
|> map mapFolderToShare
|> builtins.listToAttrs;
in
mkMerge [
{
global = {
"workgroup" = "WORKGROUP";
"server string" = "smbnix";
"netbios name" = "smbnix";
"security" = "user";
};
}
shareConfigs
]; ];
};
}; };
in
cfg.mounts |> mapAttrs' processMount;
environment.etc."samba/.credentials".text = let samba-wsdd = {
secrets = readJsonOrEmpty "${inputs.self}/secrets/crypt/secrets.json"; enable = true;
in '' openFirewall = true;
username=${getIn "samba.username" secrets} };
password=${getIn "samba.password" secrets}
'';
services.samba = mkIf cfg.enable {
enable = true;
openFirewall = true;
settings = let
mkShare = folderPath: {
"path" = "/mnt/samba/${folderPath}";
"browsable" = "yes";
"read only" = "no";
"guest ok" = "no";
"create mask" = "0644";
"directory mask" = "0755";
"force user" = users.c4patino.name;
"force group" = users.c4patino.group;
};
mapFolderToShare = folderPath: {
name = folderPath;
value = mkShare folderPath;
};
shareConfigs =
cfg.shares
|> map mapFolderToShare
|> builtins.listToAttrs;
in
mkMerge [
{
global = {
"workgroup" = "WORKGROUP";
"server string" = "smbnix";
"netbios name" = "smbnix";
"security" = "user";
};
}
shareConfigs
];
}; };
services.samba-wsdd = mkIf cfg.enable { ${namespace}.services.storage.impermanence.folders = mkMerge [
enable = true; ["/var/lib/samba"]
openFirewall = true; (mkIf (cfg.shares != []) (cfg.shares |> map (s: "/mnt/samba/${s}")))
}; ];
${namespace}.services.storage.impermanence.folders = mkIf (cfg.enable && cfg.shares != []) (
["/var/lib/samba"] ++ (cfg.shares |> map (s: "/mnt/samba/${s}"))
);
}; };
} }

View file

@ -0,0 +1,38 @@
{
config,
inputs,
lib,
namespace,
...
}: let
inherit (lib) mapAttrs';
inherit (lib.${namespace}) getAttrByNamespace resolveHostIP readJsonOrEmpty getIn;
cfg = getAttrByNamespace config "${namespace}.services.storage.samba";
networkCfg = getAttrByNamespace config "${namespace}.services.networking";
in {
config = {
fileSystems = let
processMount = name: mountCfg: let
hostIP = resolveHostIP networkCfg.devices mountCfg.host;
localPath =
if mountCfg.mountPath != null
then mountCfg.mountPath
else "/mnt/samba/${name}";
automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s";
in {
name = localPath;
value = {
device = "//${hostIP}/${mountCfg.folder}";
fsType = "cifs";
options = [
"${automount_opts},credentials=/etc/samba/.credentials,uid=1000,gid=100"
];
};
};
in
cfg.mounts |> mapAttrs' processMount;
sops.secrets."samba" = {};
};
}