feat: refactored database configuration
This commit is contained in:
parent
e57c1df6e5
commit
f9c27c82b6
8 changed files with 229 additions and 204 deletions
|
|
@ -102,13 +102,6 @@
|
||||||
directories = ["leyla_documents" "eve_documents" "users_documents" "media"];
|
directories = ["leyla_documents" "eve_documents" "users_documents" "media"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
postgres = {
|
|
||||||
extraUsers = {
|
|
||||||
leyla = {
|
|
||||||
isAdmin = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.network = {
|
systemd.network = {
|
||||||
|
|
@ -220,6 +213,12 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
|
# PostgreSQL database server
|
||||||
|
postgresql = {
|
||||||
|
enable = true;
|
||||||
|
adminUsers = ["leyla"];
|
||||||
|
};
|
||||||
|
|
||||||
# temp enable desktop environment for setup
|
# temp enable desktop environment for setup
|
||||||
# Enable the X11 windowing system.
|
# Enable the X11 windowing system.
|
||||||
xserver.enable = true;
|
xserver.enable = true;
|
||||||
|
|
@ -327,7 +326,7 @@
|
||||||
enable = true;
|
enable = true;
|
||||||
domain = "home.jan-leila.com";
|
domain = "home.jan-leila.com";
|
||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
database = "postgres";
|
postgres.enable = true;
|
||||||
|
|
||||||
extensions = {
|
extensions = {
|
||||||
sonos.enable = true;
|
sonos.enable = true;
|
||||||
|
|
|
||||||
|
|
@ -2,40 +2,31 @@
|
||||||
lib,
|
lib,
|
||||||
config,
|
config,
|
||||||
...
|
...
|
||||||
}: {
|
}: let
|
||||||
config = lib.mkIf config.services.forgejo.enable (
|
usingPostgres = config.services.forgejo.database.type == "postgres";
|
||||||
lib.mkMerge [
|
in {
|
||||||
|
config = lib.mkIf config.services.forgejo.enable {
|
||||||
|
assertions = [
|
||||||
{
|
{
|
||||||
host = {
|
assertion = !usingPostgres || config.services.postgresql.enable;
|
||||||
postgres = {
|
message = "PostgreSQL must be enabled when Forgejo database type is postgres";
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = config.services.forgejo.settings.database.DB_TYPE == "postgres";
|
|
||||||
message = "Forgejo database type must be postgres";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
(lib.mkIf config.host.postgres.enable {
|
{
|
||||||
host = {
|
assertion = !(usingPostgres && config.services.forgejo.database.createDatabase) || (builtins.any (db: db == "forgejo") config.services.postgresql.ensureDatabases);
|
||||||
postgres = {
|
message = "Forgejo built-in database creation failed - expected 'forgejo' in ensureDatabases but got: ${builtins.toString config.services.postgresql.ensureDatabases}";
|
||||||
extraUsers = {
|
}
|
||||||
forgejo = {
|
{
|
||||||
isClient = true;
|
assertion = !(usingPostgres && config.services.forgejo.database.createDatabase) || (builtins.any (user: user.name == "forgejo") config.services.postgresql.ensureUsers);
|
||||||
createUser = true;
|
message = "Forgejo built-in user creation failed - expected user 'forgejo' in ensureUsers but got: ${builtins.toString (builtins.map (u: u.name) config.services.postgresql.ensureUsers)}";
|
||||||
};
|
}
|
||||||
};
|
];
|
||||||
extraDatabases = {
|
|
||||||
forgejo = {
|
services.forgejo.database.createDatabase = lib.mkDefault usingPostgres;
|
||||||
name = "forgejo";
|
|
||||||
};
|
systemd.services.forgejo = lib.mkIf usingPostgres {
|
||||||
};
|
requires = [
|
||||||
};
|
config.systemd.services.postgresql.name
|
||||||
};
|
];
|
||||||
})
|
};
|
||||||
]
|
};
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,55 +2,52 @@
|
||||||
lib,
|
lib,
|
||||||
config,
|
config,
|
||||||
...
|
...
|
||||||
}: let
|
}: {
|
||||||
dbUser = "hass";
|
options.services.home-assistant = {
|
||||||
in {
|
postgres = {
|
||||||
config = lib.mkIf config.services.home-assistant.enable (
|
enable = lib.mkOption {
|
||||||
lib.mkMerge [
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Use PostgreSQL instead of SQLite";
|
||||||
|
};
|
||||||
|
user = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "hass";
|
||||||
|
description = "Database user name";
|
||||||
|
};
|
||||||
|
database = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "hass";
|
||||||
|
description = "Database name";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.services.home-assistant.enable {
|
||||||
|
assertions = [
|
||||||
{
|
{
|
||||||
host = {
|
assertion = !config.services.home-assistant.postgres.enable || config.services.postgresql.enable;
|
||||||
postgres = {
|
message = "PostgreSQL must be enabled when using postgres database for Home Assistant";
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = config.services.home-assistant.database == "postgres";
|
|
||||||
message = "Home Assistant database type must be postgres";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
(lib.mkIf config.host.postgres.enable {
|
];
|
||||||
host = {
|
|
||||||
postgres = {
|
|
||||||
extraUsers = {
|
|
||||||
${dbUser} = {
|
|
||||||
isClient = true;
|
|
||||||
createUser = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
extraDatabases = {
|
|
||||||
${dbUser} = {
|
|
||||||
name = dbUser;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.home-assistant = {
|
services.postgresql.databases.home-assistant = lib.mkIf config.services.home-assistant.postgres.enable {
|
||||||
extraPackages = python3Packages:
|
enable = true;
|
||||||
with python3Packages; [
|
user = config.services.home-assistant.postgres.user;
|
||||||
psycopg2
|
database = config.services.home-assistant.postgres.database;
|
||||||
];
|
};
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.home-assistant = {
|
services.home-assistant = lib.mkIf config.services.home-assistant.postgres.enable {
|
||||||
requires = [
|
extraPackages = python3Packages:
|
||||||
config.systemd.services.postgresql.name
|
with python3Packages; [
|
||||||
];
|
psycopg2
|
||||||
};
|
];
|
||||||
})
|
};
|
||||||
]
|
|
||||||
);
|
systemd.services.home-assistant = lib.mkIf config.services.home-assistant.postgres.enable {
|
||||||
|
requires = [
|
||||||
|
config.systemd.services.postgresql.name
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,28 @@
|
||||||
config,
|
config,
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
config = lib.mkIf config.services.immich.enable (lib.mkMerge [
|
config = lib.mkIf config.services.immich.enable {
|
||||||
{
|
assertions = [
|
||||||
host = {
|
{
|
||||||
postgres = {
|
assertion = !config.services.immich.database.enable || config.services.postgresql.enable;
|
||||||
enable = true;
|
message = "PostgreSQL must be enabled when using postgres database for Immich";
|
||||||
};
|
}
|
||||||
};
|
{
|
||||||
}
|
assertion = !(config.services.immich.database.enable && config.services.immich.database.createDB) || (builtins.any (db: db == "immich") config.services.postgresql.ensureDatabases);
|
||||||
(lib.mkIf config.host.postgres.enable {
|
message = "Immich built-in database creation failed - expected 'immich' in ensureDatabases but got: ${builtins.toString config.services.postgresql.ensureDatabases}";
|
||||||
host = {
|
}
|
||||||
postgres = {
|
{
|
||||||
extraUsers = {
|
assertion = !(config.services.immich.database.enable && config.services.immich.database.createDB) || (builtins.any (user: user.name == "immich") config.services.postgresql.ensureUsers);
|
||||||
${config.services.immich.database.user} = {
|
message = "Immich built-in user creation failed - expected user 'immich' in ensureUsers but got: ${builtins.toString (builtins.map (u: u.name) config.services.postgresql.ensureUsers)}";
|
||||||
isClient = true;
|
}
|
||||||
};
|
];
|
||||||
};
|
|
||||||
};
|
# Note: Immich has built-in database creation via services.immich.database.createDB we only add the systemd dependency
|
||||||
};
|
|
||||||
})
|
systemd.services.immich-server = lib.mkIf config.services.immich.database.enable {
|
||||||
]);
|
requires = [
|
||||||
|
config.systemd.services.postgresql.name
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,32 +3,46 @@
|
||||||
config,
|
config,
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
config = lib.mkIf config.services.panoramax.enable (lib.mkMerge [
|
options.services.panoramax = {
|
||||||
{
|
database = {
|
||||||
host = {
|
postgres = {
|
||||||
postgres = {
|
enable = lib.mkOption {
|
||||||
enable = true;
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Use PostgreSQL instead of SQLite";
|
||||||
|
};
|
||||||
|
user = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "panoramax";
|
||||||
|
description = "Database user name";
|
||||||
|
};
|
||||||
|
database = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "panoramax";
|
||||||
|
description = "Database name";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
(
|
};
|
||||||
lib.mkIf config.host.postgres.enable {
|
|
||||||
host = {
|
config = lib.mkIf config.services.panoramax.enable {
|
||||||
postgres = {
|
assertions = [
|
||||||
extraUsers = {
|
{
|
||||||
${config.services.panoramax.database.user} = {
|
assertion = !config.services.panoramax.database.postgres.enable || config.services.postgresql.enable;
|
||||||
isClient = true;
|
message = "PostgreSQL must be enabled when using postgres database for Panoramax";
|
||||||
createUser = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
extraDatabases = {
|
|
||||||
${config.services.panoramax.database.name} = {
|
|
||||||
name = config.services.panoramax.database.user;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
)
|
];
|
||||||
]);
|
|
||||||
|
services.postgresql.databases.panoramax = lib.mkIf config.services.panoramax.database.postgres.enable {
|
||||||
|
enable = true;
|
||||||
|
user = config.services.panoramax.database.postgres.user;
|
||||||
|
database = config.services.panoramax.database.postgres.database;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.panoramax = lib.mkIf config.services.panoramax.database.postgres.enable {
|
||||||
|
requires = [
|
||||||
|
config.systemd.services.postgresql.name
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,32 +3,28 @@
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
config = lib.mkIf config.services.paperless.enable (lib.mkMerge [
|
config = lib.mkIf config.services.paperless.enable {
|
||||||
{
|
assertions = [
|
||||||
host = {
|
{
|
||||||
postgres = {
|
assertion = !config.services.paperless.database.createLocally || config.services.postgresql.enable;
|
||||||
enable = true;
|
message = "PostgreSQL must be enabled when using local postgres database for Paperless";
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(
|
|
||||||
lib.mkIf config.host.postgres.enable {
|
|
||||||
host = {
|
|
||||||
postgres = {
|
|
||||||
extraUsers = {
|
|
||||||
${config.services.paperless.database.user} = {
|
|
||||||
isClient = true;
|
|
||||||
createUser = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
extraDatabases = {
|
|
||||||
${config.services.paperless.database.user} = {
|
|
||||||
name = config.services.paperless.database.user;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
)
|
{
|
||||||
]);
|
assertion = !config.services.paperless.database.createLocally || (builtins.any (db: db == "paperless") config.services.postgresql.ensureDatabases);
|
||||||
|
message = "Paperless built-in database creation failed - expected 'paperless' in ensureDatabases but got: ${builtins.toString config.services.postgresql.ensureDatabases}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = !config.services.paperless.database.createLocally || (builtins.any (user: user.name == "paperless") config.services.postgresql.ensureUsers);
|
||||||
|
message = "Paperless built-in user creation failed - expected user 'paperless' in ensureUsers but got: ${builtins.toString (builtins.map (u: u.name) config.services.postgresql.ensureUsers)}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
services.paperless.database.createLocally = lib.mkDefault true;
|
||||||
|
|
||||||
|
systemd.services.paperless-scheduler = lib.mkIf config.services.paperless.database.createLocally {
|
||||||
|
requires = [
|
||||||
|
config.systemd.services.postgresql.name
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
}: let
|
}: let
|
||||||
dataDir = "/var/lib/postgresql/16";
|
dataDir = "/var/lib/postgresql/16";
|
||||||
in {
|
in {
|
||||||
config = lib.mkIf (config.host.postgres.enable && config.host.impermanence.enable) {
|
config = lib.mkIf (config.services.postgresql.enable && config.host.impermanence.enable) {
|
||||||
assertions = [
|
assertions = [
|
||||||
{
|
{
|
||||||
assertion = config.services.postgresql.dataDir == dataDir;
|
assertion = config.services.postgresql.dataDir == dataDir;
|
||||||
|
|
|
||||||
|
|
@ -4,70 +4,94 @@
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
adminUsers = lib.lists.filter (user: user.isAdmin) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers);
|
enabledDatabases = lib.filterAttrs (_: db: db.enable) config.services.postgresql.databases;
|
||||||
clientUsers = lib.lists.filter (user: user.isClient) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers);
|
extraDatabasesList = config.services.postgresql.extraDatabases;
|
||||||
createUsers = lib.lists.filter (user: user.createUser) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers);
|
|
||||||
createDatabases = lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraDatabases;
|
serviceDatabaseUsers = lib.mapAttrsToList (_: db: {
|
||||||
|
name = db.user;
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
}) (lib.filterAttrs (_: db: db.ensureUser) enabledDatabases);
|
||||||
|
|
||||||
|
extraDatabaseUsers =
|
||||||
|
builtins.map (dbName: {
|
||||||
|
name = dbName;
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
})
|
||||||
|
extraDatabasesList;
|
||||||
|
|
||||||
|
serviceDatabases = lib.mapAttrsToList (_: db: db.database) enabledDatabases;
|
||||||
|
extraDatabaseNames = extraDatabasesList;
|
||||||
|
|
||||||
|
serviceUserMappings = lib.mapAttrsToList (_: db: "user_map ${db.user} ${db.user}") enabledDatabases;
|
||||||
|
extraUserMappings = builtins.map (dbName: "user_map ${dbName} ${dbName}") extraDatabasesList;
|
||||||
|
|
||||||
|
builtinServiceMappings = let
|
||||||
|
forgejoMapping = lib.optional (config.services.forgejo.enable && config.services.forgejo.database.type == "postgres") "user_map forgejo forgejo";
|
||||||
|
immichMapping = lib.optional (config.services.immich.enable && config.services.immich.database.enable) "user_map immich immich";
|
||||||
|
paperlessMapping = lib.optional (config.services.paperless.enable && config.services.paperless.database.createLocally) "user_map paperless paperless";
|
||||||
|
in
|
||||||
|
forgejoMapping ++ immichMapping ++ paperlessMapping;
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
host.postgres = {
|
services.postgresql = {
|
||||||
enable = lib.mkEnableOption "enable postgres";
|
databases = lib.mkOption {
|
||||||
extraUsers = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
|
type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
|
||||||
options = {
|
options = {
|
||||||
name = lib.mkOption {
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Whether to create this database and user";
|
||||||
|
};
|
||||||
|
user = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = name;
|
default = name;
|
||||||
|
description = "Database user name";
|
||||||
};
|
};
|
||||||
isAdmin = lib.mkOption {
|
database = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.str;
|
||||||
default = false;
|
default = name;
|
||||||
|
description = "Database name";
|
||||||
};
|
};
|
||||||
isClient = lib.mkOption {
|
ensureUser = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = true;
|
||||||
};
|
description = "Whether to ensure the user exists";
|
||||||
createUser = lib.mkOption {
|
|
||||||
type = lib.types.bool;
|
|
||||||
default = false;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
default = {};
|
default = {};
|
||||||
|
description = "Databases to create for services";
|
||||||
};
|
};
|
||||||
|
|
||||||
extraDatabases = lib.mkOption {
|
extraDatabases = lib.mkOption {
|
||||||
type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
|
type = lib.types.listOf lib.types.str;
|
||||||
options = {
|
default = [];
|
||||||
name = lib.mkOption {
|
description = "Additional databases to create (user name will match database name)";
|
||||||
type = lib.types.str;
|
example = ["custom_db" "test_db"];
|
||||||
default = name;
|
};
|
||||||
};
|
|
||||||
};
|
adminUsers = lib.mkOption {
|
||||||
}));
|
type = lib.types.listOf lib.types.str;
|
||||||
default = {};
|
default = [];
|
||||||
|
description = "System users who should have PostgreSQL superuser access";
|
||||||
|
example = ["leyla" "admin"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf config.host.postgres.enable {
|
config = lib.mkIf config.services.postgresql.enable {
|
||||||
services = {
|
services = {
|
||||||
postgresql = {
|
postgresql = {
|
||||||
enable = true;
|
|
||||||
package = pkgs.postgresql_16;
|
package = pkgs.postgresql_16;
|
||||||
|
|
||||||
ensureUsers =
|
ensureUsers =
|
||||||
[
|
[
|
||||||
{
|
{name = "postgres";}
|
||||||
name = "postgres";
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
++ (
|
++ serviceDatabaseUsers ++ extraDatabaseUsers;
|
||||||
builtins.map (user: {
|
|
||||||
name = user.name;
|
ensureDatabases = serviceDatabases ++ extraDatabaseNames;
|
||||||
ensureDBOwnership = true;
|
|
||||||
})
|
|
||||||
createUsers
|
|
||||||
);
|
|
||||||
ensureDatabases = builtins.map (database: database.name) createDatabases;
|
|
||||||
identMap =
|
identMap =
|
||||||
''
|
''
|
||||||
# ArbitraryMapName systemUser DBUser
|
# ArbitraryMapName systemUser DBUser
|
||||||
|
|
@ -77,16 +101,16 @@ in {
|
||||||
superuser_map postgres postgres
|
superuser_map postgres postgres
|
||||||
''
|
''
|
||||||
+ (
|
+ (
|
||||||
lib.strings.concatLines (builtins.map (user: "superuser_map ${user.name} postgres") adminUsers)
|
lib.strings.concatLines (builtins.map (user: "superuser_map ${user} postgres") config.services.postgresql.adminUsers)
|
||||||
)
|
)
|
||||||
+ ''
|
+ ''
|
||||||
|
|
||||||
# Client Users
|
# Client Users
|
||||||
''
|
''
|
||||||
+ (
|
+ (
|
||||||
lib.strings.concatLines (builtins.map (user: "user_map ${user.name} ${user.name}") clientUsers)
|
lib.strings.concatLines (serviceUserMappings ++ extraUserMappings ++ builtinServiceMappings)
|
||||||
);
|
);
|
||||||
# configuration here lets users access the db that matches their name and lets user postgres access everything
|
|
||||||
authentication = pkgs.lib.mkOverride 10 ''
|
authentication = pkgs.lib.mkOverride 10 ''
|
||||||
# type database DBuser origin-address auth-method optional_ident_map
|
# type database DBuser origin-address auth-method optional_ident_map
|
||||||
local all postgres peer map=superuser_map
|
local all postgres peer map=superuser_map
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue