forked from jan-leila/nix-config
		
	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"]; | ||||
|       }; | ||||
|     }; | ||||
|     postgres = { | ||||
|       extraUsers = { | ||||
|         leyla = { | ||||
|           isAdmin = true; | ||||
|         }; | ||||
|       }; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   systemd.network = { | ||||
|  | @ -220,6 +213,12 @@ | |||
|   }; | ||||
| 
 | ||||
|   services = { | ||||
|     # PostgreSQL database server | ||||
|     postgresql = { | ||||
|       enable = true; | ||||
|       adminUsers = ["leyla"]; | ||||
|     }; | ||||
| 
 | ||||
|     # temp enable desktop environment for setup | ||||
|     # Enable the X11 windowing system. | ||||
|     xserver.enable = true; | ||||
|  | @ -327,7 +326,7 @@ | |||
|       enable = true; | ||||
|       domain = "home.jan-leila.com"; | ||||
|       openFirewall = true; | ||||
|       database = "postgres"; | ||||
|       postgres.enable = true; | ||||
| 
 | ||||
|       extensions = { | ||||
|         sonos.enable = true; | ||||
|  |  | |||
|  | @ -2,40 +2,31 @@ | |||
|   lib, | ||||
|   config, | ||||
|   ... | ||||
| }: { | ||||
|   config = lib.mkIf config.services.forgejo.enable ( | ||||
|     lib.mkMerge [ | ||||
|       { | ||||
|         host = { | ||||
|           postgres = { | ||||
|             enable = true; | ||||
|           }; | ||||
|         }; | ||||
| 
 | ||||
| }: let | ||||
|   usingPostgres = config.services.forgejo.database.type == "postgres"; | ||||
| in { | ||||
|   config = lib.mkIf config.services.forgejo.enable { | ||||
|     assertions = [ | ||||
|       { | ||||
|             assertion = config.services.forgejo.settings.database.DB_TYPE == "postgres"; | ||||
|             message = "Forgejo database type must be postgres"; | ||||
|         assertion = !usingPostgres || config.services.postgresql.enable; | ||||
|         message = "PostgreSQL must be enabled when Forgejo database type is postgres"; | ||||
|       } | ||||
|       { | ||||
|         assertion = !(usingPostgres && config.services.forgejo.database.createDatabase) || (builtins.any (db: db == "forgejo") config.services.postgresql.ensureDatabases); | ||||
|         message = "Forgejo built-in database creation failed - expected 'forgejo' in ensureDatabases but got: ${builtins.toString config.services.postgresql.ensureDatabases}"; | ||||
|       } | ||||
|       { | ||||
|         assertion = !(usingPostgres && config.services.forgejo.database.createDatabase) || (builtins.any (user: user.name == "forgejo") config.services.postgresql.ensureUsers); | ||||
|         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)}"; | ||||
|       } | ||||
|     ]; | ||||
|       } | ||||
|       (lib.mkIf config.host.postgres.enable { | ||||
|         host = { | ||||
|           postgres = { | ||||
|             extraUsers = { | ||||
|               forgejo = { | ||||
|                 isClient = true; | ||||
|                 createUser = true; | ||||
|               }; | ||||
|             }; | ||||
|             extraDatabases = { | ||||
|               forgejo = { | ||||
|                 name = "forgejo"; | ||||
|               }; | ||||
|             }; | ||||
|           }; | ||||
|         }; | ||||
|       }) | ||||
|     ] | ||||
|   ); | ||||
| 
 | ||||
|     services.forgejo.database.createDatabase = lib.mkDefault usingPostgres; | ||||
| 
 | ||||
|     systemd.services.forgejo = lib.mkIf usingPostgres { | ||||
|       requires = [ | ||||
|         config.systemd.services.postgresql.name | ||||
|       ]; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
|  |  | |||
|  | @ -2,55 +2,52 @@ | |||
|   lib, | ||||
|   config, | ||||
|   ... | ||||
| }: let | ||||
|   dbUser = "hass"; | ||||
| in { | ||||
|   config = lib.mkIf config.services.home-assistant.enable ( | ||||
|     lib.mkMerge [ | ||||
|       { | ||||
|         host = { | ||||
| }: { | ||||
|   options.services.home-assistant = { | ||||
|     postgres = { | ||||
|             enable = true; | ||||
|       enable = lib.mkOption { | ||||
|         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 = [ | ||||
|       { | ||||
|             assertion = config.services.home-assistant.database == "postgres"; | ||||
|             message = "Home Assistant database type must be postgres"; | ||||
|         assertion = !config.services.home-assistant.postgres.enable || config.services.postgresql.enable; | ||||
|         message = "PostgreSQL must be enabled when using postgres database for Home Assistant"; | ||||
|       } | ||||
|     ]; | ||||
|       } | ||||
|       (lib.mkIf config.host.postgres.enable { | ||||
|         host = { | ||||
|           postgres = { | ||||
|             extraUsers = { | ||||
|               ${dbUser} = { | ||||
|                 isClient = true; | ||||
|                 createUser = true; | ||||
|               }; | ||||
|             }; | ||||
|             extraDatabases = { | ||||
|               ${dbUser} = { | ||||
|                 name = dbUser; | ||||
|               }; | ||||
|             }; | ||||
|           }; | ||||
| 
 | ||||
|     services.postgresql.databases.home-assistant = lib.mkIf config.services.home-assistant.postgres.enable { | ||||
|       enable = true; | ||||
|       user = config.services.home-assistant.postgres.user; | ||||
|       database = config.services.home-assistant.postgres.database; | ||||
|     }; | ||||
| 
 | ||||
|         services.home-assistant = { | ||||
|     services.home-assistant = lib.mkIf config.services.home-assistant.postgres.enable { | ||||
|       extraPackages = python3Packages: | ||||
|         with python3Packages; [ | ||||
|           psycopg2 | ||||
|         ]; | ||||
|     }; | ||||
| 
 | ||||
|         systemd.services.home-assistant = { | ||||
|     systemd.services.home-assistant = lib.mkIf config.services.home-assistant.postgres.enable { | ||||
|       requires = [ | ||||
|         config.systemd.services.postgresql.name | ||||
|       ]; | ||||
|     }; | ||||
|       }) | ||||
|     ] | ||||
|   ); | ||||
|   }; | ||||
| } | ||||
|  |  | |||
|  | @ -3,24 +3,28 @@ | |||
|   config, | ||||
|   ... | ||||
| }: { | ||||
|   config = lib.mkIf config.services.immich.enable (lib.mkMerge [ | ||||
|   config = lib.mkIf config.services.immich.enable { | ||||
|     assertions = [ | ||||
|       { | ||||
|       host = { | ||||
|         postgres = { | ||||
|           enable = true; | ||||
|         assertion = !config.services.immich.database.enable || config.services.postgresql.enable; | ||||
|         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); | ||||
|         message = "Immich built-in database creation failed - expected 'immich' in ensureDatabases but got: ${builtins.toString config.services.postgresql.ensureDatabases}"; | ||||
|       } | ||||
|       { | ||||
|         assertion = !(config.services.immich.database.enable && config.services.immich.database.createDB) || (builtins.any (user: user.name == "immich") config.services.postgresql.ensureUsers); | ||||
|         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)}"; | ||||
|       } | ||||
|     ]; | ||||
| 
 | ||||
|     # 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 | ||||
|       ]; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
|     (lib.mkIf config.host.postgres.enable { | ||||
|       host = { | ||||
|         postgres = { | ||||
|           extraUsers = { | ||||
|             ${config.services.immich.database.user} = { | ||||
|               isClient = true; | ||||
|             }; | ||||
|           }; | ||||
|         }; | ||||
|       }; | ||||
|     }) | ||||
|   ]); | ||||
| } | ||||
|  |  | |||
|  | @ -3,32 +3,46 @@ | |||
|   config, | ||||
|   ... | ||||
| }: { | ||||
|   config = lib.mkIf config.services.panoramax.enable (lib.mkMerge [ | ||||
|   options.services.panoramax = { | ||||
|     database = { | ||||
|       postgres = { | ||||
|         enable = lib.mkOption { | ||||
|           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"; | ||||
|         }; | ||||
|       }; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   config = lib.mkIf config.services.panoramax.enable { | ||||
|     assertions = [ | ||||
|       { | ||||
|       host = { | ||||
|         postgres = { | ||||
|         assertion = !config.services.panoramax.database.postgres.enable || config.services.postgresql.enable; | ||||
|         message = "PostgreSQL must be enabled when using postgres database for Panoramax"; | ||||
|       } | ||||
|     ]; | ||||
| 
 | ||||
|     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 | ||||
|       ]; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
|     ( | ||||
|       lib.mkIf config.host.postgres.enable { | ||||
|         host = { | ||||
|           postgres = { | ||||
|             extraUsers = { | ||||
|               ${config.services.panoramax.database.user} = { | ||||
|                 isClient = true; | ||||
|                 createUser = true; | ||||
|               }; | ||||
|             }; | ||||
|             extraDatabases = { | ||||
|               ${config.services.panoramax.database.name} = { | ||||
|                 name = config.services.panoramax.database.user; | ||||
|               }; | ||||
|             }; | ||||
|           }; | ||||
|         }; | ||||
|       } | ||||
|     ) | ||||
|   ]); | ||||
| } | ||||
|  |  | |||
|  | @ -3,32 +3,28 @@ | |||
|   lib, | ||||
|   ... | ||||
| }: { | ||||
|   config = lib.mkIf config.services.paperless.enable (lib.mkMerge [ | ||||
|   config = lib.mkIf config.services.paperless.enable { | ||||
|     assertions = [ | ||||
|       { | ||||
|       host = { | ||||
|         postgres = { | ||||
|           enable = true; | ||||
|         assertion = !config.services.paperless.database.createLocally || config.services.postgresql.enable; | ||||
|         message = "PostgreSQL must be enabled when using local postgres database for Paperless"; | ||||
|       } | ||||
|       { | ||||
|         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 | ||||
|       ]; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
|     ( | ||||
|       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; | ||||
|               }; | ||||
|             }; | ||||
|           }; | ||||
|         }; | ||||
|       } | ||||
|     ) | ||||
|   ]); | ||||
| } | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
| }: let | ||||
|   dataDir = "/var/lib/postgresql/16"; | ||||
| in { | ||||
|   config = lib.mkIf (config.host.postgres.enable && config.host.impermanence.enable) { | ||||
|   config = lib.mkIf (config.services.postgresql.enable && config.host.impermanence.enable) { | ||||
|     assertions = [ | ||||
|       { | ||||
|         assertion = config.services.postgresql.dataDir == dataDir; | ||||
|  |  | |||
|  | @ -4,70 +4,94 @@ | |||
|   pkgs, | ||||
|   ... | ||||
| }: let | ||||
|   adminUsers = lib.lists.filter (user: user.isAdmin) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); | ||||
|   clientUsers = lib.lists.filter (user: user.isClient) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); | ||||
|   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; | ||||
|   enabledDatabases = lib.filterAttrs (_: db: db.enable) config.services.postgresql.databases; | ||||
|   extraDatabasesList = config.services.postgresql.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 { | ||||
|   options = { | ||||
|     host.postgres = { | ||||
|       enable = lib.mkEnableOption "enable postgres"; | ||||
|       extraUsers = lib.mkOption { | ||||
|     services.postgresql = { | ||||
|       databases = lib.mkOption { | ||||
|         type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { | ||||
|           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; | ||||
|               default = name; | ||||
|               description = "Database user name"; | ||||
|             }; | ||||
|             isAdmin = lib.mkOption { | ||||
|               type = lib.types.bool; | ||||
|               default = false; | ||||
|             database = lib.mkOption { | ||||
|               type = lib.types.str; | ||||
|               default = name; | ||||
|               description = "Database name"; | ||||
|             }; | ||||
|             isClient = lib.mkOption { | ||||
|             ensureUser = lib.mkOption { | ||||
|               type = lib.types.bool; | ||||
|               default = false; | ||||
|             }; | ||||
|             createUser = lib.mkOption { | ||||
|               type = lib.types.bool; | ||||
|               default = false; | ||||
|               default = true; | ||||
|               description = "Whether to ensure the user exists"; | ||||
|             }; | ||||
|           }; | ||||
|         })); | ||||
|         default = {}; | ||||
|         description = "Databases to create for services"; | ||||
|       }; | ||||
| 
 | ||||
|       extraDatabases = lib.mkOption { | ||||
|         type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { | ||||
|           options = { | ||||
|             name = lib.mkOption { | ||||
|               type = lib.types.str; | ||||
|               default = name; | ||||
|         type = lib.types.listOf lib.types.str; | ||||
|         default = []; | ||||
|         description = "Additional databases to create (user name will match database name)"; | ||||
|         example = ["custom_db" "test_db"]; | ||||
|       }; | ||||
|           }; | ||||
|         })); | ||||
|         default = {}; | ||||
| 
 | ||||
|       adminUsers = lib.mkOption { | ||||
|         type = lib.types.listOf lib.types.str; | ||||
|         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 = { | ||||
|       postgresql = { | ||||
|         enable = true; | ||||
|         package = pkgs.postgresql_16; | ||||
| 
 | ||||
|         ensureUsers = | ||||
|           [ | ||||
|             { | ||||
|               name = "postgres"; | ||||
|             } | ||||
|             {name = "postgres";} | ||||
|           ] | ||||
|           ++ ( | ||||
|             builtins.map (user: { | ||||
|               name = user.name; | ||||
|               ensureDBOwnership = true; | ||||
|             }) | ||||
|             createUsers | ||||
|           ); | ||||
|         ensureDatabases = builtins.map (database: database.name) createDatabases; | ||||
|           ++ serviceDatabaseUsers ++ extraDatabaseUsers; | ||||
| 
 | ||||
|         ensureDatabases = serviceDatabases ++ extraDatabaseNames; | ||||
| 
 | ||||
|         identMap = | ||||
|           '' | ||||
|             # ArbitraryMapName systemUser DBUser | ||||
|  | @ -77,16 +101,16 @@ in { | |||
|             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 | ||||
|           '' | ||||
|           + ( | ||||
|             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 '' | ||||
|           # type database DBuser    origin-address auth-method   optional_ident_map | ||||
|           local  all      postgres                 peer          map=superuser_map | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue