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