persist: allow persisting of individual files, not just directories

i actually do already, with ~/.ssh/id_ed25519 -- it works only as a fluke
This commit is contained in:
Colin 2023-07-08 00:56:20 +00:00
parent 8e4dc0c6ae
commit 0a519eddb4
25 changed files with 64 additions and 43 deletions

View File

@ -44,7 +44,7 @@
sane.persist.sys.plaintext = [
# TODO: this is overly broad; only need media and share directories to be persisted
{ user = "colin"; group = "users"; directory = "/var/lib/uninsane"; }
{ user = "colin"; group = "users"; path = "/var/lib/uninsane"; }
];
# make sure large media is stored to the HDD
sane.persist.sys.ext = [
@ -52,19 +52,19 @@
user = "colin";
group = "users";
mode = "0777";
directory = "/var/lib/uninsane/media/Videos";
path = "/var/lib/uninsane/media/Videos";
}
{
user = "colin";
group = "users";
mode = "0777";
directory = "/var/lib/uninsane/media/freeleech";
path = "/var/lib/uninsane/media/freeleech";
}
{
user = "colin";
group = "users";
mode = "0777";
directory = "/var/lib/uninsane/media/datasets";
path = "/var/lib/uninsane/media/datasets";
}
];

View File

@ -13,7 +13,7 @@ in
lib.mkIf false
{
sane.persist.sys.plaintext = [
{ inherit user group; mode = "0700"; directory = svc-dir; }
{ inherit user group; mode = "0700"; path = svc-dir; }
];
services.calibre-web.enable = true;

View File

@ -20,7 +20,7 @@
# lib.mkIf false
{
sane.persist.sys.plaintext = [
{ user = "ejabberd"; group = "ejabberd"; directory = "/var/lib/ejabberd"; }
{ user = "ejabberd"; group = "ejabberd"; path = "/var/lib/ejabberd"; }
];
sane.ports.ports."3478" = {
protocol = [ "tcp" "udp" ];

View File

@ -20,9 +20,9 @@ in
{
sane.persist.sys.plaintext = [
# TODO: mode? could be more granular
{ user = "opendkim"; group = "opendkim"; directory = "/var/lib/opendkim"; }
{ user = "root"; group = "root"; directory = "/var/lib/postfix"; }
{ user = "root"; group = "root"; directory = "/var/spool/mail"; }
{ user = "opendkim"; group = "opendkim"; path = "/var/lib/opendkim"; }
{ user = "root"; group = "root"; path = "/var/lib/postfix"; }
{ user = "root"; group = "root"; path = "/var/spool/mail"; }
# *probably* don't need these dirs:
# "/var/lib/dhparams" # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/dhparams.nix
# "/var/lib/dovecot"

View File

@ -16,7 +16,7 @@
mode = "0400";
};
sane.persist.sys.plaintext = [
{ user = "freshrss"; group = "freshrss"; directory = "/var/lib/freshrss"; }
{ user = "freshrss"; group = "freshrss"; path = "/var/lib/freshrss"; }
];
services.freshrss.enable = true;

View File

@ -4,7 +4,7 @@
{
sane.persist.sys.plaintext = [
# TODO: mode? could be more granular
{ user = "git"; group = "gitea"; directory = "/var/lib/gitea"; }
{ user = "git"; group = "gitea"; path = "/var/lib/gitea"; }
];
services.gitea.enable = true;
services.gitea.user = "git"; # default is 'gitea'

View File

@ -12,7 +12,7 @@ lib.mkIf false # i don't actively use ipfs anymore
{
sane.persist.sys.plaintext = [
# TODO: mode? could be more granular
{ user = "261"; group = "261"; directory = "/var/lib/ipfs"; }
{ user = "261"; group = "261"; path = "/var/lib/ipfs"; }
];
networking.firewall.allowedTCPPorts = [ 4001 ];

View File

@ -3,7 +3,7 @@
{
sane.persist.sys.plaintext = [
# TODO: mode? we only need this to save Indexer creds ==> migrate to config?
{ user = "root"; group = "root"; directory = "/var/lib/jackett"; }
{ user = "root"; group = "root"; path = "/var/lib/jackett"; }
];
services.jackett.enable = true;

View File

@ -41,7 +41,7 @@
};
sane.persist.sys.plaintext = [
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; directory = "/var/lib/jellyfin"; }
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin"; }
];
sane.fs."/var/lib/jellyfin/config/logging.json" = {
# "Emby.Dlna" logging: <https://jellyfin.org/docs/general/networking/dlna>

View File

@ -5,7 +5,7 @@ let
in
{
sane.persist.sys.plaintext = [
{ inherit user group; mode = "0700"; directory = stateDir; }
{ inherit user group; mode = "0700"; path = stateDir; }
];
services.komga.enable = true;

View File

@ -11,7 +11,7 @@
];
sane.persist.sys.plaintext = [
{ user = "matrix-synapse"; group = "matrix-synapse"; directory = "/var/lib/matrix-synapse"; }
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/matrix-synapse"; }
];
services.matrix-synapse.enable = true;
# this changes the default log level from INFO to WARN.

View File

@ -6,7 +6,7 @@
lib.mkIf false
{
sane.persist.sys.plaintext = [
{ user = "matrix-synapse"; group = "matrix-synapse"; directory = "/var/lib/mx-puppet-discord"; }
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/mx-puppet-discord"; }
];
services.matrix-synapse.settings.app_service_config_files = [

View File

@ -104,7 +104,7 @@ in
sane.persist.sys.plaintext = [
# TODO: mode?
{ user = "matrix-appservice-irc"; group = "matrix-appservice-irc"; directory = "/var/lib/matrix-appservice-irc"; }
{ user = "matrix-appservice-irc"; group = "matrix-appservice-irc"; path = "/var/lib/matrix-appservice-irc"; }
];
# XXX: matrix-appservice-irc PreStart tries to chgrp the registration.yml to matrix-synapse,

View File

@ -3,8 +3,8 @@
{ config, pkgs, ... }:
{
sane.persist.sys.plaintext = [
{ user = "mautrix-signal"; group = "mautrix-signal"; directory = "/var/lib/mautrix-signal"; }
{ user = "signald"; group = "signald"; directory = "/var/lib/signald"; }
{ user = "mautrix-signal"; group = "mautrix-signal"; path = "/var/lib/mautrix-signal"; }
{ user = "signald"; group = "signald"; path = "/var/lib/signald"; }
];
# allow synapse to read the registration file

View File

@ -2,7 +2,7 @@
{
sane.persist.sys.plaintext = [
{ user = "navidrome"; group = "navidrome"; directory = "/var/lib/navidrome"; }
{ user = "navidrome"; group = "navidrome"; path = "/var/lib/navidrome"; }
];
services.navidrome.enable = true;
services.navidrome.settings = {

View File

@ -134,8 +134,8 @@ in
sane.persist.sys.plaintext = [
# TODO: mode?
{ user = "acme"; group = "acme"; directory = "/var/lib/acme"; }
{ user = "colin"; group = "users"; directory = "/var/www/sites"; }
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; }
{ user = "colin"; group = "users"; path = "/var/www/sites"; }
];
# let's encrypt default chain looks like:

View File

@ -6,7 +6,7 @@ let
in
{
sane.persist.sys.plaintext = lib.mkIf cfg.enable [
{ user = "pict-rs"; group = "pict-rs"; directory = cfg.dataDir; }
{ user = "pict-rs"; group = "pict-rs"; path = cfg.dataDir; }
];
systemd.services.pict-rs.serviceConfig = {

View File

@ -15,7 +15,7 @@ let
in
{
sane.persist.sys.plaintext = [
{ user = "pleroma"; group = "pleroma"; directory = "/var/lib/pleroma"; }
{ user = "pleroma"; group = "pleroma"; path = "/var/lib/pleroma"; }
];
services.pleroma.enable = true;
services.pleroma.secretConfigFile = config.sops.secrets.pleroma_secrets.path;

View File

@ -3,7 +3,7 @@
{
sane.persist.sys.plaintext = [
# TODO: mode?
{ user = "postgres"; group = "postgres"; directory = "/var/lib/postgresql"; }
{ user = "postgres"; group = "postgres"; path = "/var/lib/postgresql"; }
];
services.postgresql.enable = true;
# services.postgresql.dataDir = "/opt/postgresql/13";

View File

@ -10,7 +10,7 @@
lib.mkIf false
{
sane.persist.sys.plaintext = [
{ user = "prosody"; group = "prosody"; directory = "/var/lib/prosody"; }
{ user = "prosody"; group = "prosody"; path = "/var/lib/prosody"; }
];
sane.ports.ports."5222" = {
protocol = [ "tcp" ];

View File

@ -3,7 +3,7 @@
{
sane.persist.sys.plaintext = [
# TODO: mode? we need this specifically for the stats tracking in .config/
{ user = "transmission"; group = "transmission"; directory = "/var/lib/transmission"; }
{ user = "transmission"; group = "transmission"; path = "/var/lib/transmission"; }
];
services.transmission.enable = true;
services.transmission.settings = {

View File

@ -27,7 +27,7 @@ in
sane.persist.sys.plaintext = lib.mkIf cfg.enable [
# intentionally allow other users to write to the guest folder
{ directory = "/home/guest"; user = "guest"; group = "users"; mode = "0775"; }
{ path = "/home/guest"; user = "guest"; group = "users"; mode = "0775"; }
];
};
}

View File

@ -74,7 +74,7 @@ in
programs.ccache.enable = true;
nix.settings.extra-sandbox-paths = [ cacheDir ];
sane.persist.sys.plaintext = [
{ group = "nixbld"; mode = "0775"; directory = config.programs.ccache.cacheDir; }
{ group = "nixbld"; mode = "0775"; path = config.programs.ccache.cacheDir; }
];
sane.fs."${cacheDir}/ccache.conf" = sane-lib.fs.wantedText ''
max_size = 50G

View File

@ -50,6 +50,7 @@ let path = rec {
walk = start: end: if start == end then
[ start ]
else
assert end != "/"; # else there's no path from `start` to `end`!
(walk start (parent end)) ++ [ end ]
;
};

View File

@ -76,6 +76,14 @@ let
how to link the store entry into the fs
'';
};
type = mkOption {
type = types.enum [ "dir" "file" ];
default = "dir";
description = ''
whether the thing being persisted is a whole directory,
or just one file.
'';
};
};
};
@ -84,16 +92,16 @@ let
entryOpts
{
options = {
directory = mkOption {
path = mkOption {
type = types.str;
};
};
}
];
# allow "bar/baz" as shorthand for { directory = "bar/baz"; }
# allow "bar/baz" as shorthand for { path = "bar/baz"; }
entryInStoreOrShorthand = types.coercedTo
types.str
(d: { directory = d; })
(d: { path = d; })
entryInStore;
# allow the user to provide the `acl` field inline: we pop acl sub-attributes placed at the
@ -123,11 +131,12 @@ let
# this submodule creates one attr per store, so that the user can specify something like:
# <option>.private.".cache/vim" = { mode = "0700"; };
# to place ".cache/vim" into the private store and create with the appropriate mode
dirsSubModule = types.submodule ({ config, ... }: {
entrySubmodule = types.submodule ({ config, ... }: {
# TODO: this should be a plain-old `attrsOf (convertInlineAcl entryInStoreOrShorthand)` with downstream checks,
# rather than being filled in based on *other* settings.
# otherwise, it behaves poorly when `sane.persist.enable = false`
options = lib.attrsets.unionOfDisjoint
# create one option per store:
(mapAttrs (store: store-cfg: mkOption {
default = [];
type = types.listOf (convertInlineAcl entryInStoreOrShorthand);
@ -135,8 +144,9 @@ let
suffix = if store-cfg.storeDescription != null then
": ${store-cfg.storeDescription}"
else "";
in "directories to persist in ${store}${suffix}";
in "directories/files to persist in ${store}${suffix}";
}) cfg.stores)
# or allow direct access by path
{
byPath = mkOption {
type = types.attrsOf (convertInlineAcl entryAtPath);
@ -150,11 +160,11 @@ let
config = let
# set the `store` attribute on one dir attrset
annotateWithStore = store: dir: {
"${dir.directory}".store = store;
"${dir.path}".store = store;
};
# convert an `entryInStore` to an `entryAtPath` (less the `store` item)
dirToAttrs = dir: {
"${dir.directory}" = builtins.removeAttrs dir ["directory"];
"${dir.path}" = builtins.removeAttrs dir ["path"];
};
store-names = attrNames cfg.stores;
# :: (store -> entry -> AttrSet) -> [AttrSet]
@ -183,9 +193,9 @@ in
description = "define / fs root to be a tmpfs. make sure to mount some other device to /nix";
};
sane.persist.sys = mkOption {
description = "directories to persist to disk, relative to the fs root /";
description = "directories (or files) to persist to disk, relative to the fs root /";
default = {};
type = dirsSubModule;
type = entrySubmodule;
};
sane.persist.stores = mkOption {
type = types.attrsOf storeType;
@ -202,6 +212,7 @@ in
];
config = let
# String => entryAtPath => generated toplevel config
cfgFor = fspath: opt:
let
store = opt.store;
@ -221,10 +232,19 @@ in
symlink.acl = opt.acl;
symlink.target = fsPathToBackingPath fspath;
});
# create the backing path as a dir
sane.fs."${fsPathToBackingPath fspath}".dir = {};
}
(lib.optionalAttrs (opt.type == "dir") {
# create the backing path as a dir
sane.fs."${fsPathToBackingPath fspath}".dir = {
acl = config.sane.fs."${fspath}".generated.acl;
};
})
(lib.optionalAttrs (opt.type == "file") {
# ensure the backing path of this file's parent exists.
# XXX: this forces the backing parent to be a directory
# this is almost always what is wanted, but it's sometimes an arbitrary constraint
sane.fs."${path.parent (fsPathToBackingPath fspath)}".dir = {};
})
{
# default each item along the backing path to have the same acl as the location it would be mounted.
sane.fs = lib.mkMerge (builtins.map
@ -233,7 +253,7 @@ in
generated.acl = config.sane.fs."${fsSubpath}".generated.acl;
};
})
(path.walk store.prefix fspath)
(path.walk store.prefix (path.parent fspath))
);
}
];