Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion nix/tools/tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ let
}
''
${withTools.withPg} -f test/observability/fixtures/load.sql \
${cabal-install}/bin/cabal v2-run ${devCabalOptions} test:observability -- "''${_arg_leftovers[@]}"
${withTools.withToxiproxyPgProxy} \
${cabal-install}/bin/cabal v2-run ${devCabalOptions} test:observability -- "''${_arg_leftovers[@]}"
'';

testDoctests =
Expand Down
117 changes: 110 additions & 7 deletions nix/tools/withTools.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
, python3Packages
, writeText
, writers
, toxiproxy
}:
let
withTmpDb =
Expand Down Expand Up @@ -54,16 +55,25 @@ let

export PGDATA="$tmpdir/db"
export PGHOST="$tmpdir/socket"
PGPORT=$(${randomPort})
export PGPORT
export PGUSER
export PGDATABASE
export PGRST_DB_SCHEMAS
export PGTZ
export PGOPTIONS

HBA_FILE="$tmpdir/pg_hba.conf"
echo "local $PGDATABASE some_protected_user password" > "$HBA_FILE"
echo "local $PGDATABASE all trust" >> "$HBA_FILE"
echo "local replication all trust" >> "$HBA_FILE"
{
echo "local $PGDATABASE some_protected_user password"
echo "local $PGDATABASE all trust"
echo "local replication all trust"
echo "host $PGDATABASE some_protected_user localhost password"
echo "host $PGDATABASE all localhost trust"
} >> "$HBA_FILE"

UNIX_PGHOST="$PGHOST"
export TCP_PGHOST="localhost"

log "Initializing database cluster..."
# We try to make the database cluster as independent as possible from the host
Expand All @@ -80,7 +90,7 @@ let
# On MacOS, it's 104 chars
# See: https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket

pg_ctl -l "$tmpdir/db.log" -w start -o "-F -c listen_addresses=\"\" -c hba_file=$HBA_FILE -k $PGHOST -c log_statement=\"all\" " \
pg_ctl -l "$tmpdir/db.log" -w start -o "-F -c listen_addresses=\"$TCP_PGHOST\" -c hba_file=$HBA_FILE -k $UNIX_PGHOST -c log_statement=\"all\" " \
>> "$setuplog"

log "Creating a minimally privileged $PGUSER connection role..."
Expand All @@ -93,6 +103,7 @@ let
replica_slot="replica_$RANDOM"
replica_dir="$tmpdir/$replica_slot"
replica_host="$tmpdir/socket_$replica_slot"
replica_port=$(${randomPort})

mkdir -p "$replica_host"

Expand All @@ -106,15 +117,16 @@ let
log "Starting replica on $replica_host"

# We set a low max_standby_streaming_delay to make the replication conflict fail faster in tests (otherwise it waits for the default 30s)
pg_ctl -D "$replica_dir" -l "$replica_dblog" -w start -o "-F -c listen_addresses=\"\" -c hba_file=$HBA_FILE -k $replica_host -c log_statement=\"all\" -c max_standby_streaming_delay=\"3s\" " \
pg_ctl -D "$replica_dir" -l "$replica_dblog" -w start -o "-F -c listen_addresses=\"$TCP_PGHOST\" -c port=$replica_port -c hba_file=$HBA_FILE -k $replica_host -c log_statement=\"all\" -c max_standby_streaming_delay=\"3s\" " \
>> "$setuplog"

>&2 echo "${commandName}: Replica enabled. You can connect to it with: psql 'postgres:///$PGDATABASE?host=$replica_host' -U postgres"
>&2 echo "${commandName}: You can tail the replica logs with: tail -f $replica_dblog"

export PGREPLICAHOST="$replica_host"
export PGREPLICAPORT="$replica_port"
export PGREPLICASLOT="$replica_slot"
export PGRST_DB_URI="postgres:///$PGDATABASE?host=$PGREPLICAHOST,$PGHOST"
export PGRST_DB_URI="postgres:///$PGDATABASE?host=$PGREPLICAHOST,$PGHOST&port=$replica_port,$PGPORT"
fi

