Archived
98 lines
3.9 KiB
Nix
98 lines
3.9 KiB
Nix
{ vars, lib, pkgs, ... }:
|
|
|
|
let
|
|
poolName = lib.removePrefix "/" vars.storageRoot;
|
|
|
|
# For each NFS share subpath, generate every ancestor path so ZFS datasets
|
|
# are created parent-first. e.g. "docker/config" → ["docker" "docker/config"]
|
|
ancestors = path:
|
|
let parts = lib.splitString "/" path;
|
|
in lib.imap1 (i: _: lib.concatStringsSep "/" (lib.take i parts)) parts;
|
|
|
|
poolDatasets = lib.unique (
|
|
lib.concatMap (share: ancestors share.subpath) (lib.attrValues vars.nfsShares)
|
|
);
|
|
in
|
|
{
|
|
imports = [
|
|
../beszel/enable-agent.nix
|
|
../services/zfs/enable-service.nix
|
|
];
|
|
|
|
boot.zfs.extraPools = [ poolName ];
|
|
|
|
# On a fresh image deploy the data disk (scsi1) starts blank — no pool
|
|
# exists yet, so zfs-import-tank.service would spin for 60 s and fail.
|
|
# This service runs first: if the pool is already present it exits instantly;
|
|
# otherwise it creates it (with all required datasets) so the standard
|
|
# import service finds it ready on the very first boot.
|
|
systemd.services."zfs-init-${poolName}" = {
|
|
description = "Initialize '${poolName}' ZFS pool on first boot if not present";
|
|
wantedBy = [ "zfs-import-${poolName}.service" ];
|
|
before = [ "zfs-import-${poolName}.service" ];
|
|
after = [ "systemd-udev-settle.service" ];
|
|
unitConfig.DefaultDependencies = false;
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
};
|
|
path = [ pkgs.zfs_unstable ];
|
|
script = ''
|
|
# Already imported — nothing to do.
|
|
if zpool list "${poolName}" >/dev/null 2>&1; then
|
|
exit 0
|
|
fi
|
|
|
|
# Pool exists on a device but not yet imported — let the standard
|
|
# zfs-import-${poolName}.service handle it normally.
|
|
if zpool import -d /dev/disk/by-id -N "${poolName}" 2>/dev/null; then
|
|
exit 0
|
|
fi
|
|
|
|
# No pool found at all. Create it on the Proxmox data disk (scsi1),
|
|
# which appears as /dev/disk/by-id/scsi-*drive-scsi1 inside the VM.
|
|
DATA_DISK=""
|
|
for candidate in /dev/disk/by-id/scsi-*drive-scsi1; do
|
|
[[ "$candidate" == *-part* ]] && continue
|
|
[ -b "$candidate" ] && DATA_DISK="$candidate" && break
|
|
done
|
|
|
|
if [ -z "$DATA_DISK" ]; then
|
|
echo "zfs-init-${poolName}: no data disk found (expected /dev/disk/by-id/scsi-*drive-scsi1)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "zfs-init-${poolName}: creating pool on $DATA_DISK"
|
|
zpool create -f "${poolName}" "$DATA_DISK"
|
|
${lib.concatMapStrings (ds: ''
|
|
zfs create "${poolName}/${ds}"
|
|
'') poolDatasets}
|
|
'';
|
|
};
|
|
|
|
systemd.services.nfs-server = {
|
|
after = [ "zfs-mount.service" ];
|
|
requires = [ "zfs-mount.service" ];
|
|
};
|
|
|
|
services.nfs.server = {
|
|
enable = true;
|
|
exports = ''
|
|
${vars.storageRoot}/${vars.nfsShares.dockerConfig.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
|
${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
|
${vars.storageRoot}/${vars.nfsShares.dockerDatabases.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
|
${vars.storageRoot}/${vars.nfsShares.nextcloudData.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
|
${vars.storageRoot}/${vars.nfsShares.raspiVolumes.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
|
${vars.storageRoot}/${vars.nfsShares.proxmoxIsos.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
|
${vars.storageRoot}/${vars.nfsShares.proxomoxLxcImages.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
|
${vars.storageRoot}/${vars.nfsShares.pxebootImages.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
|
'';
|
|
};
|
|
|
|
# mountd (20048) is needed for showmount/NFSv3 mount protocol — without it
|
|
# clients can reach portmapper (111) and get the mountd port back, then
|
|
# time out trying to connect to it. All three ports need TCP and UDP.
|
|
networking.firewall.allowedTCPPorts = [ vars.ports.nfsRpcbind vars.ports.nfsd vars.ports.nfsMountd ];
|
|
networking.firewall.allowedUDPPorts = [ vars.ports.nfsRpcbind vars.ports.nfsd vars.ports.nfsMountd ];
|
|
}
|