Compare commits

..

40 commits

Author SHA1 Message Date
a0807b014c feat: moved logs to impermanence 2025-11-27 20:29:03 -06:00
adc1c1a918 Merge branch 'main' into storage-refactor 2025-11-27 20:14:09 -06:00
3d1750060d fix: fixed nix flake check 2025-11-23 15:44:59 -06:00
a4f3b3141d fix: fixed trailing mount path issue 2025-11-23 15:35:26 -06:00
2922114367 fix: fixed file system resolution 2025-11-23 11:51:53 -06:00
5dc602339c Merge branch 'main' into storage-refactor 2025-11-22 01:25:30 +00:00
ecdd407abe feat: switched jellyfin media and qbittorent media to being the same dataset 2025-11-17 17:56:31 -06:00
e196541f2a feat: filter out impermanence datasets that dont do anything 2025-11-16 00:12:29 -06:00
57fba596c2 Merge branch 'main' into storage-refactor 2025-11-16 00:11:26 -06:00
dfcacdc6fb feat: moved some datasets to common zfs storage config 2025-11-16 00:04:03 -06:00
c2701ea8f0 feat: moved services over to using the new storage datasets 2025-11-15 16:37:10 -06:00
757a3892e1 feat: updated interface for storage 2025-11-15 13:39:53 -06:00
f8edad75bf feat: updated user configs to better match original config 2025-11-14 22:06:32 -06:00
1eb66d1c31 feat: updated pool names 2025-11-12 19:27:12 -06:00
ac0f1ce2e6 feat: updated flake input to use fork 2025-11-10 15:51:28 -06:00
8aa984a389 feat: made datasets build 2025-11-10 15:49:12 -06:00
61eef3067e feat: made persist build with new impermanence system 2025-11-10 15:42:25 -06:00
d06c25f33f feat: migrated users over to new persistence structure 2025-11-10 02:38:28 -06:00
37f5e65bd6 Merge branch 'main' into storage-refactor 2025-11-09 02:33:38 -06:00
318a0a9748 feat: added sops dataset to users.nix 2025-11-08 22:37:19 -06:00
4d7d11e0c8 feat: removed now unneeded disko and impermanence modules 2025-11-08 21:19:54 -06:00
4da5d65d8f feat: added activation and resume scripts to storage and impermanence 2025-11-08 21:10:18 -06:00
1310b50794 feat: moved ssh config to use new storage config 2025-11-08 19:04:59 -06:00
5acf060e9e feat: updated imports to use new storage module only 2025-11-08 18:49:19 -06:00
703530ddfe feat: updated storage config for emergent 2025-11-08 18:48:41 -06:00
ab555f50ff fix: defiant config cache drive converted to correct format 2025-11-08 18:30:49 -06:00
d283f88160 feat: moved ollama, tailscale, and sync into folders following the new storage pattern 2025-11-08 18:28:34 -06:00
b67be1472a feat: refactored impermanence modules to follow new pattern 2025-11-08 18:17:22 -06:00
3ca0e9bf0a fix: fixed generation of disko configuration 2025-11-08 17:20:37 -06:00
730eeef242 Merge branch 'main' into storage-refactor 2025-11-08 14:26:07 -06:00
39edb65539 feat: removed broken disko config 2025-11-08 14:21:22 -06:00
9df29cc07f feat: refined options for datasets 2025-11-08 13:21:01 -06:00
0de97fa4a2 feat: added more development notes 2025-11-07 18:14:00 -06:00
adc6b90c93 feat: made impermanence create datasets for zfs and persistence 2025-11-07 16:29:56 -06:00
409fdb7276 Merge branch 'main' into storage-refactor 2025-11-06 17:07:07 -06:00
d8989bb43d feat: drafted out zfs vdev, pool, and dataset implementations 2025-11-05 10:56:04 -06:00
2fd14e4cc0 feat: added config block to zfs.nix and gave it notification functionality 2025-11-04 19:39:27 -06:00
573708fd47 moved storage option draft to its own folder 2025-11-04 15:02:49 -06:00
aeb37e658e Merge branch 'main' into storage-refactor 2025-11-04 14:28:28 -06:00
78dd22fed3 feat: started to draft out new storage interface 2025-11-03 11:55:10 -06:00
118 changed files with 1663 additions and 1370 deletions

View file

@ -12,7 +12,7 @@
]; ];
config = { config = {
impermanence.enable = osConfig.host.impermanence.enable; impermanence.enable = osConfig.storage.impermanence.enable;
# Home Manager needs a bit of information about you and the paths it should # Home Manager needs a bit of information about you and the paths it should
# manage. # manage.

View file

@ -4,7 +4,7 @@
... ...
}: { }: {
config = lib.mkIf (config.impermanence.enable) { config = lib.mkIf (config.impermanence.enable) {
home.persistence."/persist/home/leyla" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"desktop" "desktop"
"downloads" "downloads"
@ -14,7 +14,6 @@
".bash_history" # keep shell history around ".bash_history" # keep shell history around
"${config.xdg.dataHome}/recently-used.xbel" # gnome recently viewed files "${config.xdg.dataHome}/recently-used.xbel" # gnome recently viewed files
]; ];
allowOther = true;
}; };
}; };
} }

View file

