Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add postgres dependency for server to startup #36585

Merged
merged 9 commits into from
Sep 30, 2024
92 changes: 92 additions & 0 deletions deploy/docker/fs/opt/appsmith/pg-utils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/bin/bash

waitForPostgresAvailability() {
if [ -z "$PG_DB_HOST" ]; then
tlog "PostgreSQL host name is empty. Check env variables. Error. Exiting java setup"
exit 2
else

MAX_RETRIES=50
RETRYSECONDS=10
retry_count=0
while true; do
su postgres -c "pg_isready -h '${PG_DB_HOST}' -p '${PG_DB_PORT}'"
status=$?

case $status in
0)
tlog "PostgreSQL host '$PG_DB_HOST' is ready."
break
;;
1)
tlog "PostgreSQL host '$PG_DB_HOST' is rejecting connections e.g. due to being in recovery mode or not accepting connections eg. connections maxed out."
;;
2)
tlog "PostgreSQL host '$PG_DB_HOST' is not responding or running."
;;
3)
tlog "The connection check failed e.g. due to network issues or incorrect parameters."
;;
*)
tlog "pg_isready exited with unexpected status code: $status"
break
;;
esac

retry_count=$((retry_count + 1))
if [ $retry_count -le $MAX_RETRIES ]; then
tlog "PostgreSQL connection failed. Retrying attempt $retry_count/$MAX_RETRIES in $RETRYSECONDS seconds..."
sleep $RETRYSECONDS
else
tlog "Exceeded maximum retry attempts ($MAX_RETRIES). Exiting."
# use exit code 2 to indicate that the script failed to connect to postgres and supervisor conf is set not to restart the program for 2.
exit 2
fi

done
fi
}

# for PostgreSQL, we use APPSMITH_DB_URL=postgresql://username:password@postgresserver:5432/dbname
# Args:
# conn_string (string): PostgreSQL connection string
# Returns:
# None
# Example:
# postgres syntax
# "postgresql://user:password@localhost:5432/appsmith"
# "postgresql://user:password@localhost/appsmith"
# "postgresql://user@localhost:5432/appsmith"
# "postgresql://user@localhost/appsmith"
extract_postgres_db_params() {
local conn_string=$1

# Use node to parse the URI and extract components
IFS=' ' read -r USER PASSWORD HOST PORT DB <<<"$(node -e "
const connectionString = process.argv[1];
const pgUri = connectionString.startsWith(\"postgresql://\")
? connectionString
: 'http://' + connectionString; //Prepend a fake scheme for URL parsing
const url = require('url');
const parsedUrl = new url.URL(pgUri);

// Extract the pathname and remove the leading '/'
const db = parsedUrl.pathname.substring(1);

// Default the port to 5432 if it's empty
const port = parsedUrl.port || '5432';

console.log(\`\${parsedUrl.username || '-'} \${parsedUrl.password || '-'} \${parsedUrl.hostname} \${port} \${db}\`);
" "$conn_string")"

# Now, set the environment variables
export PG_DB_USER="$USER"
export PG_DB_PASSWORD="$PASSWORD"
export PG_DB_HOST="$HOST"
export PG_DB_PORT="$PORT"
export PG_DB_NAME="$DB"
}

# Example usage of the functions
# waitForPostgresAvailability
# extract_postgres_db_params "postgresql://user:password@localhost:5432/dbname"
9 changes: 9 additions & 0 deletions deploy/docker/fs/opt/appsmith/run-java.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/bash

# Source the helper script
source pg-utils.sh

set -o errexit
set -o pipefail
set -o nounset
Expand Down Expand Up @@ -29,6 +32,12 @@ match-proxy-url() {
[[ -n $proxy_host ]]
}

# Extract the database parameters from the APPSMITH_DB_URL and wait for the database to be available
if [[ "$mode" == "pg" ]]; then
extract_postgres_db_params "$APPSMITH_DB_URL"
waitForPostgresAvailability
fi

if match-proxy-url "${HTTP_PROXY-}"; then
extra_args+=(-Dhttp.proxyHost="$proxy_host" -Dhttp.proxyPort="$proxy_port")
if [[ -n $proxy_user ]]; then
Expand Down
68 changes: 68 additions & 0 deletions deploy/docker/tests/test-pg-utils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env bash

set -e

# Include the script to be tested
source /Users/appsmith/Work/appsmith-ce/deploy/docker/fs/opt/appsmith/pg-utils.sh

assert_equals() {
if [ "$1" != "$2" ]; then
echo "Assertion failed: expected '$2', but got '$1'"
return 1
fi
}

# Test extract_postgres_db_params function
test_extract_postgres_db_params_valid_db_string() {
local conn_string="postgresql://user:password@localhost:5432/dbname"
extract_postgres_db_params "$conn_string"

if [ "$PG_DB_USER" != "user" ] || [ "$PG_DB_PASSWORD" != "password" ] || [ "$PG_DB_HOST" != "localhost" ] || [ "$PG_DB_PORT" != "5432" ] || [ "$PG_DB_NAME" != "dbname" ]; then
echo "Test failed: test_extract_postgres_db_params_valid_db_string did not extract parameters correctly"
echo_params
exit 1
fi

echo "Test passed: test_extract_postgres_db_params_valid_db_string"
}

test_extract_postgres_db_params_empty_dbname() {
local conn_string="postgresql://user:password@localhost:5432"
extract_postgres_db_params "$conn_string"

if [ "$PG_DB_USER" != "user" ] || [ "$PG_DB_PASSWORD" != "password" ] || [ "$PG_DB_HOST" != "localhost" ] || [ "$PG_DB_PORT" != "5432" ] || [ "$PG_DB_NAME" != "" ]; then
echo "Test failed: test_extract_postgres_db_params_empty_dbname did not extract parameters correctly"
echo_params
exit 1
fi

echo "Test passed: test_extract_postgres_db_params_empty_dbname"
}

test_extract_postgres_db_params_with_spaces() {
local conn_string="postgresql://user:p a s s w o r d@localhost:5432/db_name"
extract_postgres_db_params "$conn_string"

if [ "$PG_DB_USER" != "user" ] || [ "$PG_DB_PASSWORD" != "p%20a%20s%20s%20w%20o%20r%20d" ] || [ "$PG_DB_HOST" != "localhost" ] || [ "$PG_DB_PORT" != "5432" ] || [ "$PG_DB_NAME" != "db_name" ]; then
echo "Test failed: test_extract_postgres_db_params_with_spaces did not extract parameters correctly"
echo_params
exit 1
fi

echo "Test passed: test_extract_postgres_db_params_with_spaces"
}

echo_params() {
echo "PG_DB_USER: $PG_DB_USER"
echo "PG_DB_PASSWORD: $PG_DB_PASSWORD"
echo "PG_DB_HOST: $PG_DB_HOST"
echo "PG_DB_PORT: $PG_DB_PORT"
echo "PG_DB_NAME: $PG_DB_NAME"
}

# Run tests
test_extract_postgres_db_params_valid_db_string
test_extract_postgres_db_params_empty_dbname
test_extract_postgres_db_params_with_spaces

echo "All Tests Pass!"
Loading