From 81d2433735742cc8457bbd8bcbb0b328b0784fb3 Mon Sep 17 00:00:00 2001 From: Harry Stern Date: Wed, 1 May 2024 19:08:31 -0400 Subject: [PATCH] Add -o option to pgtemp daemon for passing server configs Allows `PgTempDBBuilder::with_config_param` with pgtemp daemon --- CHANGELOG.md | 8 ++++++++ README.md | 2 ++ TODO | 2 +- src/daemon.rs | 25 +++++++++++++++++++++++++ tests/daemon.rs | 21 +++++++++++++++++++++ 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e812a43..a11c965 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +unreleased +---------- +Add -o options to pgtemp daemon for postgresql server configs + +0.2 +--- +Documentation updates + 0.1.0 ----- Initial release diff --git a/README.md b/README.md index f29f7e0..ec4c72c 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ The pgtemp cli tool allows you to even more simply make temporary connections, a pgtemp supports loading (and dumping, in the library) the database to/from [dumpfiles via `pg_dump`](https://www.postgresql.org/docs/current/backup-dump.html). +Note that the default postgres authentication configuration (`pg_hba.conf`) in most cases allows all local connections. Since pgtemp only allows you to make servers that listen on localhost, this means in most cases you do not need to provide a password to connect. You may set the server's `hba_file` parameter in `PgTempDBBuilder::with_config_param` or use the pgtemp daemon's `-o` flag to pass `hba_file` there. + # Requirements You must install both the postgresql client and server packages. On Debian/Ubuntu, they are `postgresql postgresql-client`, on Fedora they are `postgresql postgresql-server`, and on Arch Linux they are `postgresql postgresql-libs`. Note also that Debian/Ubuntu install the standard postgres binaries into their own directory, so you must add them to your path. For an Ubuntu GitHub Actions runner, it looks like: diff --git a/TODO b/TODO index ad96b81..5b04e46 100644 --- a/TODO +++ b/TODO @@ -5,7 +5,7 @@ await db.async_shutdown() - .pgpass file instead of just writing password to file? only seems to be an issue for createdb and really at that point we could just execute with psql instead. -- support all builder options in cli (--persist, custom config params) +- support all builder options in cli (e.g. --persist) - cache initial files from initdb or otherwise optimize all setup stuff diff --git a/src/daemon.rs b/src/daemon.rs index 6f2fe02..b888ba1 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -10,6 +10,7 @@ use tokio::signal::unix::{signal, SignalKind}; /// Contains the clap args struct pub mod cli { use clap::Parser; + use std::error::Error; use std::path::PathBuf; #[derive(Parser, Debug)] @@ -32,10 +33,30 @@ pub mod cli { /// The sql script to be loaded on startup pub load_from: Option, + #[arg(long, short = 'o', value_name = "KEY=VAL", value_parser = parse_key_val::)] + /// PostgreSQL server configuration parameters in key=value format to pass on startup. May + /// be passed multiple times. + pub server_params: Vec<(String, String)>, + /// The postgres connection uri to be used by pgtemp clients. /// E.g. postgresql://localhost:5432/mytestdb pub connection_uri: String, } + + // from https://github.com/clap-rs/clap/blob/d681a81dd7f4d7ff71f2e65be26d8f90783f7b40/examples/typed-derive.rs#L47C1-L59C2 + /// Parse a single key-value pair + fn parse_key_val(s: &str) -> Result<(T, U), Box> + where + T: std::str::FromStr, + T::Err: Error + Send + Sync + 'static, + U: std::str::FromStr, + U::Err: Error + Send + Sync + 'static, + { + let pos = s + .find('=') + .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?; + Ok((s[..pos].parse()?, s[pos + 1..].parse()?)) + } } #[cfg(feature = "cli")] @@ -65,6 +86,10 @@ impl PgTempDaemon { if let Some(load_from) = args.load_from { builder = builder.load_database(&load_from); } + for (key, value) in args.server_params { + builder = builder.with_config_param(&key, &value); + eprintln!("{}={}", key, value); + } let port = builder.get_port_or_set_random(); let single_mode = args.single; diff --git a/tests/daemon.rs b/tests/daemon.rs index 09a6600..0bc1d1a 100644 --- a/tests/daemon.rs +++ b/tests/daemon.rs @@ -96,6 +96,7 @@ async fn daemon_single_mode() { single: true, data_dir_prefix: Some(temp_prefix.path().into()), load_from: None, + server_params: vec![("geqo".into(), "off".into()), ("jit".into(), "off".into())], connection_uri: uri.to_string(), }; @@ -110,6 +111,9 @@ async fn daemon_single_mode() { .await .expect("failed to connect to db"); + // check the config params were set + check_config(&mut conn1).await; + // create table on conn 2 create_table(&mut conn2).await; @@ -121,6 +125,23 @@ async fn daemon_single_mode() { check_data(&mut conn2, "test").await; } +async fn check_config(conn: &mut PgConn) { + // jit, ssl, and geqo are the shorted postgres config names but we can't turn on ssl + let rows = sqlx::query("SELECT name, setting from pg_settings WHERE name = 'jit' OR name = 'geqo' ORDER BY name ASC") + .fetch_all(conn) + .await + .expect("failed to get config settings"); + assert_eq!(rows.len(), 2); + + let row = &rows[1]; + let geqo: &str = row.get(1); + assert_eq!(geqo, "off"); + + let row = &rows[0]; + let jit: &str = row.get(1); + assert_eq!(jit, "off"); +} + async fn create_table(conn: &mut PgConn) { sqlx::query( "