# shellcheck disable=SC2329
Expand Down Expand Up @@ -372,6 +384,97 @@ let
libraries = [ python3Packages.pandas python3Packages.tabulate python3Packages.psutil ];
}
(builtins.readFile ./monitor_pid.py);

randomPort =
writers.writePython3 "postgrest-random-port"
{
# Quick one-liner: ignore linting errors
flakeIgnore = [ "E702" "W292" "E501" ];
}
''import socket; s = socket.socket(); s.bind(("127.0.0.1", 0)); print(s.getsockname()[1]); s.close()'';

withToxiproxyProxy =
checkedShellScript
{
name = "postgrest-with-toxiproxy-proxy";
docs = "Run <command> with Toxiproxy proxy created. Proxy name passed as TOXI_PROXY_NAME env variable.";
args =
[
"ARG_POSITIONAL_SINGLE([command], [Command to run])"
"ARG_LEFTOVERS([command arguments])"
"ARG_OPTIONAL_SINGLE([listen], [l], [Proxy will listen on this address])"
"ARG_OPTIONAL_SINGLE([upstream], [u], [Proxy will forward to this address])"
];
positionalCompletion = "_command";
workingDir = "/";
withPath = [ toxiproxy ];
}
''
proxyname="tp$RANDOM"
toxiproxy-cli create -l "$_arg_listen" -u "$_arg_upstream" "$proxyname"

# shellcheck disable=SC2329
stop () {
toxiproxy-cli delete "$proxyname" || true
}
trap stop EXIT

(TOXI_PROXY_NAME="$proxyname" "$_arg_command" "''${_arg_leftovers[@]}")
'';

withToxiproxyPgProxy =
checkedShellScript
{
name = "postgrest-with-toxiproxy-pg-proxy";
docs = "Run <command> with a Toxiproxy proxy to PosgreSQL.";
args =
[
"ARG_POSITIONAL_SINGLE([command], [Command to run])"
"ARG_LEFTOVERS([command arguments])"
"ARG_USE_ENV([TCP_PGHOST], [], [PG host name])"
"ARG_USE_ENV([PGPORT], [], [PG port])"
];
positionalCompletion = "_command";
workingDir = "/";
}
''
proxy_port=''$(${randomPort})

${withToxiproxyServer} ${withToxiproxyProxy} -l "$TCP_PGHOST:$proxy_port" -u "$TCP_PGHOST:$PGPORT" \
env "TOXI_PGPORT=$proxy_port" "$_arg_command" "''${_arg_leftovers[@]}"
'';

withToxiproxyServer =
checkedShellScript
{
name = "postgrest-with-toxiproxy-server";
docs = "Run <command> with toxiproxy-server";
args =
[
"ARG_POSITIONAL_SINGLE([command], [Command to run])"
"ARG_LEFTOVERS([command arguments])"
];
positionalCompletion = "_command";
workingDir = "/";
withPath = [ toxiproxy ];
}
''
if ! test -v TOXI_PROXY; then
export TOXI_PROXY=""
LOG_LEVEL=error toxiproxy-server&
TOXIPROXY_PID=$!
sleep 1 # give the server a moment to start

# shellcheck disable=SC2329
stop () {
kill "$TOXIPROXY_PID" || true
wait "$TOXIPROXY_PID" || true
}
trap stop EXIT
fi
("$_arg_command" "''${_arg_leftovers[@]}")
'';