@ -33,44 +33,6 @@
isPrincipleUser = true; isPrincipleUser = true;
}; };
}; };
impermanence.enable = true;
storage = {
enable = true;
encryption = true;
notifications = {
enable = true;
host = "smtp.protonmail.ch";
port = 587;
to = "leyla@jan-leila.com";
user = "noreply@jan-leila.com";
tokenFile = config.sops.secrets."services/zfs_smtp_token".path;
};
pool = {
# We are having to boot off of the nvm cache drive because I cant figure out how to boot via the HBA
bootDrives = ["nvme-Samsung_SSD_990_PRO_4TB_S7KGNU0X907881F"];
vdevs = [
[
"ata-ST18000NE000-3G6101_ZVTCXVEB"
"ata-ST18000NE000-3G6101_ZVTCXWSC"
"ata-ST18000NE000-3G6101_ZVTD10EH"
"ata-ST18000NT001-3NF101_ZVTE0S3Q"
"ata-ST18000NT001-3NF101_ZVTEF27J"
"ata-ST18000NE000-3G6101_ZVTJ7359"
]
[
"ata-ST4000NE001-2MA101_WS2275P3"
"ata-ST4000NE001-2MA101_WS227B9F"
"ata-ST4000NE001-2MA101_WS227CEW"
"ata-ST4000NE001-2MA101_WS227CYN"
"ata-ST4000NE001-2MA101_WS23TBWV"
"ata-ST4000NE001-2MA101_WS23TC5F"
]
];
cache = [
"nvme-Samsung_SSD_990_PRO_4TB_S7KGNU0X907881F"
];
};
};
network_storage = { network_storage = {
enable = true; enable = true;
directories = [ directories = [
@ -104,6 +66,53 @@
}; };
}; };
storage = {
zfs = {
enable = true;
notifications = {
enable = true;
host = "smtp.protonmail.ch";
port = 587;
to = "leyla@jan-leila.com";
user = "noreply@jan-leila.com";
tokenFile = config.sops.secrets."services/zfs_smtp_token".path;
};
pool = {
encryption = {
enable = true;
};
vdevs = [
[
"ata-ST18000NE000-3G6101_ZVTCXVEB"
"ata-ST18000NE000-3G6101_ZVTCXWSC"
"ata-ST18000NE000-3G6101_ZVTD10EH"
"ata-ST18000NT001-3NF101_ZVTE0S3Q"
"ata-ST18000NT001-3NF101_ZVTEF27J"
"ata-ST18000NE000-3G6101_ZVTJ7359"
]
[
"ata-ST4000NE001-2MA101_WS2275P3"
"ata-ST4000NE001-2MA101_WS227B9F"
"ata-ST4000NE001-2MA101_WS227CEW"
"ata-ST4000NE001-2MA101_WS227CYN"
"ata-ST4000NE001-2MA101_WS23TBWV"
"ata-ST4000NE001-2MA101_WS23TC5F"
]
];
# We are having to boot off of the nvm cache drive because I cant figure out how to boot via the HBA
cache = [
{
device = "nvme-Samsung_SSD_990_PRO_4TB_S7KGNU0X907881F";
boot = true;
}
];
};
};
impermanence = {
enable = true;
};
};
systemd.network = { systemd.network = {
enable = true; enable = true;

View file

@ -59,12 +59,22 @@
hardware = { hardware = {
piperMouse.enable = true; piperMouse.enable = true;
}; };
};
storage = { storage = {
zfs = {
enable = true; enable = true;
pool = { pool = {
mode = ""; mode = "stripe";
drives = ["wwn-0x5000039fd0cf05eb"]; vdevs = [
[
{
device = "wwn-0x5000039fd0cf05eb";
boot = true;
}
]
];
cache = [];
}; };
}; };
}; };

19
flake.lock generated
View file

