diff --git a/flake.nix b/flake.nix index dae7232..849432a 100644 --- a/flake.nix +++ b/flake.nix @@ -46,6 +46,7 @@ modules/blocks/ssl.nix modules/blocks/tinyproxy.nix modules/blocks/vpn.nix + modules/blocks/zfs.nix modules/services/arr.nix modules/services/audiobookshelf.nix diff --git a/modules/blocks/zfs.nix b/modules/blocks/zfs.nix new file mode 100644 index 0000000..f3e76d0 --- /dev/null +++ b/modules/blocks/zfs.nix @@ -0,0 +1,73 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.shb.zfs; +in +{ + options.shb.zfs = { + defaultPoolName = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "ZFS pool name datasets should be created on if no pool name is given in the dataset."; + }; + + datasets = lib.mkOption { + description = '' + ZFS Datasets. + + Each entry in the attrset will be created and mounted in the given path. + The attrset name is the dataset name. + + This block implements the following contracts: + - mount + ''; + default = {}; + example = lib.literalExpression '' + shb.zfs."safe/postgresql".path = "/var/lib/postgresql"; + ''; + type = lib.types.attrsOf (lib.types.submodule { + options = { + enable = lib.mkEnableOption "shb.zfs.datasets"; + + poolName = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "ZFS pool name this dataset should be created on. Overrides the defaultPoolName."; + }; + + path = lib.mkOption { + type = lib.types.str; + description = "Path this dataset should be mounted on."; + }; + }; + }); + }; + }; + + config = { + assertions = [ + { + assertion = lib.any (x: x.poolName == null) (lib.mapAttrsToList (n: v: v) cfg.datasets) -> cfg.defaultPoolName != null; + message = "Cannot have both datasets.poolName and defaultPoolName set to null"; + } + ]; + + system.activationScripts = lib.mapAttrs' (name: cfg': + let + dataset = (if cfg'.poolName != null then cfg'.poolName else cfg.defaultPoolName) + "/" + name; + in + lib.attrsets.nameValuePair "zfsCreate-${name}" { + text = '' + ${pkgs.zfs}/bin/zfs list ${dataset} > /dev/null 2>&1 \ + || ${pkgs.zfs}/bin/zfs create \ + -o mountpoint=none \ + ${dataset} || : + + [ "$(${pkgs.zfs}/bin/zfs get -H mountpoint -o value ${dataset})" = ${cfg'.path} ] \ + || ${pkgs.zfs}/bin/zfs set \ + mountpoint=${cfg'.path} \ + ${dataset} + ''; + }) cfg.datasets; + }; +} diff --git a/modules/contracts/default.nix b/modules/contracts/default.nix index cb95801..54a06f6 100644 --- a/modules/contracts/default.nix +++ b/modules/contracts/default.nix @@ -1,4 +1,5 @@ { lib }: { + mount = import ./mount.nix { inherit lib; }; ssl = import ./ssl.nix { inherit lib; }; } diff --git a/modules/contracts/mount.nix b/modules/contracts/mount.nix new file mode 100644 index 0000000..71083be --- /dev/null +++ b/modules/contracts/mount.nix @@ -0,0 +1,11 @@ +{ lib, ... }: +lib.types.submodule { + freeformType = lib.types.anything; + + options = { + path = lib.mkOption { + type = lib.types.str; + description = "Path to be mounted."; + }; + }; +}