about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/services/databases/postgresql.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/services/databases/postgresql.nix')
-rw-r--r--nixpkgs/nixos/modules/services/databases/postgresql.nix279
1 files changed, 279 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/services/databases/postgresql.nix b/nixpkgs/nixos/modules/services/databases/postgresql.nix
new file mode 100644
index 000000000000..87b236dd5fd1
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/databases/postgresql.nix
@@ -0,0 +1,279 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.postgresql;
+
+  # see description of extraPlugins
+  postgresqlAndPlugins = pg:
+    if cfg.extraPlugins == [] then pg
+    else pkgs.buildEnv {
+      name = "postgresql-and-plugins-${(builtins.parseDrvName pg.name).version}";
+      paths = [ pg pg.lib ] ++ cfg.extraPlugins;
+      buildInputs = [ pkgs.makeWrapper ];
+      postBuild =
+        ''
+          mkdir -p $out/bin
+          rm $out/bin/{pg_config,postgres,pg_ctl}
+          cp --target-directory=$out/bin ${pg}/bin/{postgres,pg_config,pg_ctl}
+          wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib
+        '';
+    };
+
+  postgresql = postgresqlAndPlugins cfg.package;
+
+  # The main PostgreSQL configuration file.
+  configFile = pkgs.writeText "postgresql.conf"
+    ''
+      hba_file = '${pkgs.writeText "pg_hba.conf" cfg.authentication}'
+      ident_file = '${pkgs.writeText "pg_ident.conf" cfg.identMap}'
+      log_destination = 'stderr'
+      listen_addresses = '${if cfg.enableTCPIP then "*" else "localhost"}'
+      port = ${toString cfg.port}
+      ${cfg.extraConfig}
+    '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.postgresql = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to run PostgreSQL.
+        '';
+      };
+
+      package = mkOption {
+        type = types.package;
+        example = literalExample "pkgs.postgresql_9_6";
+        description = ''
+          PostgreSQL package to use.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 5432;
+        description = ''
+          The port on which PostgreSQL listens.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        example = "/var/lib/postgresql/9.6";
+        description = ''
+          Data directory for PostgreSQL.
+        '';
+      };
+
+      authentication = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Defines how users authenticate themselves to the server. By
+          default, "trust" access to local users will always be granted
+          along with any other custom options. If you do not want this,
+          set this option using "lib.mkForce" to override this
+          behaviour.
+        '';
+      };
+
+      identMap = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Defines the mapping from system users to database users.
+        '';
+      };
+
+      initialScript = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = ''
+          A file containing SQL statements to execute on first startup.
+        '';
+      };
+
+      enableTCPIP = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether PostgreSQL should listen on all network interfaces.
+          If disabled, the database can only be accessed via its Unix
+          domain socket or via TCP connections to localhost.
+        '';
+      };
+
+      extraPlugins = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        example = literalExample "[ (pkgs.postgis.override { postgresql = pkgs.postgresql_9_4; }) ]";
+        description = ''
+          When this list contains elements a new store path is created.
+          PostgreSQL and the elements are symlinked into it. Then pg_config,
+          postgres and pg_ctl are copied to make them use the new
+          $out/lib directory as pkglibdir. This makes it possible to use postgis
+          without patching the .sql files which reference $libdir/postgis-1.5.
+        '';
+        # Note: the duplication of executables is about 4MB size.
+        # So a nicer solution was patching postgresql to allow setting the
+        # libdir explicitely.
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Additional text to be appended to <filename>postgresql.conf</filename>.";
+      };
+
+      recoveryConfig = mkOption {
+        type = types.nullOr types.lines;
+        default = null;
+        description = ''
+          Contents of the <filename>recovery.conf</filename> file.
+        '';
+      };
+      superUser = mkOption {
+        type = types.str;
+        default= if versionAtLeast config.system.stateVersion "17.09" then "postgres" else "root";
+        internal = true;
+        description = ''
+          NixOS traditionally used 'root' as superuser, most other distros use 'postgres'.
+          From 17.09 we also try to follow this standard. Internal since changing this value
+          would lead to breakage while setting up databases.
+        '';
+        };
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.postgresql.enable {
+
+    services.postgresql.package =
+      # Note: when changing the default, make it conditional on
+      # ‘system.stateVersion’ to maintain compatibility with existing
+      # systems!
+      mkDefault (if versionAtLeast config.system.stateVersion "17.09" then pkgs.postgresql_9_6
+            else if versionAtLeast config.system.stateVersion "16.03" then pkgs.postgresql_9_5
+            else pkgs.postgresql_9_4);
+
+    services.postgresql.dataDir =
+      mkDefault (if versionAtLeast config.system.stateVersion "17.09" then "/var/lib/postgresql/${config.services.postgresql.package.psqlSchema}"
+                 else "/var/db/postgresql");
+
+    services.postgresql.authentication = mkAfter
+      ''
+        # Generated file; do not edit!
+        local all all              ident
+        host  all all 127.0.0.1/32 md5
+        host  all all ::1/128      md5
+      '';
+
+    users.users.postgres =
+      { name = "postgres";
+        uid = config.ids.uids.postgres;
+        group = "postgres";
+        description = "PostgreSQL server user";
+        home = "${cfg.dataDir}";
+        useDefaultShell = true;
+      };
+
+    users.groups.postgres.gid = config.ids.gids.postgres;
+
+    environment.systemPackages = [ postgresql ];
+
+    systemd.services.postgresql =
+      { description = "PostgreSQL Server";
+
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
+
+        environment.PGDATA = cfg.dataDir;
+
+        path = [ postgresql ];
+
+        preStart =
+          ''
+            # Create data directory.
+            if ! test -e ${cfg.dataDir}/PG_VERSION; then
+              mkdir -m 0700 -p ${cfg.dataDir}
+              rm -f ${cfg.dataDir}/*.conf
+              chown -R postgres:postgres ${cfg.dataDir}
+            fi
+          ''; # */
+
+        script =
+          ''
+            # Initialise the database.
+            if ! test -e ${cfg.dataDir}/PG_VERSION; then
+              initdb -U ${cfg.superUser}
+              # See postStart!
+              touch "${cfg.dataDir}/.first_startup"
+            fi
+            ln -sfn "${configFile}" "${cfg.dataDir}/postgresql.conf"
+            ${optionalString (cfg.recoveryConfig != null) ''
+              ln -sfn "${pkgs.writeText "recovery.conf" cfg.recoveryConfig}" \
+                "${cfg.dataDir}/recovery.conf"
+            ''}
+
+             exec postgres
+          '';
+
+        serviceConfig =
+          { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+            User = "postgres";
+            Group = "postgres";
+            PermissionsStartOnly = true;
+            RuntimeDirectory = "postgresql";
+            Type = if lib.versionAtLeast cfg.package.version "9.6"
+                   then "notify"
+                   else "simple";
+
+            # Shut down Postgres using SIGINT ("Fast Shutdown mode").  See
+            # http://www.postgresql.org/docs/current/static/server-shutdown.html
+            KillSignal = "SIGINT";
+            KillMode = "mixed";
+
+            # Give Postgres a decent amount of time to clean up after
+            # receiving systemd's SIGINT.
+            TimeoutSec = 120;
+          };
+
+        # Wait for PostgreSQL to be ready to accept connections.
+        postStart =
+          ''
+            while ! ${pkgs.sudo}/bin/sudo -u ${cfg.superUser} psql --port=${toString cfg.port} -d postgres -c "" 2> /dev/null; do
+                if ! kill -0 "$MAINPID"; then exit 1; fi
+                sleep 0.1
+            done
+
+            if test -e "${cfg.dataDir}/.first_startup"; then
+              ${optionalString (cfg.initialScript != null) ''
+                ${pkgs.sudo}/bin/sudo -u ${cfg.superUser} psql -f "${cfg.initialScript}" --port=${toString cfg.port} -d postgres
+              ''}
+              rm -f "${cfg.dataDir}/.first_startup"
+            fi
+          '';
+
+        unitConfig.RequiresMountsFor = "${cfg.dataDir}";
+      };
+
+  };
+
+  meta.doc = ./postgresql.xml;
+  meta.maintainers = with lib.maintainers; [ thoughtpolice ];
+}