@ -147,16 +147,25 @@
} }
}, },
"impermanence": { "impermanence": {
"inputs": {
"home-manager": [
"home-manager"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1737831083, "lastModified": 1762761176,
"narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=", "narHash": "sha256-i3gM8fUozQrgZIbwVNlTuhLqPSl56zxAYpsQpQ9Lhro=",
"owner": "nix-community", "owner": "jan-leila",
"repo": "impermanence", "repo": "impermanence",
"rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170", "rev": "ffbe1ca47cf4b3008c3aa5c49cdae294d8c8058a",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nix-community", "owner": "jan-leila",
"ref": "home-manager-v2",
"repo": "impermanence", "repo": "impermanence",
"type": "github" "type": "github"
} }

View file

@ -36,7 +36,9 @@
# delete your darlings # delete your darlings
impermanence = { impermanence = {
url = "github:nix-community/impermanence"; url = "github:jan-leila/impermanence/home-manager-v2";
inputs.nixpkgs.follows = "nixpkgs";
inputs.home-manager.follows = "home-manager";
}; };
nix-darwin = { nix-darwin = {

View file

@ -18,17 +18,16 @@ in {
(lib.mkIf config.impermanence.enable { (lib.mkIf config.impermanence.enable {
assertions = [ assertions = [
{ {
assertion = osConfig.host.impermanence.enable; assertion = osConfig.storage.impermanence.enable;
message = "impermanence can not be enabled for a user when it is not enabled for the system"; message = "impermanence can not be enabled for a user when it is not enabled for the system";
} }
]; ];
}) })
# If impermanence is not enabled for this user but system impermanence is enabled, # If impermanence is not enabled for this user but system impermanence is enabled,
# persist the entire home directory as fallback # persist the entire home directory as fallback
(lib.mkIf (osConfig.host.impermanence.enable && !cfg.enable && cfg.fallbackPersistence.enable) { (lib.mkIf (osConfig.storage.impermanence.enable && !cfg.enable && cfg.fallbackPersistence.enable) {
home.persistence."/persist/home/${config.home.username}" = { home.persistence."/persist/replicate/home" = {
directories = ["."]; directories = ["."];
allowOther = true;
}; };
}) })
]; ];

View file

@ -96,7 +96,7 @@
} }
) )
(lib.mkIf config.impermanence.enable { (lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
files = lib.lists.flatten ( files = lib.lists.flatten (
builtins.map (hostKey: [".ssh/${hostKey.path}" ".ssh/${hostKey.path}.pub"]) config.programs.openssh.hostKeys builtins.map (hostKey: [".ssh/${hostKey.path}" ".ssh/${hostKey.path}.pub"]) config.programs.openssh.hostKeys
); );

View file

@ -1,15 +1,13 @@
{ {
lib, lib,
config, config,
osConfig,
... ...
}: { }: {
config = lib.mkIf (config.programs.anki.enable && osConfig.host.impermanence.enable) { config = lib.mkIf (config.programs.anki.enable && config.impermanence.enable) {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.dataHome}/Anki2/" ".local/share/Anki2"
]; ];
allowOther = true;
}; };
}; };
} }

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/Bitwarden" "${config.xdg.configHome}/Bitwarden"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/bruno/" "${config.xdg.configHome}/bruno/"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/calibre" "${config.xdg.configHome}/calibre"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,12 +16,11 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.dataHome}/DaVinciResolve" "${config.xdg.dataHome}/DaVinciResolve"
"${config.xdg.configHome}/blackmagic" "${config.xdg.configHome}/blackmagic"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.dataHome}/DBeaverData/" "${config.xdg.dataHome}/DBeaverData/"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -6,11 +6,10 @@
config = lib.mkIf config.programs.discord.enable (lib.mkMerge [ config = lib.mkIf config.programs.discord.enable (lib.mkMerge [
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/discord/" "${config.xdg.configHome}/discord/"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -22,11 +22,10 @@
# Extension configuration # Extension configuration
".mozilla/firefox/${profile}/extension-settings.json" ".mozilla/firefox/${profile}/extension-settings.json"
]; ];
allowOther = true;
}; };
in { in {
config = lib.mkIf (config.programs.firefox.enable && config.impermanence.enable) { config = lib.mkIf (config.programs.firefox.enable && config.impermanence.enable) {
home.persistence."/persist${config.home.homeDirectory}" = lib.mkMerge ( home.persistence."/persist/replicate/home" = lib.mkMerge (
( (
lib.attrsets.mapAttrsToList lib.attrsets.mapAttrsToList
(profile: _: buildProfilePersistence profile) (profile: _: buildProfilePersistence profile)

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/FreeCAD" "${config.xdg.configHome}/FreeCAD"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/GIMP" "${config.xdg.configHome}/GIMP"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,7 +16,7 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
# configuration # configuration
"${config.xdg.configHome}/JetBrains/" "${config.xdg.configHome}/JetBrains/"

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/inkscape" "${config.xdg.configHome}/inkscape"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -23,12 +23,11 @@ in {
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/kdenliverc" "${config.xdg.configHome}/kdenliverc"
"${config.xdg.dataHome}/kdenlive" "${config.xdg.dataHome}/kdenlive"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,12 +16,11 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/kritarc" "${config.xdg.configHome}/kritarc"
"${config.xdg.dataHome}/krita" "${config.xdg.dataHome}/krita"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/libreoffice" "${config.xdg.configHome}/libreoffice"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -30,7 +30,7 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
".MakeMKV" ".MakeMKV"
]; ];

View file

@ -17,12 +17,11 @@ in {
} }
( (
mkIf config.impermanence.enable { mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/mapillary-uploader" "${config.xdg.configHome}/mapillary-uploader"
"${config.xdg.dataHome}/mapillary-uploader" "${config.xdg.dataHome}/mapillary-uploader"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -6,11 +6,10 @@
config = lib.mkIf config.programs.obs-studio.enable (lib.mkMerge [ config = lib.mkIf config.programs.obs-studio.enable (lib.mkMerge [
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/obs-studio" "${config.xdg.configHome}/obs-studio"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -6,7 +6,7 @@
config = lib.mkIf config.programs.obsidian.enable (lib.mkMerge [ config = lib.mkIf config.programs.obsidian.enable (lib.mkMerge [
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/obsidian" "${config.xdg.configHome}/obsidian"
]; ];

View file

@ -23,12 +23,11 @@ in {
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/olympus" "${config.xdg.configHome}/olympus"
"${config.xdg.dataHome}/olympus" "${config.xdg.dataHome}/olympus"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/OpenRGB" "${config.xdg.configHome}/OpenRGB"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/MusicBrainz" "${config.xdg.configHome}/MusicBrainz"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,7 +16,7 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/ProStudioMasters" "${config.xdg.configHome}/ProStudioMasters"
]; ];

View file

@ -16,7 +16,7 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/protonvpn" "${config.xdg.configHome}/protonvpn"
"${config.xdg.configHome}/Proton" "${config.xdg.configHome}/Proton"

View file

@ -16,7 +16,7 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/qBittorrent" "${config.xdg.configHome}/qBittorrent"
]; ];

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/qFlipper" "${config.xdg.configHome}/qFlipper"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,7 +16,7 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/Signal" "${config.xdg.configHome}/Signal"
]; ];

View file

@ -18,14 +18,13 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
{ {
directory = "${config.xdg.dataHome}/Steam"; directory = "${config.xdg.dataHome}/Steam";
method = "symlink"; method = "symlink";
} }
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.dataHome}/torbrowser" "${config.xdg.dataHome}/torbrowser"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,11 +16,10 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/chromium" "${config.xdg.configHome}/chromium"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -16,12 +16,11 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
"${config.xdg.configHome}/via" "${config.xdg.configHome}/via"
"${config.xdg.dataHome}/via" "${config.xdg.dataHome}/via"
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -17,7 +17,7 @@
} }
( (
lib.mkIf config.impermanence.enable { lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = { home.persistence."/persist/replicate/home" = {
directories = [ directories = [
{ {
directory = ".vmware"; directory = ".vmware";
@ -28,7 +28,6 @@
method = "symlink"; method = "symlink";
} }
]; ];
allowOther = true;
}; };
} }
) )

View file

@ -8,14 +8,13 @@
./desktop.nix ./desktop.nix
./ssh.nix ./ssh.nix
./i18n.nix ./i18n.nix
./sync.nix ./sync
./impermanence.nix ./ollama
./disko.nix
./ollama.nix
./ai.nix ./ai.nix
./tailscale.nix ./tailscale
./steam.nix ./steam.nix
./server ./server
./storage
]; ];
nixpkgs.config.permittedInsecurePackages = [ nixpkgs.config.permittedInsecurePackages = [

View file

@ -1,267 +0,0 @@
{
lib,
pkgs,
config,
inputs,
...
}: let
# there currently is a bug with disko that causes long disk names to be generated improperly this hash function should alleviate it when used for disk names instead of what we are defaulting to
# max gpt length is 36 and disk adds formats it like disk-xxxx-zfs which means we need to be 9 characters under that
hashDisk = drive: (builtins.substring 0 27 (builtins.hashString "sha256" drive));
vdevs =
builtins.map (
disks:
builtins.map (disk: lib.attrsets.nameValuePair (hashDisk disk) disk) disks
)
config.host.storage.pool.vdevs;
cache =
builtins.map (
disk: lib.attrsets.nameValuePair (hashDisk disk) disk
)
config.host.storage.pool.cache;
datasets = config.host.storage.pool.datasets // config.host.storage.pool.extraDatasets;
in {
options.host.storage = {
enable = lib.mkEnableOption "are we going create zfs disks with disko on this device";
encryption = lib.mkEnableOption "is the vdev going to be encrypted";
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 = {
mode = lib.mkOption {
type = lib.types.str;
default = "raidz2";
description = "what level of redundancy should this pool have";
};
# list of drives in pool that will have a boot partition put onto them
bootDrives = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "list of disks that are going to have a boot partition installed on them";
default = lib.lists.flatten config.host.storage.pool.vdevs;
};
# shorthand for vdevs if you only have 1 vdev
drives = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "list of drives that are going to be in the vdev";
default = [];
};
# list of all drives in each vdev
vdevs = lib.mkOption {
type = lib.types.listOf (lib.types.listOf lib.types.str);
description = "list of disks that are going to be in";
default = [config.host.storage.pool.drives];
};
# list of cache drives for pool
cache = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "list of drives that are going to be used as cache";
default = [];
};
# Default datasets that are needed to make a functioning system
datasets = lib.mkOption {
type = lib.types.attrsOf (inputs.disko.lib.subType {
types = {inherit (inputs.disko.lib.types) zfs_fs zfs_volume;};
});
default = {
"local" = {
type = "zfs_fs";
options.canmount = "off";
};
# nix directory needs to be available pre persist and doesn't need to be snapshotted or backed up
"local/system/nix" = {
type = "zfs_fs";
mountpoint = "/nix";
options = {
atime = "off";
relatime = "off";
canmount = "on";
};
};
# dataset for root that gets rolled back on every boot
"local/system/root" = {
type = "zfs_fs";
mountpoint = "/";
options = {
canmount = "on";
};
postCreateHook = ''
zfs snapshot rpool/local/system/root@blank
'';
};
};
};
extraDatasets = lib.mkOption {
type = lib.types.attrsOf (inputs.disko.lib.subType {
types = {inherit (inputs.disko.lib.types) zfs_fs zfs_volume;};
});
description = "List of datasets to define";
default = {};
};
};
};
config = lib.mkIf config.host.storage.enable {
programs.msmtp = lib.mkIf config.host.storage.notifications.enable {
enable = true;
setSendmail = true;
defaults = {
aliases = "/etc/aliases";
port = config.host.storage.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.host.storage.notifications.host;
passwordeval = "cat ${config.host.storage.notifications.tokenFile}";
user = config.host.storage.notifications.user;
from = config.host.storage.notifications.user;
};
};
};
services.zfs = {
autoScrub.enable = true;
autoSnapshot.enable = true;
zed = lib.mkIf config.host.storage.notifications.enable {
enableMail = true;
settings = {
ZED_DEBUG_LOG = "/tmp/zed.debug.log";
ZED_EMAIL_ADDR = [config.host.storage.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;
};
};
};
disko.devices = {
disk = (
builtins.listToAttrs (
builtins.map
(drive:
lib.attrsets.nameValuePair (drive.name) {
type = "disk";
device = "/dev/disk/by-id/${drive.value}";
content = {
type = "gpt";
partitions = {
ESP = lib.mkIf (builtins.elem drive.value config.host.storage.pool.bootDrives) {
# The 2GB here for the boot partition might be a bit overkill we probably only need like 1/4th of that but storage is cheap
size = "2G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = ["umask=0077"];
};
};
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "rpool";
};
};
};
};
})
(
(lib.lists.flatten vdevs) ++ cache
)
)
);
zpool = {
rpool = {
type = "zpool";
mode = {
topology = {
type = "topology";
vdev = (
builtins.map (disks: {
mode = config.host.storage.pool.mode;
members =
builtins.map (disk: disk.name) disks;
})
vdevs
);
cache = builtins.map (disk: disk.name) cache;
};
};
options = {
ashift = "12";
autotrim = "on";
};
rootFsOptions =
{
canmount = "off";
mountpoint = "none";
xattr = "sa";
acltype = "posixacl";
relatime = "on";
compression = "lz4";
"com.sun:auto-snapshot" = "false";
}
// (
lib.attrsets.optionalAttrs config.host.storage.encryption {
encryption = "on";
keyformat = "hex";
keylocation = "prompt";
}
);
datasets = lib.mkMerge [
(
lib.attrsets.mapAttrs (name: value: {
type = value.type;
options = value.options;
mountpoint = value.mountpoint;
postCreateHook = value.postCreateHook;
})
datasets
)
];
};
};
};
};
}

