diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix index c8fdd89d0d8fb..a5c94afae643d 100644 --- a/nixos/modules/services/databases/postgresql.nix +++ b/nixos/modules/services/databases/postgresql.nix @@ -111,6 +111,25 @@ in ]; }; + ensureExtensions = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Ensures that the specified extensions exist. + Extensions will be created in the 'public' schema, thus making them automatically + availabe on the default search path. + + This option will never drop existing extensions, especially not when the value of this + option is changed. This means that extensions created once through this option or + otherwise have to be removed manually. + ''; + example = [ + "hstore" + "pgcrypto" + "pg_trgm" + ]; + }; + ensureUsers = mkOption { type = types.listOf (types.submodule { options = { @@ -344,6 +363,10 @@ in $PSQL -tAc 'GRANT ${permission} ON ${database} TO "${user.name}"' '') user.ensurePermissions)} '') cfg.ensureUsers} + '' + optionalString (cfg.ensureExtensions != []) '' + ${concatMapStrings (extension: '' + $PSQL -tAc "SELECT 1 FROM pg_available_extensions WHERE name = '${extension}' and installed_version is not null" | grep -q 1 || $PSQL -tAc 'CREATE EXTENSION "${extension}" SCHEMA public CASCADE' + '') cfg.ensureExtensions} ''; unitConfig.RequiresMountsFor = "${cfg.dataDir}"; diff --git a/nixos/tests/postgresql.nix b/nixos/tests/postgresql.nix index e71c38882881f..5e81fcaf63c49 100644 --- a/nixos/tests/postgresql.nix +++ b/nixos/tests/postgresql.nix @@ -31,6 +31,7 @@ let { services.postgresql.enable = true; services.postgresql.package = postgresql-package; + services.postgresql.ensureExtensions = [ "hstore" ]; services.postgresqlBackup.enable = true; services.postgresqlBackup.databases = optional (!backup-all) "postgres"; @@ -61,6 +62,12 @@ let machine.succeed(check_count("SELECT * FROM sth;", 5)) machine.fail(check_count("SELECT * FROM sth;", 4)) machine.succeed(check_count("SELECT xpath('/test/text()', doc) FROM xmltest;", 1)) + machine.succeed( + check_count( + "SELECT * FROM pg_available_extensions WHERE name = 'hstore' AND installed_version is not null", + 1, + ) + ) # Check backup service machine.succeed("systemctl start ${backupService}.service")