in
buildToolbox
{
Expand All @@ -386,5 +489,5 @@ buildToolbox
builtins.map (pg: { inherit (pg) name; value = withTmpDb pg; }) postgresqlVersions
);
# make latest withPg available for other nix files
extra = { inherit withPg; };
extra = { inherit withPg withToxiproxyPgProxy; };
}
10 changes: 10 additions & 0 deletions postgrest.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -311,22 +311,32 @@ test-suite observability
Observation.JwtCache
Observation.MetricsSpec
Observation.SchemaCacheSpec
Observation.ToxiSpec
Toxiproxy
build-depends: base >= 4.9 && < 4.22
, aeson >= 2.0.3 && < 2.3
, base64-bytestring >= 1 && < 1.3
, bytestring >= 0.10.8 && < 0.13
, containers >= 0.5.7 && < 0.8
, hasql-pool >= 1.0.1 && <= 1.3.0.4
, hasql-transaction >= 1.0.1 && <= 1.2.1
, hspec >= 2.3 && < 2.12
, hspec-expectations >= 0.8.4 && < 0.9
, hspec-wai >= 0.10 && < 0.12
, hspec-wai-json >= 0.10 && < 0.12
, http-client >= 0.7.19 && < 0.8
, http-types >= 0.12.3 && < 0.13
, jose-jwt >= 0.9.6 && < 0.11
, monad-control >= 1.0.1 && < 1.1
, postgrest
, prometheus-client >= 1.1.1 && < 1.2.0
, protolude >= 0.3.1 && < 0.4
, servant-client >= 0.20.3.0 && < 0.21
, servant >= 0.20.3.0 && < 0.21
, text >= 1.2.2 && < 2.2
, transformers-base >= 0.4.4 && < 0.5
, wai >= 3.2.1 && < 3.3
, wai-extra >= 3.1.8 && < 3.2
ghc-options: -threaded -O0 -Werror -Wall -fwarn-identities
-fno-spec-constr -optP-Wno-nonportable-include-path
-fwrite-ide-info
Expand Down
2 changes: 1 addition & 1 deletion src/PostgREST/App.hs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ run appState = do
NS.close mainSocket
Unix.installSignalHandlers observer closeSockets (AppState.schemaCacheLoader appState) (AppState.readInDbConfig False appState)

Listener.runListener appState
void $ Listener.runListener appState

Admin.runAdmin appState adminSocket mainSocket (serverSettings conf)

Expand Down
1 change: 1 addition & 0 deletions src/PostgREST/AppState.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
module PostgREST.AppState
( AppState
, destroy
, flushPool
, getConfig
, getSchemaCache
, getMainThreadId
Expand Down
7 changes: 4 additions & 3 deletions src/PostgREST/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module PostgREST.Config
, readPGRSTEnvironment
, toURI
, parseSecret
, addConnStringOption
, addFallbackAppName
, addTargetSessionAttrs
, toConnectionSettings
Expand Down Expand Up @@ -627,7 +628,7 @@ pgConnString conn | uriDesignator `T.isPrefixOf` conn || shortUriDesignator `T.i
-- >>> addFallbackAppName ver "postgresql:///postgres?host=/run/user/1000/postgrest/postgrest-with-postgresql-16-BuR/socket&user=some_protected_user&password=invalid_pass"
-- "postgresql:///postgres?host=/run/user/1000/postgrest/postgrest-with-postgresql-16-BuR/socket&user=some_protected_user&password=invalid_pass&fallback_application_name=PostgREST%2011.1.0%20%285a04ec7%29"
addFallbackAppName :: ByteString -> Text -> Text
addFallbackAppName version dbUri = addConnStringOption dbUri "fallback_application_name" pgrstVer
addFallbackAppName version = addConnStringOption "fallback_application_name" pgrstVer
where
pgrstVer = "PostgREST " <> T.decodeUtf8 version

Expand All @@ -649,7 +650,7 @@ addFallbackAppName version dbUri = addConnStringOption dbUri "fallback_applicati
-- >>> addTargetSessionAttrs "host=localhost port=5432 dbname=postgres"
-- "host=localhost port=5432 dbname=postgres target_session_attrs='read-write'"
addTargetSessionAttrs :: Text -> Text
addTargetSessionAttrs dbUri = addConnStringOption dbUri "target_session_attrs" "read-write"
addTargetSessionAttrs = addConnStringOption "target_session_attrs" "read-write"

toConnectionSettings :: (Text -> Text) -> AppConfig -> [SQL.Setting]
toConnectionSettings transformUri AppConfig{configDbUri, configDbPreparedStatements} =
Expand All @@ -658,7 +659,7 @@ toConnectionSettings transformUri AppConfig{configDbUri, configDbPreparedStateme
]

addConnStringOption :: Text -> Text -> Text -> Text
addConnStringOption dbUri key val = dbUri <>
addConnStringOption key val dbUri= dbUri <>
case pgConnString dbUri of
Nothing -> mempty
Just PGKeyVal -> " " <> keyValFmt
Expand Down
Loading
Loading