View file

@ -1,134 +0,0 @@
{
config,
lib,
...
}: {
# options.storage = {
# zfs = {
# # TODO: enable option
# # when this option is enabled we need to configure and enable disko things
# # TODO: we need some way of managing notifications
# # TODO: we need options to configure zfs pools
# # we should have warnings when the configured pool is missing drives
# # 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: pools and datasets need to be passed to disko
# };
# impermanence = {
# # TODO: enable option
# # 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: 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";
config = lib.mkMerge [
{
assertions = [
{
assertion = !(config.host.impermanence.enable && !config.host.storage.enable);
message = ''
Disko storage must be enabled to use impermanence.
'';
}
];
}
(
lib.mkIf config.host.impermanence.enable {
assertions = [
{
assertion = config.host.impermanence.enable && config.host.storage.enable;
message = "Impermanence can not be used without managed host storage.";
}
];
# fixes issues with /var/lib/private not having the correct permissions https://github.com/nix-community/impermanence/issues/254
system.activationScripts."createPersistentStorageDirs".deps = ["var-lib-private-permissions" "users" "groups"];
system.activationScripts = {
"var-lib-private-permissions" = {
deps = ["specialfs"];
text = ''
mkdir -p /persist/system/root/var/lib/private
chmod 0700 /persist/system/root/var/lib/private
'';
};
};
programs.fuse.userAllowOther = true;
boot.initrd.postResumeCommands = lib.mkAfter ''
zfs rollback -r rpool/local/system/root@blank
'';
fileSystems = {
"/".neededForBoot = true;
"/persist/system/root".neededForBoot = true;
"/persist/system/var/log".neededForBoot = true;
};
host.storage.pool.extraDatasets = {
# persist datasets are datasets that contain information that we would like to keep around
"persist" = {
type = "zfs_fs";
options.canmount = "off";
options = {
"com.sun:auto-snapshot" = "true";
};
};
# this is where root data actually lives
"persist/system/root" = {
type = "zfs_fs";
mountpoint = "/persist/system/root";
};
"persist/system/var/log" = {
type = "zfs_fs";
mountpoint = "/persist/system/var/log";
# logs should be append only so we shouldn't need to snapshot them
options = {
"com.sun:auto-snapshot" = "false";
};
};
};
environment.persistence."/persist/system/var/log" = {
enable = true;
hideMounts = true;
directories = [
"/var/log"
];
};
environment.persistence."/persist/system/root" = {
enable = true;
hideMounts = true;
directories = [
"/var/lib/nixos"
"/var/lib/systemd/coredump"
];
files = [
"/etc/machine-id"
];
};
# TODO: this should live in leylas home manager configuration
security.sudo.extraConfig = "Defaults lecture=never";
}
)
];
}

