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