args @ { lib, pkgs, config, ... }: let datasetSubmodule = (import ./submodules/dataset.nix) args; in { options.storage = { zfs = { enable = lib.mkEnableOption "Should zfs be enabled on this system."; notifications = { enable = lib.mkEnableOption "are notifications enabled"; host = lib.mkOption { type = lib.types.str; description = "what is the host that we are going to send the email to"; }; port = lib.mkOption { type = lib.types.port; description = "what port is the host using to receive mail on"; }; to = lib.mkOption { type = lib.types.str; description = "what account is the email going to be sent to"; }; user = lib.mkOption { type = lib.types.str; description = "what user is the email going to be set from"; }; tokenFile = lib.mkOption { type = lib.types.str; description = "file containing the password to be used by msmtp for notifications"; }; }; pool = let deviceType = lib.types.coercedTo lib.types.str (device: { device = device; boot = false; }) { device = lib.mkOption { type = lib.types.str; }; boot = lib.mkEnableOption "should this device be a boot device"; }; in { encryption = { enable = lib.mkEnableOption "Should encryption be enabled on this pool."; keyformat = lib.mkOption { type = lib.types.enum ["raw" "hex" "passphrase"]; default = "hex"; description = "Format of the encryption key"; }; keylocation = lib.mkOption { type = lib.types.str; default = "prompt"; description = "Location of the encryption key"; }; }; mode = lib.mkOption { type = lib.types.enum ["stripe" "mirror" "raidz1" "raidz2" "raidz3"]; default = "raidz2"; description = "ZFS redundancy mode for the pool"; }; bootPartitionSize = lib.mkOption { type = lib.types.str; default = "2G"; description = "Size of the boot partition on boot drives"; }; vdevs = lib.mkOption { type = lib.types.listOf (lib.types.listOf deviceType); default = []; description = "List of vdevs, where each vdev is a list of devices"; }; cache = lib.mkOption { type = lib.types.attrsOf deviceType; default = {}; }; }; rootDataset = lib.mkOption { type = lib.types.submodule datasetSubmodule; description = "Root ZFS dataset to create"; default = {}; }; datasets = lib.mkOption { type = lib.types.attrsOf (lib.types.submodule datasetSubmodule); description = "Additional ZFS datasets to create"; default = {}; }; }; }; config = lib.mkIf config.storage.zfs.enable (lib.mkMerge [ { services.zfs = { autoScrub.enable = true; autoSnapshot.enable = true; }; # TODO: configure disko # TODO: assertion that we have a boot device # TODO: check that disks on system match configuration and warn user if they don't # TODO: check that datasets on system match configuration and warn user if they don't } (lib.mkIf config.storage.zfs.notifications.enable { programs.msmtp = { enable = true; setSendmail = true; defaults = { aliases = "/etc/aliases"; port = config.storage.zfs.notifications.port; tls_trust_file = "/etc/ssl/certs/ca-certificates.crt"; tls = "on"; auth = "login"; tls_starttls = "off"; }; accounts = { zfs_notifications = { auth = true; tls = true; host = config.storage.zfs.notifications.host; passwordeval = "cat ${config.storage.zfs.notifications.tokenFile}"; user = config.storage.zfs.notifications.user; from = config.storage.zfs.notifications.user; }; }; }; services.zfs = { zed = { enableMail = true; settings = { ZED_DEBUG_LOG = "/tmp/zed.debug.log"; ZED_EMAIL_ADDR = [config.storage.zfs.notifications.to]; ZED_EMAIL_PROG = "${pkgs.msmtp}/bin/msmtp"; ZED_EMAIL_OPTS = "-a zfs_notifications @ADDRESS@"; ZED_NOTIFY_INTERVAL_SECS = 3600; ZED_NOTIFY_VERBOSE = true; ZED_USE_ENCLOSURE_LEDS = true; ZED_SCRUB_AFTER_RESILVER = true; }; }; }; }) ]); }