View file

@ -0,0 +1,6 @@
{...}: {
imports = [
./ollama.nix
./storage.nix
];
}

View file

@ -27,20 +27,6 @@
allowedUDPPorts = ports; allowedUDPPorts = ports;
}; };
})) }))
(lib.mkIf config.host.impermanence.enable {
environment.persistence."/persist/system/root" = {
enable = true;
hideMounts = true;
directories = [
{
directory = "/var/lib/private/ollama";
user = config.services.ollama.user;
group = config.services.ollama.group;
mode = "0700";
}
];
};
})
] ]
); );
} }

View file

@ -0,0 +1,37 @@
{
config,
lib,
...
}: {
options = {
services.ollama.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.ollama.enable && config.storage.impermanence.enable;
};
};
config = lib.mkIf (config.services.ollama.enable) {
storage.datasets.replicate."system/root" = {
directories."/var/lib/private/ollama" = lib.mkIf config.services.ollama.impermanence.enable {
enable = true;
owner.name = config.services.ollama.user;
group.name = config.services.ollama.group;
owner.permissions = {
read = true;
write = true;
execute = false;
};
group.permissions = {
read = false;
write = false;
execute = false;
};
other.permissions = {
read = false;
write = false;
execute = false;
};
};
};
};
}

View file

@ -3,6 +3,6 @@
./actual.nix ./actual.nix
./proxy.nix ./proxy.nix
./fail2ban.nix ./fail2ban.nix
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,37 +0,0 @@
{
lib,
config,
...
}: let
const = import ./const.nix;
dataDirectory = const.dataDirectory;
in {
options.services.actual = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.actual.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.actual.impermanence.enable {
assertions = [
{
assertion = config.services.actual.settings.dataDir == dataDirectory;
message = "actual data location does not match persistence\nconfig directory: ${config.services.actual.settings.dataDir}\npersistence directory: ${dataDirectory}";
}
{
assertion = config.systemd.services.actual.serviceConfig.DynamicUser or false;
message = "actual systemd service must have DynamicUser enabled to use private directory";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = dataDirectory;
user = "actual";
group = "actual";
}
];
};
};
}

View file

@ -0,0 +1,22 @@
{
lib,
config,
...
}: let
const = import ./const.nix;
dataDirectory = const.dataDirectory;
in {
options.services.actual.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.actual.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.actual.enable {
storage.datasets.replicate."system/root" = {
directories."${dataDirectory}" = lib.mkIf config.services.actual.impermanence.enable {
owner.name = "actual";
group.name = "actual";
};
};
};
}

View file

