at 17.09-beta 8.3 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.postgresql; 8 9 # see description of extraPlugins 10 postgresqlAndPlugins = pg: 11 if cfg.extraPlugins == [] then pg 12 else pkgs.buildEnv { 13 name = "postgresql-and-plugins-${(builtins.parseDrvName pg.name).version}"; 14 paths = [ pg pg.lib ] ++ cfg.extraPlugins; 15 buildInputs = [ pkgs.makeWrapper ]; 16 postBuild = 17 '' 18 mkdir -p $out/bin 19 rm $out/bin/{pg_config,postgres,pg_ctl} 20 cp --target-directory=$out/bin ${pg}/bin/{postgres,pg_config,pg_ctl} 21 wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib 22 ''; 23 }; 24 25 postgresql = postgresqlAndPlugins cfg.package; 26 27 flags = optional cfg.enableTCPIP "-i"; 28 29 # The main PostgreSQL configuration file. 30 configFile = pkgs.writeText "postgresql.conf" 31 '' 32 hba_file = '${pkgs.writeText "pg_hba.conf" cfg.authentication}' 33 ident_file = '${pkgs.writeText "pg_ident.conf" cfg.identMap}' 34 log_destination = 'stderr' 35 port = ${toString cfg.port} 36 ${cfg.extraConfig} 37 ''; 38 39 pre84 = versionOlder (builtins.parseDrvName postgresql.name).version "8.4"; 40 41 # NixOS traditionally used `root` as superuser, most other distros use `postgres`. From 17.09 42 # we also try to follow this standard 43 superuser = (if versionAtLeast config.system.stateVersion "17.09" then "postgres" else "root"); 44 45in 46 47{ 48 49 ###### interface 50 51 options = { 52 53 services.postgresql = { 54 55 enable = mkOption { 56 type = types.bool; 57 default = false; 58 description = '' 59 Whether to run PostgreSQL. 60 ''; 61 }; 62 63 package = mkOption { 64 type = types.package; 65 example = literalExample "pkgs.postgresql92"; 66 description = '' 67 PostgreSQL package to use. 68 ''; 69 }; 70 71 port = mkOption { 72 type = types.int; 73 default = 5432; 74 description = '' 75 The port on which PostgreSQL listens. 76 ''; 77 }; 78 79 dataDir = mkOption { 80 type = types.path; 81 example = "/var/lib/postgresql/9.6"; 82 description = '' 83 Data directory for PostgreSQL. 84 ''; 85 }; 86 87 authentication = mkOption { 88 type = types.lines; 89 default = ""; 90 description = '' 91 Defines how users authenticate themselves to the server. By 92 default, "trust" access to local users will always be granted 93 along with any other custom options. If you do not want this, 94 set this option using "lib.mkForce" to override this 95 behaviour. 96 ''; 97 }; 98 99 identMap = mkOption { 100 type = types.lines; 101 default = ""; 102 description = '' 103 Defines the mapping from system users to database users. 104 ''; 105 }; 106 107 initialScript = mkOption { 108 type = types.nullOr types.path; 109 default = null; 110 description = '' 111 A file containing SQL statements to execute on first startup. 112 ''; 113 }; 114 115 enableTCPIP = mkOption { 116 type = types.bool; 117 default = false; 118 description = '' 119 Whether PostgreSQL should listen on all network interfaces. 120 If disabled, the database can only be accessed via its Unix 121 domain socket or via TCP connections to localhost. 122 ''; 123 }; 124 125 extraPlugins = mkOption { 126 type = types.listOf types.path; 127 default = []; 128 example = literalExample "[ (pkgs.postgis.override { postgresql = pkgs.postgresql94; }).v_2_1_4 ]"; 129 description = '' 130 When this list contains elements a new store path is created. 131 PostgreSQL and the elements are symlinked into it. Then pg_config, 132 postgres and pg_ctl are copied to make them use the new 133 $out/lib directory as pkglibdir. This makes it possible to use postgis 134 without patching the .sql files which reference $libdir/postgis-1.5. 135 ''; 136 # Note: the duplication of executables is about 4MB size. 137 # So a nicer solution was patching postgresql to allow setting the 138 # libdir explicitely. 139 }; 140 141 extraConfig = mkOption { 142 type = types.lines; 143 default = ""; 144 description = "Additional text to be appended to <filename>postgresql.conf</filename>."; 145 }; 146 147 recoveryConfig = mkOption { 148 type = types.nullOr types.lines; 149 default = null; 150 description = '' 151 Contents of the <filename>recovery.conf</filename> file. 152 ''; 153 }; 154 }; 155 156 }; 157 158 159 ###### implementation 160 161 config = mkIf config.services.postgresql.enable { 162 163 services.postgresql.package = 164 # Note: when changing the default, make it conditional on 165 # ‘system.stateVersion’ to maintain compatibility with existing 166 # systems! 167 mkDefault (if versionAtLeast config.system.stateVersion "17.09" then pkgs.postgresql96 168 else if versionAtLeast config.system.stateVersion "16.03" then pkgs.postgresql95 169 else pkgs.postgresql94); 170 171 services.postgresql.dataDir = 172 mkDefault (if versionAtLeast config.system.stateVersion "17.09" then "/var/lib/postgresql/${config.services.postgresql.package.psqlSchema}" 173 else "/var/db/postgresql"); 174 175 services.postgresql.authentication = mkAfter 176 '' 177 # Generated file; do not edit! 178 local all all ident ${optionalString pre84 "sameuser"} 179 host all all 127.0.0.1/32 md5 180 host all all ::1/128 md5 181 ''; 182 183 users.extraUsers.postgres = 184 { name = "postgres"; 185 uid = config.ids.uids.postgres; 186 group = "postgres"; 187 description = "PostgreSQL server user"; 188 }; 189 190 users.extraGroups.postgres.gid = config.ids.gids.postgres; 191 192 environment.systemPackages = [ postgresql ]; 193 194 systemd.services.postgresql = 195 { description = "PostgreSQL Server"; 196 197 wantedBy = [ "multi-user.target" ]; 198 after = [ "network.target" ]; 199 200 environment.PGDATA = cfg.dataDir; 201 202 path = [ postgresql ]; 203 204 preStart = 205 '' 206 # Create data directory. 207 if ! test -e ${cfg.dataDir}/PG_VERSION; then 208 mkdir -m 0700 -p ${cfg.dataDir} 209 rm -f ${cfg.dataDir}/*.conf 210 chown -R postgres:postgres ${cfg.dataDir} 211 fi 212 ''; # */ 213 214 script = 215 '' 216 # Initialise the database. 217 if ! test -e ${cfg.dataDir}/PG_VERSION; then 218 initdb -U ${superuser} 219 # See postStart! 220 touch "${cfg.dataDir}/.first_startup" 221 fi 222 ln -sfn "${configFile}" "${cfg.dataDir}/postgresql.conf" 223 ${optionalString (cfg.recoveryConfig != null) '' 224 ln -sfn "${pkgs.writeText "recovery.conf" cfg.recoveryConfig}" \ 225 "${cfg.dataDir}/recovery.conf" 226 ''} 227 228 exec postgres ${toString flags} 229 ''; 230 231 serviceConfig = 232 { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 233 User = "postgres"; 234 Group = "postgres"; 235 PermissionsStartOnly = true; 236 237 # Shut down Postgres using SIGINT ("Fast Shutdown mode"). See 238 # http://www.postgresql.org/docs/current/static/server-shutdown.html 239 KillSignal = "SIGINT"; 240 KillMode = "mixed"; 241 242 # Give Postgres a decent amount of time to clean up after 243 # receiving systemd's SIGINT. 244 TimeoutSec = 120; 245 }; 246 247 # Wait for PostgreSQL to be ready to accept connections. 248 postStart = 249 '' 250 while ! ${pkgs.sudo}/bin/sudo -u ${superuser} psql --port=${toString cfg.port} -d postgres -c "" 2> /dev/null; do 251 if ! kill -0 "$MAINPID"; then exit 1; fi 252 sleep 0.1 253 done 254 255 if test -e "${cfg.dataDir}/.first_startup"; then 256 ${optionalString (cfg.initialScript != null) '' 257 ${pkgs.sudo}/bin/sudo -u ${superuser} psql -f "${cfg.initialScript}" --port=${toString cfg.port} -d postgres 258 ''} 259 rm -f "${cfg.dataDir}/.first_startup" 260 fi 261 ''; 262 263 unitConfig.RequiresMountsFor = "${cfg.dataDir}"; 264 }; 265 266 }; 267 268 meta.doc = ./postgresql.xml; 269 270}