diff --git a/nix/postgres.nix b/nix/postgres.nix index e3cbdb7..435ff2f 100644 --- a/nix/postgres.nix +++ b/nix/postgres.nix @@ -44,6 +44,67 @@ in default = "./data/${config.name}"; description = "The DB data directory"; }; + + hbaConf = + let + hbaConfSubmodule = lib.types.submodule { + options = { + type = lib.mkOption { type = lib.types.str; }; + database = lib.mkOption { type = lib.types.str; }; + user = lib.mkOption { type = lib.types.str; }; + address = lib.mkOption { type = lib.types.str; }; + method = lib.mkOption { type = lib.types.str; }; + }; + }; + in + lib.mkOption { + type = lib.types.listOf hbaConfSubmodule; + default = [ ]; + description = '' + A list of objects that represent the entries in the pg_hba.conf file. + + Each object has sub-options for type, database, user, address, and method. + + See the official PostgreSQL documentation for more information: + https://www.postgresql.org/docs/current/auth-pg-hba-conf.html + ''; + example = [ + { type = "local"; database = "all"; user = "postgres"; address = ""; method = "md5"; } + { type = "host"; database = "all"; user = "all"; address = "0.0.0.0/0"; method = "md5"; } + ]; + }; + hbaConfFile = + let + # Default pg_hba.conf entries + defaultHbaConf = [ + { type = "local"; database = "all"; user = "all"; address = ""; method = "trust"; } + { type = "host"; database = "all"; user = "all"; address = "127.0.0.1/32"; method = "trust"; } + { type = "host"; database = "all"; user = "all"; address = "::1/128"; method = "trust"; } + { type = "local"; database = "replication"; user = "all"; address = ""; method = "trust"; } + { type = "host"; database = "replication"; user = "all"; address = "127.0.0.1/32"; method = "trust"; } + { type = "host"; database = "replication"; user = "all"; address = "::1/128"; method = "trust"; } + ]; + + # Merge the default pg_hba.conf entries with the user-defined entries + hbaConf = defaultHbaConf ++ config.hbaConf; + + # Convert the pgHbaConf array to a string + hbaConfString = '' + # Generated by Nix + ${"# TYPE\tDATABASE\tUSER\tADDRESS\tMETHOD\n"} + ${lib.concatMapStrings (cnf: " ${cnf.type}\t${cnf.database}\t${cnf.user}\t${cnf.address}\t${cnf.method}\n") hbaConf} + ''; + in + lib.mkOption { + type = lib.types.package; + internal = true; + readOnly = true; + description = "The `pg_hba.conf` file."; + default = pkgs.runCommand "pg_hba.conf" { } '' + echo "${hbaConfString}" | ${pkgs.util-linux}/bin/column -t -s $'\t' > $out + ''; + }; + listen_addresses = lib.mkOption { type = lib.types.str; description = "Listen address"; @@ -77,32 +138,34 @@ in ''; }; - settings = lib.mkOption { - type = with lib.types; attrsOf (oneOf [ bool float int str ]); - default = { }; - description = '' - PostgreSQL configuration. Refer to - - for an overview of `postgresql.conf`. + settings = + lib.mkOption { + type = with lib.types; attrsOf (oneOf [ bool float int str ]); + default = { }; + description = '' + PostgreSQL configuration. Refer to + + for an overview of `postgresql.conf`. - String values will automatically be enclosed in single quotes. Single quotes will be - escaped with two single quotes as described by the upstream documentation linked above. - ''; - default = { - listen_addresses = config.listen_addresses; - port = config.port; - unix_socket_directories = lib.mkDefault config.dataDir; + String values will automatically be enclosed in single quotes. Single quotes will be + escaped with two single quotes as described by the upstream documentation linked above. + ''; + default = { + listen_addresses = config.listen_addresses; + port = config.port; + unix_socket_directories = lib.mkDefault config.dataDir; + hba_file = "${config.hbaConfFile}"; + }; + example = lib.literalExpression '' + { + log_connections = true; + log_statement = "all"; + logging_collector = true + log_disconnections = true + log_destination = lib.mkForce "syslog"; + } + ''; }; - example = lib.literalExpression '' - { - log_connections = true; - log_statement = "all"; - logging_collector = true - log_disconnections = true - log_destination = lib.mkForce "syslog"; - } - ''; - }; initialDatabases = lib.mkOption { type = types.listOf (types.submodule { diff --git a/nix/postgres_test.nix b/nix/postgres_test.nix index 67e8526..618fccb 100644 --- a/nix/postgres_test.nix +++ b/nix/postgres_test.nix @@ -1,13 +1,18 @@ -{ config, ... }: { +{ pkgs, config, ... }: { services.postgres = { enable = true; listen_addresses = "127.0.0.1"; }; - testScript = '' - process_compose.wait_until(lambda procs: - # TODO: Check for 'ready' - procs["postgres"]["status"] == "Running" - ) - machine.succeed("echo 'SELECT version();' | ${config.services.postgres.package}/bin/psql -h 127.0.0.1 -U tester") - ''; + testScript = + let + psql = "${config.services.postgres.package}/bin/psql"; + in + '' + process_compose.wait_until(lambda procs: + # TODO: Check for 'ready' + procs["postgres"]["status"] == "Running" + ) + machine.succeed("echo 'SELECT version();' | ${config.services.postgres.package}/bin/psql -h 127.0.0.1 -U tester") + machine.succeed("echo 'SHOW hba_file;' | ${psql} -h 127.0.0.1 -U tester | ${pkgs.gawk}/bin/awk 'NR==3' | ${pkgs.gnugrep}/bin/grep '^ /nix/store'") + ''; }