@ -1,5 +1,5 @@
{...}: { {...}: {
imports = [ imports = [
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,33 +0,0 @@
{
lib,
config,
...
}: let
bazarr_data_directory = "/var/lib/bazarr";
in {
options.services.bazarr = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.bazarr.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.bazarr.impermanence.enable {
assertions = [
{
assertion = config.services.bazarr.dataDir == bazarr_data_directory;
message = "bazarr data directory does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = bazarr_data_directory;
user = "bazarr";
group = "bazarr";
}
];
};
};
}

View file

@ -0,0 +1,21 @@
{
lib,
config,
...
}: let
bazarr_data_directory = "/var/lib/bazarr";
in {
options.services.bazarr.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.bazarr.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.bazarr.enable {
storage.datasets.replicate."system/root" = {
directories."${bazarr_data_directory}" = lib.mkIf config.services.bazarr.impermanence.enable {
owner.name = "bazarr";
group.name = "bazarr";
};
};
};
}

View file

@ -1,6 +1,6 @@
{...}: { {...}: {
imports = [ imports = [
./crab-hole.nix ./crab-hole.nix
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,33 +0,0 @@
{
lib,
config,
...
}: let
workingDirectory = "/var/lib/private/crab-hole";
in {
options.services.crab-hole = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.crab-hole.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.crab-hole.impermanence.enable {
assertions = [
{
assertion =
config.systemd.services.crab-hole.serviceConfig.WorkingDirectory == (builtins.replaceStrings ["/private"] [""] workingDirectory);
message = "crab-hole working directory does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = workingDirectory;
user = "crab-hole";
group = "crab-hole";
}
];
};
};
}

View file

@ -0,0 +1,21 @@
{
lib,
config,
...
}: let
workingDirectory = "/var/lib/private/crab-hole";
in {
options.services.crab-hole.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.crab-hole.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.crab-hole.enable {
storage.datasets.replicate."system/root" = {
directories."${workingDirectory}" = lib.mkIf config.services.crab-hole.impermanence.enable {
owner.name = "crab-hole";
group.name = "crab-hole";
};
};
};
}

View file

@ -1,6 +1,6 @@
{...}: { {...}: {
imports = [ imports = [
./fail2ban.nix ./fail2ban.nix
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,34 +0,0 @@
{
lib,
config,
...
}: let
dataFolder = "/var/lib/fail2ban";
dataFile = "fail2ban.sqlite3";
in {
options.services.fail2ban = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.fail2ban.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.fail2ban.impermanence.enable {
assertions = [
{
assertion = config.services.fail2ban.daemonSettings.Definition.dbfile == "${dataFolder}/${dataFile}";
message = "fail2ban data file does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = dataFolder;
user = "fail2ban";
group = "fail2ban";
}
];
};
};
}

View file

@ -0,0 +1,22 @@
{
lib,
config,
...
}: let
dataFolder = "/var/lib/fail2ban";
dataFile = "fail2ban.sqlite3";
in {
options.services.fail2ban.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.fail2ban.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.fail2ban.enable {
storage.datasets.replicate."system/root" = {
directories."${dataFolder}" = lib.mkIf config.services.fail2ban.impermanence.enable {
owner.name = "fail2ban";
group.name = "fail2ban";
};
};
};
}

View file

@ -1,5 +1,5 @@
{...}: { {...}: {
imports = [ imports = [
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,26 +0,0 @@
{
lib,
config,
...
}: {
options.services.flaresolverr = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.flaresolverr.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.flaresolverr.impermanence.enable {
# FlareSolverr typically doesn't need persistent storage as it's a proxy service
# but we'll add basic structure in case it's needed for logs or configuration
environment.persistence."/persist/system/root" = {
directories = [
{
directory = "/var/lib/flaresolverr";
user = "flaresolverr";
group = "flaresolverr";
}
];
};
};
}

View file

@ -0,0 +1,19 @@
{
lib,
config,
...
}: {
options.services.flaresolverr.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.flaresolverr.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.flaresolverr.enable {
storage.datasets.replicate."system/root" = {
directories."/var/lib/flaresolverr" = lib.mkIf config.services.flaresolverr.impermanence.enable {
owner.name = "flaresolverr";
group.name = "flaresolverr";
};
};
};
}

View file

@ -4,6 +4,6 @@
./proxy.nix ./proxy.nix
./database.nix ./database.nix
./fail2ban.nix ./fail2ban.nix
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,35 +0,0 @@
{
lib,
config,
...
}: let
stateDir = "/var/lib/forgejo";
in {
options.services.forgejo = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.forgejo.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.forgejo.impermanence.enable {
assertions = [
{
assertion = config.services.forgejo.stateDir == stateDir;
message = "forgejo state directory does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
enable = true;
hideMounts = true;
directories = [
{
directory = stateDir;
user = "forgejo";
group = "forgejo";
}
];
};
};
}

View file

@ -0,0 +1,21 @@
{
lib,
config,
...
}: let
stateDir = "/var/lib/forgejo";
in {
options.services.forgejo.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.forgejo.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.forgejo.enable {
storage.datasets.replicate."system/root" = {
directories."${stateDir}" = lib.mkIf config.services.forgejo.impermanence.enable {
owner.name = "forgejo";
group.name = "forgejo";
};
};
};
}

View file

@ -4,7 +4,7 @@
./proxy.nix ./proxy.nix
./database.nix ./database.nix
./fail2ban.nix ./fail2ban.nix
./impermanence.nix ./storage.nix
./extensions ./extensions
]; ];
} }

View file

@ -1,26 +0,0 @@
{
lib,
config,
...
}: let
configDir = "/var/lib/hass";
in
lib.mkIf (config.host.impermanence.enable && config.services.home-assistant.enable) {
assertions = [
{
assertion = config.services.home-assistant.configDir == configDir;
message = "home assistant config directory does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
enable = true;
hideMounts = true;
directories = [
{
directory = configDir;
user = "hass";
group = "hass";
}
];
};
}

View file

@ -0,0 +1,21 @@
{
lib,
config,
...
}: let
configDir = "/var/lib/hass";
in {
options.services.home-assistant.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.home-assistant.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.home-assistant.enable {
storage.datasets.replicate."system/root" = {
directories."${configDir}" = lib.mkIf config.services.home-assistant.impermanence.enable {
owner.name = "hass";
group.name = "hass";
};
};
};
}

View file

@ -3,7 +3,7 @@
./proxy.nix ./proxy.nix
./database.nix ./database.nix
./fail2ban.nix ./fail2ban.nix
./impermanence.nix ./storage.nix
]; ];
# NOTE: This shouldn't be needed now that we are out of testing # NOTE: This shouldn't be needed now that we are out of testing

View file

@ -1,32 +0,0 @@
{
lib,
config,
...
}: let
mediaLocation = "/var/lib/immich";
in {
options.services.immich = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.immich.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.immich.impermanence.enable {
assertions = [
{
assertion = config.services.immich.mediaLocation == mediaLocation;
message = "immich media location does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = mediaLocation;
user = "immich";
group = "immich";
}
];
};
};
}

View file

@ -0,0 +1,21 @@
{
lib,
config,
...
}: let
mediaLocation = "/var/lib/immich";
in {
options.services.immich.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.immich.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.immich.enable {
storage.datasets.replicate."system/root" = {
directories."${mediaLocation}" = lib.mkIf config.services.immich.impermanence.enable {
owner.name = "immich";
group.name = "immich";
};
};
};
}

View file

@ -1,5 +1,5 @@
{...}: { {...}: {
imports = [ imports = [
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,33 +0,0 @@
{
lib,
config,
...
}: let
jackett_data_directory = "/var/lib/jackett/.config/Jackett";
in {
options.services.jackett = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.jackett.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.jackett.impermanence.enable {
assertions = [
{
assertion = config.services.jackett.dataDir == jackett_data_directory;
message = "jackett data directory does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = jackett_data_directory;
user = "jackett";
group = "jackett";
}
];
};
};
}

View file

@ -0,0 +1,21 @@
{
lib,
config,
...
}: let
jackett_data_directory = "/var/lib/jackett/.config/Jackett";
in {
options.services.jackett.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.jackett.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.jackett.enable {
storage.datasets.replicate."system/root" = {
directories."${jackett_data_directory}" = lib.mkIf config.services.jackett.impermanence.enable {
owner.name = "jackett";
group.name = "jackett";
};
};
};
}

View file

@ -3,6 +3,6 @@
./jellyfin.nix ./jellyfin.nix
./proxy.nix ./proxy.nix
./fail2ban.nix ./fail2ban.nix
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,73 +0,0 @@
{
lib,
config,
...
}: let
jellyfin_data_directory = "/var/lib/jellyfin";
jellyfin_cache_directory = "/var/cache/jellyfin";
in {
options.services.jellyfin = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.jellyfin.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.jellyfin.impermanence.enable {
fileSystems."/persist/system/jellyfin".neededForBoot = true;
host.storage.pool.extraDatasets = {
# sops age key needs to be available to pre persist for user generation
"persist/system/jellyfin" = {
type = "zfs_fs";
mountpoint = "/persist/system/jellyfin";
options = {
atime = "off";
relatime = "off";
canmount = "on";
};
};
};
assertions = [
{
assertion = config.services.jellyfin.dataDir == jellyfin_data_directory;
message = "jellyfin data directory does not match persistence";
}
{
assertion = config.services.jellyfin.cacheDir == jellyfin_cache_directory;
message = "jellyfin cache directory does not match persistence";
}
];
environment.persistence = {
"/persist/system/root" = {
directories = [
{
directory = jellyfin_data_directory;
user = "jellyfin";
group = "jellyfin";
}
{
directory = jellyfin_cache_directory;
user = "jellyfin";
group = "jellyfin";
}
];
};
"/persist/system/jellyfin" = {
enable = true;
hideMounts = true;
directories = [
{
directory = config.services.jellyfin.media_directory;
user = "jellyfin";
group = "jellyfin_media";
mode = "1770";
}
];
};
};
};
}

View file

@ -0,0 +1,56 @@
{
lib,
config,
...
}: let
jellyfin_data_directory = "/var/lib/jellyfin";
jellyfin_cache_directory = "/var/cache/jellyfin";
in {
options.services.jellyfin.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.jellyfin.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.jellyfin.enable {
storage.datasets.replicate = {
"system/root" = {
directories = {
"${jellyfin_data_directory}" = lib.mkIf config.services.jellyfin.impermanence.enable {
enable = true;
owner.name = "jellyfin";
group.name = "jellyfin";
};
"${jellyfin_cache_directory}" = lib.mkIf config.services.jellyfin.impermanence.enable {
enable = true;
owner.name = "jellyfin";
group.name = "jellyfin";
};
};
};
"system/media" = {
mount = "/persist/replicate/system/media";
directories."${config.services.jellyfin.media_directory}" = lib.mkIf config.services.jellyfin.impermanence.enable {
enable = true;
owner.name = "jellyfin";
group.name = "jellyfin_media";
owner.permissions = {
read = true;
write = true;
execute = true;
};
group.permissions = {
read = true;
write = true;
execute = true;
};
other.permissions = {
read = false;
write = false;
execute = false;
};
};
};
};
};
}

View file

@ -1,5 +1,5 @@
{...}: { {...}: {
imports = [ imports = [
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,33 +0,0 @@
{
lib,
config,
...
}: let
lidarr_data_directory = "/var/lib/lidarr/.config/Lidarr";
in {
options.services.lidarr = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.lidarr.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.lidarr.impermanence.enable {
assertions = [
{
assertion = config.services.lidarr.dataDir == lidarr_data_directory;
message = "lidarr data directory does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = lidarr_data_directory;
user = "lidarr";
group = "lidarr";
}
];
};
};
}

View file

@ -0,0 +1,21 @@
{
lib,
config,
...
}: let
lidarr_data_directory = "/var/lib/lidarr/.config/Lidarr";
in {
options.services.lidarr.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.lidarr.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.lidarr.enable {
storage.datasets.replicate."system/root" = {
directories."${lidarr_data_directory}" = lib.mkIf config.services.lidarr.impermanence.enable {
owner.name = "lidarr";
group.name = "lidarr";
};
};
};
}

View file

@ -74,7 +74,7 @@ in {
); );
} }
# (lib.mkIf config.host.impermanence.enable { # (lib.mkIf config.host.impermanence.enable {
# environment.persistence."/persist/system/root" = { # environment.persistence."/persist/replicate/system/root" = {
# enable = true; # enable = true;
# hideMounts = true; # hideMounts = true;
# directories = [ # directories = [

View file

@ -2,7 +2,7 @@
imports = [ imports = [
./proxy.nix ./proxy.nix
./fail2ban.nix ./fail2ban.nix
./impermanence.nix ./storage.nix
./panoramax.nix ./panoramax.nix
./database.nix ./database.nix
]; ];

View file

@ -1,20 +0,0 @@
{
lib,
config,
...
}: {
options.services.panoramax = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.panoramax.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.panoramax.impermanence.enable {
# TODO: configure impermanence for panoramax data
# This would typically include directories like:
# - /var/lib/panoramax
# - panoramax storage directories
# - any cache or temporary directories that need to persist
};
}

View file

@ -0,0 +1,19 @@
{
lib,
config,
...
}: {
options.services.panoramax.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.panoramax.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.panoramax.enable {
storage.datasets.replicate."system/root" = {
directories."/var/lib/panoramax" = lib.mkIf config.services.panoramax.impermanence.enable {
owner.name = "panoramax";
group.name = "panoramax";
};
};
};
}

View file

@ -4,6 +4,6 @@
./proxy.nix ./proxy.nix
./database.nix ./database.nix
./fail2ban.nix ./fail2ban.nix
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,32 +0,0 @@
{
config,
lib,
...
}: let
dataDir = "/var/lib/paperless";
in {
options.services.paperless = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.paperless.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.paperless.impermanence.enable {
assertions = [
{
assertion = config.services.paperless.dataDir == dataDir;
message = "paperless data location does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = dataDir;
user = "paperless";
group = "paperless";
}
];
};
};
}

View file

@ -0,0 +1,21 @@
{
config,
lib,
...
}: let
dataDir = "/var/lib/paperless";
in {
options.services.paperless.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.paperless.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.paperless.enable {
storage.datasets.replicate."system/root" = {
directories."${dataDir}" = lib.mkIf config.services.paperless.impermanence.enable {
owner.name = "paperless";
group.name = "paperless";
};
};
};
}

View file

@ -1,6 +1,6 @@
{...}: { {...}: {
imports = [ imports = [
./postgres.nix ./postgres.nix
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,27 +0,0 @@
{
config,
lib,
...
}: let
dataDir = "/var/lib/postgresql/16";
in {
config = lib.mkIf (config.services.postgresql.enable && config.host.impermanence.enable) {
assertions = [
{
assertion = config.services.postgresql.dataDir == dataDir;
message = "postgres data directory does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
enable = true;
hideMounts = true;
directories = [
{
directory = dataDir;
user = "postgres";
group = "postgres";
}
];
};
};
}

View file

@ -0,0 +1,21 @@
{
config,
lib,
...
}: let
dataDir = "/var/lib/postgresql/16";
in {
options.services.postgresql.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.postgresql.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.postgresql.enable {
storage.datasets.replicate."system/root" = {
directories."${dataDir}" = lib.mkIf config.services.postgresql.impermanence.enable {
owner.name = "postgres";
group.name = "postgres";
};
};
};
}

View file

@ -1,6 +1,6 @@
{...}: { {...}: {
imports = [ imports = [
./qbittorent.nix ./qbittorent.nix
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,61 +0,0 @@
{
lib,
config,
...
}: let
qbittorent_profile_directory = "/var/lib/qBittorrent/";
in {
options.services.qbittorrent = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.qbittorrent.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.qbittorrent.impermanence.enable {
fileSystems."/persist/system/qbittorrent".neededForBoot = true;
host.storage.pool.extraDatasets = {
# sops age key needs to be available to pre persist for user generation
"persist/system/qbittorrent" = {
type = "zfs_fs";
mountpoint = "/persist/system/qbittorrent";
options = {
canmount = "on";
};
};
};
assertions = [
{
assertion = config.services.qbittorrent.profileDir == qbittorent_profile_directory;
message = "qbittorrent data directory does not match persistence";
}
];
environment.persistence = {
"/persist/system/root" = {
directories = [
{
directory = qbittorent_profile_directory;
user = "qbittorrent";
group = "qbittorrent";
}
];
};
"/persist/system/qbittorrent" = {
enable = true;
hideMounts = true;
directories = [
{
directory = config.services.qbittorrent.mediaDir;
user = "qbittorrent";
group = "qbittorrent";
mode = "1775";
}
];
};
};
};
}

View file

@ -0,0 +1,46 @@
{
lib,
config,
...
}: let
qbittorent_profile_directory = "/var/lib/qBittorrent/";
in {
options.services.qbittorrent.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.qbittorrent.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.qbittorrent.enable {
storage.datasets.replicate = {
"system/root" = {
directories."${qbittorent_profile_directory}" = lib.mkIf config.services.qbittorrent.impermanence.enable {
owner.name = "qbittorrent";
group.name = "qbittorrent";
};
};
"system/media" = {
mount = "/persist/replicate/system/media";
directories."${config.services.qbittorrent.mediaDir}" = lib.mkIf config.services.qbittorrent.impermanence.enable {
owner.name = "qbittorrent";
group.name = "qbittorrent";
owner.permissions = {
read = true;
write = true;
execute = true;
};
group.permissions = {
read = true;
write = true;
execute = true;
};
other.permissions = {
read = true;
write = false;
execute = true;
};
};
};
};
};
}

View file

@ -1,5 +1,5 @@
{...}: { {...}: {
imports = [ imports = [
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,33 +0,0 @@
{
lib,
config,
...
}: let
radarr_data_directory = "/var/lib/radarr/.config/Radarr";
in {
options.services.radarr = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.radarr.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.radarr.impermanence.enable {
assertions = [
{
assertion = config.services.radarr.dataDir == radarr_data_directory;
message = "radarr data directory does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = radarr_data_directory;
user = "radarr";
group = "radarr";
}
];
};
};
}

View file

@ -0,0 +1,21 @@
{
lib,
config,
...
}: let
radarr_data_directory = "/var/lib/radarr/.config/Radarr";
in {
options.services.radarr.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.radarr.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.radarr.enable {
storage.datasets.replicate."system/root" = {
directories."${radarr_data_directory}" = lib.mkIf config.services.radarr.impermanence.enable {
owner.name = "radarr";
group.name = "radarr";
};
};
};
}

View file

@ -1,6 +1,6 @@
{...}: { {...}: {
imports = [ imports = [
./reverseProxy.nix ./reverseProxy.nix
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,21 +0,0 @@
{
lib,
config,
...
}: let
dataDir = "/var/lib/acme";
in {
config = lib.mkIf (config.host.impermanence.enable && config.services.reverseProxy.enable) {
environment.persistence."/persist/system/root" = {
enable = true;
hideMounts = true;
directories = [
{
directory = dataDir;
user = "acme";
group = "acme";
}
];
};
};
}

View file

@ -0,0 +1,21 @@
{
lib,
config,
...
}: let
dataDir = "/var/lib/acme";
in {
options.services.reverseProxy.impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.reverseProxy.enable && config.storage.impermanence.enable;
};
config = lib.mkIf config.services.reverseProxy.enable {
storage.datasets.replicate."system/root" = {
directories."${dataDir}" = lib.mkIf config.services.reverseProxy.impermanence.enable {
owner.name = "acme";
group.name = "acme";
};
};
};
}

View file

@ -1,5 +1,5 @@
{...}: { {...}: {
imports = [ imports = [
./impermanence.nix ./storage.nix
]; ];
} }

View file

@ -1,33 +0,0 @@
{
lib,
config,
...
}: let
sonarr_data_directory = "/var/lib/sonarr/.config/NzbDrone";
in {
options.services.sonarr = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.sonarr.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.sonarr.impermanence.enable {
assertions = [
{
assertion = config.services.sonarr.dataDir == sonarr_data_directory;
message = "sonarr data directory does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = sonarr_data_directory;
user = "sonarr";
group = "sonarr";
}
];
};
};
}

Some files were not shown because too many files have changed in this diff Show more