From 78dd22fed3939862ea1e2714177060a6d143ce5a Mon Sep 17 00:00:00 2001 From: Leyla Becker Date: Mon, 3 Nov 2025 11:55:10 -0600 Subject: [PATCH] feat: started to draft out new storage interface --- modules/nixos-modules/impermanence.nix | 155 +++++++++++++++++++++---- 1 file changed, 131 insertions(+), 24 deletions(-) diff --git a/modules/nixos-modules/impermanence.nix b/modules/nixos-modules/impermanence.nix index 60011cb..5b1bbd2 100644 --- a/modules/nixos-modules/impermanence.nix +++ b/modules/nixos-modules/impermanence.nix @@ -3,38 +3,145 @@ lib, ... }: { - # options.storage = { - # zfs = { - # # TODO: enable option - # # when this option is enabled we need to configure and enable disko things + options.storage = let + datasetSubmodule = {name, ...}: { + # TODO: we need to figure out what options a dataset can have in zfs + }; - # # TODO: we need some way of managing notifications + impermanenceDatasetSubmodules = [ + datasetSubmodule + ({...}: let + pathPermissions = { + read = lib.mkEnableOption "should the path have read permissions"; + write = lib.mkEnableOption "should the path have read permissions"; + execute = lib.mkEnableOption "should the path have read permissions"; + }; + pathTypeSubmodule = {name, ...}: { + options = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + }; + owner = { + user = lib.mkOption { + type = lib.types.str; + default = "nouser"; + }; + permissions = pathPermissions; + }; + group = { + group = lib.mkOption { + type = lib.types.str; + default = "nogroup"; + }; + permissions = pathPermissions; + }; + other = { + permissions = pathPermissions; + }; + }; + }; + in { + options = { + files = lib.types.mkOption { + type = lib.types.attrsOf (lib.types.submodule pathTypeSubmodule); + default = {}; + }; + directories = { + type = lib.types.attrsOf (lib.types.submodule pathTypeSubmodule); + default = {}; + }; + }; + }) + ]; + in { + zfs = { + # TODO: enable option implementation + enable = lib.mkEnableOption "Should zfs be enabled on this system."; - # # TODO: we need options to configure zfs pools - # # we should have warnings when the configured pool is missing drives + 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"; + }; + }; - # # TODO: dataset option that is a submodule that adds datasets to the system - # # warnings for when a dataset was created in the past on a system but it is now missing some of the options defined for it + # TODO: we need options to configure zfs pools + # we should have warnings when the configured pool is missing drives after activation + # TODO: implementation of this + # TODO: validations that we have at least one boot drive + 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 = lib.mkEnableOption "Should encryption be enabled on this pool."; + vdevs = lib.mkOption { + type = lib.types.listOf deviceType; + default = []; + }; + cache = lib.mkOption { + type = lib.types.attrsOf deviceType; + }; + }; - # # TODO: pools and datasets need to be passed to disko - # }; + # TODO:create the root dataset automatically + # TODO: dataset option that is a submodule that adds datasets to the system + # warnings for when a dataset was created in the past on a system but it is now missing some of the options defined for it + datasets = lib.types.attrsOf (lib.types.submodule datasetSubmodule); + }; - # impermanence = { - # # TODO: enable option + impermanence = { + enable = lib.mkEnableOption "should impermanence be enabled for this system"; + # TODO: enable option implementation - # # TODO: datasets option that is a submodule that will be used to define what datasets to add to the storage system - # # We should by default create the `local`, `local/system/nix`, `local/system/root`, `persist` `persist/system/root`, and `persist/system/var/log` datasets - # # Then we should make a dataset for user folders local and persist - # # We should also create datasets for systemd modules that have have impermanence enabled for them - # # we need to figure out what options a dataset can have in zfs - # }; + # TODO: assertion that zfs needs to be enabled when impermanence is enabled - # # TODO: we should have an impermanence module for home manager that proxies its values namespaced to the user down here that matches the same interface + # TODO: datasets option that is a submodule that will be used to define what datasets to add to the storage system + # We should by default create the `local`, `local/system/nix`, `local/system/root`, `persist` `persist/system/root`, and `persist/system/var/log` datasets + # We should also create datasets for systemd modules that have have impermanence enabled for them - # # TODO: we should have a way of enabling impermanence for a systemd config - # # these should have an option to put their folder into their own dataset (this needs to support private vs non private) - # # options for features that can be added to the dataset - # }; + datasets = lib.types.attrsOf (lib.types.submodule impermanenceDatasetSubmodules); + + # TODO: this should just live under home-manager.users..storage.impermanence + home-manager = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + enable = lib.mkEnableOption "should impermanence be enabled for this user"; + + # We should by default create the `local/home/${name}`, and `persist/home/${name}` datasets + datasets = lib.types.attrsOf (lib.types.submodule impermanenceDatasetSubmodules); + })); + }; + + # TODO: we should have an impermanence module for home manager that proxies its values namespaced to the user down here that matches the same interface + + # TODO: we should have a way of enabling impermanence for a systemd config + # these should have an option to put their folder into their own dataset (this needs to support private vs non private) + # options for features that can be added to the dataset + }; options.host.impermanence.enable = lib.mkEnableOption "are we going to use impermanence on this device";