Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)

nixos/pgbouncer: init (#241578)

Co-authored-by: Marek Mahut <marek.mahut@gmail.com>

authored by 1000101 Marek Mahut and committed by GitHub f63d863f 7e1e290b

+703 -1
+3
nixos/doc/manual/release-notes/rl-2311.section.md
··· 24 24 25 25 - [Apache Guacamole](https://guacamole.apache.org/), a cross-platform, clientless remote desktop gateway. Available as [services.guacamole-server](#opt-services.guacamole-server.enable) and [services.guacamole-client](#opt-services.guacamole-client.enable) services. 26 26 27 + - [pgBouncer](https://www.pgbouncer.org), a PostgreSQL connection pooler. Available as [services.pgbouncer](#opt-services.pgbouncer.enable). 28 + 27 29 - [trust-dns](https://trust-dns.org/), a Rust based DNS server built to be safe and secure from the ground up. Available as [services.trust-dns](#opt-services.trust-dns.enable). 28 30 29 31 - [osquery](https://www.osquery.io/), a SQL powered operating system instrumentation, monitoring, and analytics. 30 32 31 33 - [ebusd](https://ebusd.eu), a daemon for handling communication with eBUS devices connected to a 2-wire bus system (“energy bus” used by numerous heating systems). Available as [services.ebusd](#opt-services.ebusd.enable). 34 + 32 35 33 36 ## Backward Incompatibilities {#sec-release-23.11-incompatibilities} 34 37
+1
nixos/modules/module-list.nix
··· 418 418 ./services/databases/neo4j.nix 419 419 ./services/databases/openldap.nix 420 420 ./services/databases/opentsdb.nix 421 + ./services/databases/pgbouncer.nix 421 422 ./services/databases/pgmanage.nix 422 423 ./services/databases/postgresql.nix 423 424 ./services/databases/redis.nix
+632
nixos/modules/services/databases/pgbouncer.nix
··· 1 + { lib, pkgs, config, ... } : 2 + 3 + with lib; 4 + 5 + let 6 + cfg = config.services.pgbouncer; 7 + 8 + confFile = pkgs.writeTextFile { 9 + name = "pgbouncer.ini"; 10 + text = '' 11 + [databases] 12 + ${concatStringsSep "\n" 13 + (mapAttrsToList (dbname : settings : "${dbname} = ${settings}") cfg.databases)} 14 + 15 + [users] 16 + ${concatStringsSep "\n" 17 + (mapAttrsToList (username : settings : "${username} = ${settings}") cfg.users)} 18 + 19 + [peers] 20 + ${concatStringsSep "\n" 21 + (mapAttrsToList (peerid : settings : "${peerid} = ${settings}") cfg.peers)} 22 + 23 + [pgbouncer] 24 + # general 25 + ${optionalString (cfg.ignoreStartupParameters != null) "ignore_startup_parameters = ${cfg.ignoreStartupParameters}"} 26 + listen_port = ${toString cfg.listenPort} 27 + ${optionalString (cfg.listenAddress != null) "listen_addr = ${cfg.listenAddress}"} 28 + pool_mode = ${cfg.poolMode} 29 + max_client_conn = ${toString cfg.maxClientConn} 30 + default_pool_size = ${toString cfg.defaultPoolSize} 31 + max_user_connections = ${toString cfg.maxUserConnections} 32 + max_db_connections = ${toString cfg.maxDbConnections} 33 + 34 + #auth 35 + auth_type = ${cfg.authType} 36 + ${optionalString (cfg.authHbaFile != null) "auth_hba_file = ${cfg.authHbaFile}"} 37 + ${optionalString (cfg.authFile != null) "auth_file = ${cfg.authFile}"} 38 + ${optionalString (cfg.authUser != null) "auth_user = ${cfg.authUser}"} 39 + ${optionalString (cfg.authQuery != null) "auth_query = ${cfg.authQuery}"} 40 + ${optionalString (cfg.authDbname != null) "auth_dbname = ${cfg.authDbname}"} 41 + 42 + # TLS 43 + ${optionalString (cfg.tls.client != null) '' 44 + client_tls_sslmode = ${cfg.tls.client.sslmode} 45 + client_tls_key_file = ${cfg.tls.client.keyFile} 46 + client_tls_cert_file = ${cfg.tls.client.certFile} 47 + client_tls_ca_file = ${cfg.tls.client.caFile} 48 + ''} 49 + ${optionalString (cfg.tls.server != null) '' 50 + server_tls_sslmode = ${cfg.tls.server.sslmode} 51 + server_tls_key_file = ${cfg.tls.server.keyFile} 52 + server_tls_cert_file = ${cfg.tls.server.certFile} 53 + server_tls_ca_file = ${cfg.tls.server.caFile} 54 + ''} 55 + 56 + # log 57 + ${optionalString (cfg.logFile != null) "logfile = ${cfg.homeDir}/${cfg.logFile}"} 58 + ${optionalString (cfg.syslog != null) '' 59 + syslog = ${if cfg.syslog.enable then "1" else "0"} 60 + syslog_ident = ${cfg.syslog.syslogIdent} 61 + syslog_facility = ${cfg.syslog.syslogFacility} 62 + ''} 63 + ${optionalString (cfg.verbose != null) "verbose = ${toString cfg.verbose}"} 64 + 65 + # console access 66 + ${optionalString (cfg.adminUsers != null) "admin_users = ${cfg.adminUsers}"} 67 + ${optionalString (cfg.statsUsers != null) "stats_users = ${cfg.statsUsers}"} 68 + 69 + # linux 70 + pidfile = /run/pgbouncer/pgbouncer.pid 71 + 72 + # extra 73 + ${cfg.extraConfig} 74 + ''; 75 + }; 76 + 77 + in { 78 + 79 + options.services.pgbouncer = { 80 + 81 + # NixOS settings 82 + 83 + enable = mkEnableOption (lib.mdDoc "PostgreSQL connection pooler"); 84 + 85 + package = mkOption { 86 + type = types.package; 87 + default = pkgs.pgbouncer; 88 + defaultText = literalExpression "pkgs.pgbouncer"; 89 + description = lib.mdDoc '' 90 + The pgbouncer package to use. 91 + ''; 92 + }; 93 + 94 + openFirewall = mkOption { 95 + type = types.bool; 96 + default = false; 97 + description = lib.mdDoc '' 98 + Whether to automatically open the specified TCP port in the firewall. 99 + ''; 100 + }; 101 + 102 + # Generic settings 103 + 104 + logFile = mkOption { 105 + type = types.nullOr types.str; 106 + default = "pgbouncer.log"; 107 + description = lib.mdDoc '' 108 + Specifies the log file. 109 + Either this or syslog has to be specified. 110 + ''; 111 + }; 112 + 113 + listenAddress = mkOption { 114 + type = types.nullOr types.commas; 115 + example = "*"; 116 + default = null; 117 + description = lib.mdDoc '' 118 + Specifies a list (comma-separated) of addresses where to listen for TCP connections. 119 + You may also use * meaning “listen on all addresses”. 120 + When not set, only Unix socket connections are accepted. 121 + 122 + Addresses can be specified numerically (IPv4/IPv6) or by name. 123 + ''; 124 + }; 125 + 126 + listenPort = mkOption { 127 + type = types.port; 128 + default = 6432; 129 + description = lib.mdDoc '' 130 + Which port to listen on. Applies to both TCP and Unix sockets. 131 + ''; 132 + }; 133 + 134 + poolMode = mkOption { 135 + type = types.enum [ "session" "transaction" "statement" ]; 136 + default = "session"; 137 + description = lib.mdDoc '' 138 + Specifies when a server connection can be reused by other clients. 139 + 140 + session 141 + Server is released back to pool after client disconnects. Default. 142 + transaction 143 + Server is released back to pool after transaction finishes. 144 + statement 145 + Server is released back to pool after query finishes. 146 + Transactions spanning multiple statements are disallowed in this mode. 147 + ''; 148 + }; 149 + 150 + maxClientConn = mkOption { 151 + type = types.int; 152 + default = 100; 153 + description = lib.mdDoc '' 154 + Maximum number of client connections allowed. 155 + 156 + When this setting is increased, then the file descriptor limits in the operating system 157 + might also have to be increased. Note that the number of file descriptors potentially 158 + used is more than maxClientConn. If each user connects under its own user name to the server, 159 + the theoretical maximum used is: 160 + maxClientConn + (max pool_size * total databases * total users) 161 + 162 + If a database user is specified in the connection string (all users connect under the same user name), 163 + the theoretical maximum is: 164 + maxClientConn + (max pool_size * total databases) 165 + 166 + The theoretical maximum should never be reached, unless somebody deliberately crafts a special load for it. 167 + Still, it means you should set the number of file descriptors to a safely high number. 168 + ''; 169 + }; 170 + 171 + defaultPoolSize = mkOption { 172 + type = types.int; 173 + default = 20; 174 + description = lib.mdDoc '' 175 + How many server connections to allow per user/database pair. 176 + Can be overridden in the per-database configuration. 177 + ''; 178 + }; 179 + 180 + maxDbConnections = mkOption { 181 + type = types.int; 182 + default = 0; 183 + description = lib.mdDoc '' 184 + Do not allow more than this many server connections per database (regardless of user). 185 + This considers the PgBouncer database that the client has connected to, 186 + not the PostgreSQL database of the outgoing connection. 187 + 188 + This can also be set per database in the [databases] section. 189 + 190 + Note that when you hit the limit, closing a client connection to one pool will 191 + not immediately allow a server connection to be established for another pool, 192 + because the server connection for the first pool is still open. 193 + Once the server connection closes (due to idle timeout), 194 + a new server connection will immediately be opened for the waiting pool. 195 + 196 + 0 = unlimited 197 + ''; 198 + }; 199 + 200 + maxUserConnections = mkOption { 201 + type = types.int; 202 + default = 0; 203 + description = lib.mdDoc '' 204 + Do not allow more than this many server connections per user (regardless of database). 205 + This considers the PgBouncer user that is associated with a pool, 206 + which is either the user specified for the server connection 207 + or in absence of that the user the client has connected as. 208 + 209 + This can also be set per user in the [users] section. 210 + 211 + Note that when you hit the limit, closing a client connection to one pool 212 + will not immediately allow a server connection to be established for another pool, 213 + because the server connection for the first pool is still open. 214 + Once the server connection closes (due to idle timeout), a new server connection 215 + will immediately be opened for the waiting pool. 216 + 217 + 0 = unlimited 218 + ''; 219 + }; 220 + 221 + ignoreStartupParameters = mkOption { 222 + type = types.nullOr types.commas; 223 + example = "extra_float_digits"; 224 + default = null; 225 + description = lib.mdDoc '' 226 + By default, PgBouncer allows only parameters it can keep track of in startup packets: 227 + client_encoding, datestyle, timezone and standard_conforming_strings. 228 + 229 + All others parameters will raise an error. 230 + To allow others parameters, they can be specified here, so that PgBouncer knows that 231 + they are handled by the admin and it can ignore them. 232 + 233 + If you need to specify multiple values, use a comma-separated list. 234 + 235 + IMPORTANT: When using prometheus-pgbouncer-exporter, you need: 236 + extra_float_digits 237 + <https://github.com/prometheus-community/pgbouncer_exporter#pgbouncer-configuration> 238 + ''; 239 + }; 240 + 241 + # Section [databases] 242 + databases = mkOption { 243 + type = types.attrsOf types.str; 244 + default = {}; 245 + example = { 246 + exampledb = "host=/run/postgresql/ port=5432 auth_user=exampleuser dbname=exampledb sslmode=require"; 247 + bardb = "host=localhost dbname=bazdb"; 248 + foodb = "host=host1.example.com port=5432"; 249 + }; 250 + description = lib.mdDoc '' 251 + Detailed information about PostgreSQL database definitions: 252 + <https://www.pgbouncer.org/config.html#section-databases> 253 + ''; 254 + }; 255 + 256 + # Section [users] 257 + users = mkOption { 258 + type = types.attrsOf types.str; 259 + default = {}; 260 + example = { 261 + user1 = "pool_mode=session"; 262 + }; 263 + description = lib.mdDoc '' 264 + Optional. 265 + 266 + Detailed information about PostgreSQL user definitions: 267 + <https://www.pgbouncer.org/config.html#section-users> 268 + ''; 269 + }; 270 + 271 + # Section [peers] 272 + peers = mkOption { 273 + type = types.attrsOf types.str; 274 + default = {}; 275 + example = { 276 + "1" = "host=host1.example.com"; 277 + "2" = "host=/tmp/pgbouncer-2 port=5555"; 278 + }; 279 + description = lib.mdDoc '' 280 + Optional. 281 + 282 + Detailed information about PostgreSQL database definitions: 283 + <https://www.pgbouncer.org/config.html#section-peers> 284 + ''; 285 + }; 286 + 287 + # Authentication settings 288 + authType = mkOption { 289 + type = types.enum [ "cert" "md5" "scram-sha-256" "plain" "trust" "any" "hba" "pam" ]; 290 + default = "md5"; 291 + description = lib.mdDoc '' 292 + How to authenticate users. 293 + 294 + cert 295 + Client must connect over TLS connection with a valid client certificate. 296 + The user name is then taken from the CommonName field from the certificate. 297 + md5 298 + Use MD5-based password check. This is the default authentication method. 299 + authFile may contain both MD5-encrypted and plain-text passwords. 300 + If md5 is configured and a user has a SCRAM secret, then SCRAM authentication is used automatically instead. 301 + scram-sha-256 302 + Use password check with SCRAM-SHA-256. authFile has to contain SCRAM secrets or plain-text passwords. 303 + plain 304 + The clear-text password is sent over the wire. Deprecated. 305 + trust 306 + No authentication is done. The user name must still exist in authFile. 307 + any 308 + Like the trust method, but the user name given is ignored. 309 + Requires that all databases are configured to log in as a specific user. 310 + Additionally, the console database allows any user to log in as admin. 311 + hba 312 + The actual authentication type is loaded from authHbaFile. 313 + This allows different authentication methods for different access paths, 314 + for example: connections over Unix socket use the peer auth method, connections over TCP must use TLS. 315 + pam 316 + PAM is used to authenticate users, authFile is ignored. 317 + This method is not compatible with databases using the authUser option. 318 + The service name reported to PAM is “pgbouncer”. pam is not supported in the HBA configuration file. 319 + ''; 320 + }; 321 + 322 + authHbaFile = mkOption { 323 + type = types.nullOr types.path; 324 + default = null; 325 + example = "/secrets/pgbouncer_hba"; 326 + description = lib.mdDoc '' 327 + HBA configuration file to use when authType is hba. 328 + 329 + See HBA file format details: 330 + <https://www.pgbouncer.org/config.html#hba-file-format> 331 + ''; 332 + }; 333 + 334 + authFile = mkOption { 335 + type = types.nullOr types.path; 336 + default = null; 337 + example = "/secrets/pgbouncer_authfile"; 338 + description = lib.mdDoc '' 339 + The name of the file to load user names and passwords from. 340 + 341 + See section Authentication file format details: 342 + <https://www.pgbouncer.org/config.html#authentication-file-format> 343 + 344 + Most authentication types require that either authFile or authUser be set; 345 + otherwise there would be no users defined. 346 + ''; 347 + }; 348 + 349 + authUser = mkOption { 350 + type = types.nullOr types.str; 351 + default = null; 352 + example = "pgbouncer"; 353 + description = lib.mdDoc '' 354 + If authUser is set, then any user not specified in authFile will be queried 355 + through the authQuery query from pg_shadow in the database, using authUser. 356 + The password of authUser will be taken from authFile. 357 + (If the authUser does not require a password then it does not need to be defined in authFile.) 358 + 359 + Direct access to pg_shadow requires admin rights. 360 + It's preferable to use a non-superuser that calls a SECURITY DEFINER function instead. 361 + ''; 362 + }; 363 + 364 + authQuery = mkOption { 365 + type = types.nullOr types.str; 366 + default = null; 367 + example = "SELECT usename, passwd FROM pg_shadow WHERE usename=$1"; 368 + description = lib.mdDoc '' 369 + Query to load user's password from database. 370 + 371 + Direct access to pg_shadow requires admin rights. 372 + It's preferable to use a non-superuser that calls a SECURITY DEFINER function instead. 373 + 374 + Note that the query is run inside the target database. 375 + So if a function is used, it needs to be installed into each database. 376 + ''; 377 + }; 378 + 379 + authDbname = mkOption { 380 + type = types.nullOr types.str; 381 + default = null; 382 + example = "authdb"; 383 + description = lib.mdDoc '' 384 + Database name in the [database] section to be used for authentication purposes. 385 + This option can be either global or overriden in the connection string if this parameter is specified. 386 + ''; 387 + }; 388 + 389 + # TLS settings 390 + tls.client = mkOption { 391 + type = types.nullOr (types.submodule { 392 + options = { 393 + sslmode = mkOption { 394 + type = types.enum [ "disable" "allow" "prefer" "require" "verify-ca" "verify-full" ]; 395 + default = "disable"; 396 + description = lib.mdDoc '' 397 + TLS mode to use for connections from clients. 398 + TLS connections are disabled by default. 399 + 400 + When enabled, tls.client.keyFile and tls.client.certFile 401 + must be also configured to set up the key and certificate 402 + PgBouncer uses to accept client connections. 403 + 404 + disable 405 + Plain TCP. If client requests TLS, it's ignored. Default. 406 + allow 407 + If client requests TLS, it is used. If not, plain TCP is used. 408 + If the client presents a client certificate, it is not validated. 409 + prefer 410 + Same as allow. 411 + require 412 + Client must use TLS. If not, the client connection is rejected. 413 + If the client presents a client certificate, it is not validated. 414 + verify-ca 415 + Client must use TLS with valid client certificate. 416 + verify-full 417 + Same as verify-ca 418 + ''; 419 + }; 420 + certFile = mkOption { 421 + type = types.path; 422 + example = "/secrets/pgbouncer.key"; 423 + description = lib.mdDoc "Path to certificate for private key. Clients can validate it"; 424 + }; 425 + keyFile = mkOption { 426 + type = types.path; 427 + example = "/secrets/pgbouncer.crt"; 428 + description = lib.mdDoc "Path to private key for PgBouncer to accept client connections"; 429 + }; 430 + caFile = mkOption { 431 + type = types.path; 432 + example = "/secrets/pgbouncer.crt"; 433 + description = lib.mdDoc "Path to root certificate file to validate client certificates"; 434 + }; 435 + }; 436 + }); 437 + default = null; 438 + description = lib.mdDoc '' 439 + <https://www.pgbouncer.org/config.html#tls-settings> 440 + ''; 441 + }; 442 + 443 + tls.server = mkOption { 444 + type = types.nullOr (types.submodule { 445 + options = { 446 + sslmode = mkOption { 447 + type = types.enum [ "disable" "allow" "prefer" "require" "verify-ca" "verify-full" ]; 448 + default = "disable"; 449 + description = lib.mdDoc '' 450 + TLS mode to use for connections to PostgreSQL servers. 451 + TLS connections are disabled by default. 452 + 453 + disable 454 + Plain TCP. TLS is not even requested from the server. Default. 455 + allow 456 + FIXME: if server rejects plain, try TLS? 457 + prefer 458 + TLS connection is always requested first from PostgreSQL. 459 + If refused, the connection will be established over plain TCP. 460 + Server certificate is not validated. 461 + require 462 + Connection must go over TLS. If server rejects it, plain TCP is not attempted. 463 + Server certificate is not validated. 464 + verify-ca 465 + Connection must go over TLS and server certificate must be valid according to tls.server.caFile. 466 + Server host name is not checked against certificate. 467 + verify-full 468 + Connection must go over TLS and server certificate must be valid according to tls.server.caFile. 469 + Server host name must match certificate information. 470 + ''; 471 + }; 472 + certFile = mkOption { 473 + type = types.path; 474 + example = "/secrets/pgbouncer_server.key"; 475 + description = lib.mdDoc "Certificate for private key. PostgreSQL server can validate it."; 476 + }; 477 + keyFile = mkOption { 478 + type = types.path; 479 + example = "/secrets/pgbouncer_server.crt"; 480 + description = lib.mdDoc "Private key for PgBouncer to authenticate against PostgreSQL server."; 481 + }; 482 + caFile = mkOption { 483 + type = types.path; 484 + example = "/secrets/pgbouncer_server.crt"; 485 + description = lib.mdDoc "Root certificate file to validate PostgreSQL server certificates."; 486 + }; 487 + }; 488 + }); 489 + default = null; 490 + description = lib.mdDoc '' 491 + <https://www.pgbouncer.org/config.html#tls-settings> 492 + ''; 493 + }; 494 + 495 + # Log settings 496 + syslog = mkOption { 497 + type = types.nullOr (types.submodule { 498 + options = { 499 + enable = mkOption { 500 + type = types.bool; 501 + default = false; 502 + description = lib.mdDoc '' 503 + Toggles syslog on/off. 504 + ''; 505 + }; 506 + syslogIdent = mkOption { 507 + type = types.str; 508 + default = "pgbouncer"; 509 + description = lib.mdDoc '' 510 + Under what name to send logs to syslog. 511 + ''; 512 + }; 513 + syslogFacility = mkOption { 514 + type = types.enum [ "auth" "authpriv" "daemon" "user" "local0" "local1" "local2" "local3" "local4" "local5" "local6" "local7" ]; 515 + default = "daemon"; 516 + description = lib.mdDoc '' 517 + Under what facility to send logs to syslog. 518 + ''; 519 + }; 520 + }; 521 + }); 522 + default = null; 523 + description = lib.mdDoc '' 524 + <https://www.pgbouncer.org/config.html#log-settings> 525 + ''; 526 + }; 527 + 528 + verbose = lib.mkOption { 529 + type = lib.types.int; 530 + default = 0; 531 + description = lib.mdDoc '' 532 + Increase verbosity. Mirrors the “-v” switch on the command line. 533 + ''; 534 + }; 535 + 536 + # Console access control 537 + adminUsers = mkOption { 538 + type = types.nullOr types.commas; 539 + default = null; 540 + description = lib.mdDoc '' 541 + Comma-separated list of database users that are allowed to connect and run all commands on the console. 542 + Ignored when authType is any, in which case any user name is allowed in as admin. 543 + ''; 544 + }; 545 + 546 + statsUsers = mkOption { 547 + type = types.nullOr types.commas; 548 + default = null; 549 + description = lib.mdDoc '' 550 + Comma-separated list of database users that are allowed to connect and run read-only queries on the console. 551 + That means all SHOW commands except SHOW FDS. 552 + ''; 553 + }; 554 + 555 + # Linux settings 556 + openFilesLimit = lib.mkOption { 557 + type = lib.types.int; 558 + default = 65536; 559 + description = lib.mdDoc '' 560 + Maximum number of open files. 561 + ''; 562 + }; 563 + 564 + user = mkOption { 565 + type = types.str; 566 + default = "pgbouncer"; 567 + description = lib.mdDoc '' 568 + The user pgbouncer is run as. 569 + ''; 570 + }; 571 + 572 + group = mkOption { 573 + type = types.str; 574 + default = "pgbouncer"; 575 + description = lib.mdDoc '' 576 + The group pgbouncer is run as. 577 + ''; 578 + }; 579 + 580 + homeDir = mkOption { 581 + type = types.path; 582 + default = "/var/lib/pgbouncer"; 583 + description = lib.mdDoc '' 584 + Specifies the home directory. 585 + ''; 586 + }; 587 + 588 + # Extra settings 589 + extraConfig = mkOption { 590 + type = types.lines; 591 + description = lib.mdDoc '' 592 + Any additional text to be appended to config.ini 593 + <https://www.pgbouncer.org/config.html>. 594 + ''; 595 + default = ""; 596 + }; 597 + }; 598 + 599 + config = mkIf cfg.enable { 600 + users.groups.${cfg.group} = { }; 601 + users.users.${cfg.user} = { 602 + description = "PgBouncer service user"; 603 + group = cfg.group; 604 + home = cfg.homeDir; 605 + createHome = true; 606 + isSystemUser = true; 607 + }; 608 + 609 + systemd.services.pgbouncer = { 610 + description = "PgBouncer - PostgreSQL connection pooler"; 611 + wants = [ "postgresql.service" ]; 612 + after = [ "postgresql.service" ]; 613 + wantedBy = [ "multi-user.target" ]; 614 + serviceConfig = { 615 + Type = "forking"; 616 + User = cfg.user; 617 + Group = cfg.group; 618 + ExecStart = "${pkgs.pgbouncer}/bin/pgbouncer -d ${confFile}"; 619 + ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID"; 620 + RuntimeDirectory = "pgbouncer"; 621 + PIDFile = "/run/pgbouncer/pgbouncer.pid"; 622 + LimitNOFILE = cfg.openFilesLimit; 623 + }; 624 + }; 625 + 626 + networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; 627 + 628 + }; 629 + 630 + meta.maintainers = [ maintainers._1000101 ]; 631 + 632 + }
+1
nixos/tests/all-tests.nix
··· 599 599 peertube = handleTestOn ["x86_64-linux"] ./web-apps/peertube.nix {}; 600 600 peroxide = handleTest ./peroxide.nix {}; 601 601 pgadmin4 = handleTest ./pgadmin4.nix {}; 602 + pgbouncer = handleTest ./pgbouncer.nix {}; 602 603 pgjwt = handleTest ./pgjwt.nix {}; 603 604 pgmanage = handleTest ./pgmanage.nix {}; 604 605 phosh = handleTest ./phosh.nix {};
+61
nixos/tests/pgbouncer.nix
··· 1 + import ./make-test-python.nix ({ pkgs, ... } : 2 + let 3 + testAuthFile = pkgs.writeTextFile { 4 + name = "authFile"; 5 + text = '' 6 + "testuser" "testpass" 7 + ''; 8 + }; 9 + in 10 + { 11 + name = "pgbouncer"; 12 + meta = with pkgs.lib.maintainers; { 13 + maintainers = [ _1000101 ]; 14 + }; 15 + nodes = { 16 + one = { config, pkgs, ... }: { 17 + 18 + systemd.services.postgresql = { 19 + postStart = '' 20 + ${pkgs.postgresql}/bin/psql -U postgres -c "ALTER ROLE testuser WITH LOGIN PASSWORD 'testpass'"; 21 + ''; 22 + }; 23 + 24 + services = { 25 + postgresql = { 26 + enable = true; 27 + ensureDatabases = [ "testdb" ]; 28 + ensureUsers = [ 29 + { 30 + name = "testuser"; 31 + ensurePermissions = { 32 + "DATABASE testdb" = "ALL PRIVILEGES"; 33 + }; 34 + }]; 35 + authentication = '' 36 + local testdb testuser scram-sha-256 37 + ''; 38 + }; 39 + 40 + pgbouncer = { 41 + enable = true; 42 + listenAddress = "localhost"; 43 + databases = { testdb = "host=/run/postgresql/ port=5432 auth_user=testuser dbname=testdb"; }; 44 + authType = "scram-sha-256"; 45 + authFile = testAuthFile; 46 + }; 47 + }; 48 + }; 49 + }; 50 + 51 + testScript = '' 52 + start_all() 53 + one.wait_for_unit("default.target") 54 + one.require_unit_state("pgbouncer.service", "active") 55 + 56 + # Test if we can make a query through PgBouncer 57 + one.wait_until_succeeds( 58 + "psql 'postgres://testuser:testpass@localhost:6432/testdb' -c 'SELECT 1;'" 59 + ) 60 + ''; 61 + })
+5 -1
pkgs/servers/sql/pgbouncer/default.nix
··· 1 - { lib, stdenv, fetchurl, openssl, libevent, c-ares, pkg-config }: 1 + { lib, stdenv, fetchurl, openssl, libevent, c-ares, pkg-config, nixosTests }: 2 2 3 3 stdenv.mkDerivation rec { 4 4 pname = "pgbouncer"; ··· 12 12 nativeBuildInputs = [ pkg-config ]; 13 13 buildInputs = [ libevent openssl c-ares ]; 14 14 enableParallelBuilding = true; 15 + 16 + passthru.tests = { 17 + pgbouncer = nixosTests.pgbouncer; 18 + }; 15 19 16 20 meta = with lib; { 17 21 homepage = "https://www.pgbouncer.org/";