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: create appsmith schema for postgres #36591

Merged
merged 20 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 8 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
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ public DataSourceProperties configurePostgresDB() {
return extractJdbcProperties(appsmithDbUrl);
}

/**
* Method to extract Jdbc props from the given DB URL
* Expected DB URL: postgresql://{username}:{password}@localhost:{port}/{db_name}
*/
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved
public DataSourceProperties extractJdbcProperties(String dbUrl) {
DataSourceProperties ds = new DataSourceProperties();
try {
Expand All @@ -69,10 +65,23 @@ public DataSourceProperties extractJdbcProperties(String dbUrl) {
ds.setUsername(userDetails[0]);
ds.setPassword(userDetails[1]);
}
// If the port is not mentioned default it to standard 5432
// If the port is not mentioned, default it to the standard PostgreSQL port 5432
int port = uri.getPort() == -1 ? 5432 : uri.getPort();
String updatedUrl =
String.format("%s%s://%s:%s%s", JDBC_PREFIX, uri.getScheme(), uri.getHost(), port, uri.getPath());

// Check if the URL already has query parameters
String query = uri.getQuery();
String updatedUrl;
if (StringUtils.hasLength(query)) {
// Append currentSchema=appsmith if there are already parameters
updatedUrl = String.format(
"%s%s://%s:%s%s?%s&currentSchema=appsmith",
JDBC_PREFIX, uri.getScheme(), uri.getHost(), port, uri.getPath(), query);
} else {
// No parameters, just append currentSchema
updatedUrl = String.format(
"%s%s://%s:%s%s?currentSchema=appsmith",
JDBC_PREFIX, uri.getScheme(), uri.getHost(), port, uri.getPath());
}
ds.setUrl(updatedUrl);
return ds;
} catch (URISyntaxException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ public void testExtractAndSaveJdbcParams_validDbUrlWithUsernameAndPassword() {
DataSourceProperties ds = commonDBConfig.extractJdbcProperties(dbUrl);
assertEquals("postgres", ds.getUsername());
assertEquals("password", ds.getPassword());
assertEquals("jdbc:postgresql://localhost:5432/postgres", ds.getUrl());
assertEquals("jdbc:postgresql://localhost:5432/postgres?currentSchema=appsmith", ds.getUrl());
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved

String dbUrlWithPort = "postgresql://postgres:password@localhost:1234/postgres";
ds = commonDBConfig.extractJdbcProperties(dbUrlWithPort);
assertEquals("postgres", ds.getUsername());
assertEquals("password", ds.getPassword());
assertEquals("jdbc:postgresql://localhost:1234/postgres", ds.getUrl());
assertEquals("jdbc:postgresql://localhost:1234/postgres?currentSchema=appsmith", ds.getUrl());
}

@Test
Expand All @@ -32,7 +32,7 @@ public void testExtractAndSaveJdbcParams_validDbUrlWithoutUsernameAndPassword()
DataSourceProperties ds = commonDBConfig.extractJdbcProperties(dbUrl);
assertNull(ds.getUsername());
assertNull(ds.getPassword());
assertEquals("jdbc:postgresql://localhost:5432/postgres", ds.getUrl());
assertEquals("jdbc:postgresql://localhost:5432/postgres?currentSchema=appsmith", ds.getUrl());
}

@Test
Expand Down
33 changes: 32 additions & 1 deletion deploy/docker/fs/opt/appsmith/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ init_env_file() {
# Generate new docker.env file when initializing container for first time or in Heroku which does not have persistent volume
tlog "Generating default configuration file"
mkdir -p "$CONF_PATH"

local default_appsmith_mongodb_user="appsmith"
local generated_appsmith_mongodb_password=$(
tr -dc A-Za-z0-9 </dev/urandom | head -c 13
Expand All @@ -75,9 +76,39 @@ init_env_file() {
tr -dc A-Za-z0-9 </dev/urandom | head -c 13
echo ''
)

bash "$TEMPLATES_PATH/docker.env.sh" "$default_appsmith_mongodb_user" "$generated_appsmith_mongodb_password" "$generated_appsmith_encryption_password" "$generated_appsmith_encription_salt" "$generated_appsmith_supervisor_password" > "$ENV_PATH"
fi

else
# Check if APPSMITH_DB_URL is set and is a PostgreSQL URL
if [[ -n "$APPSMITH_DB_URL" && "$APPSMITH_DB_URL" == postgres*://* ]]; then
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved
echo "APPSMITH_DB_URL is a valid PostgreSQL URL."

# Extract the host from APPSMITH_DB_URL
DB_HOST=$(echo "$APPSMITH_DB_URL" | sed -n 's#.*://[^@]*@\([^:]*\):.*#\1#p')
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved

# Check if DB_HOST is localhost or 127.0.0.1
if [[ "$DB_HOST" == "localhost" || "$DB_HOST" == "127.0.0.1" ]]; then
echo "Local PostgreSQL detected. Regenerating password..."

# Generate a new password for local PostgreSQL
DB_USER="appsmith"
DB_PASSWORD=$(openssl rand -base64 12) # Generate a random password
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved
echo "Generated new password for appsmith user: $DB_PASSWORD"
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved

# Update APPSMITH_DB_URL with the new username and password
APPSMITH_DB_URL=$(echo "$APPSMITH_DB_URL" | sed "s#postgres://[^:]*:[^@]*@#postgres://$DB_USER:$DB_PASSWORD@#")
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved
echo "APPSMITH_DB_URL updated with new user and password: $APPSMITH_DB_URL"
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved

# Optionally: Save the updated APPSMITH_DB_URL back to the .env file or environment
sed -i "s#APPSMITH_DB_URL=.*#APPSMITH_DB_URL=$APPSMITH_DB_URL#g" "$ENV_PATH"
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved
else
echo "Remote PostgreSQL detected. No changes made to username or password."
fi
else
echo "APPSMITH_DB_URL is either empty or not a PostgreSQL URL. Skipping database configuration."
fi
fi
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved

tlog "Load environment configuration"

Expand Down
57 changes: 57 additions & 0 deletions deploy/docker/fs/opt/appsmith/pg-default-schema.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/bin/bash

run_pg_db() {
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved
# Create the appsmith schema
echo "Initializing PostgreSQL with schema..."

# Check if APPSMITH_DB_URL is a PostgreSQL URL
if [[ -n "$APPSMITH_DB_URL" && "$APPSMITH_DB_URL" == postgres*://* ]]; then
echo "APPSMITH_DB_URL is a valid PostgreSQL URL."
# Extract username, password, host, port, and database name from APPSMITH_DB_URL
DB_USER=$(echo "$APPSMITH_DB_URL" | sed -n 's#.*://\([^:]*\):.*#\1#p')
DB_PASSWORD=$(echo "$APPSMITH_DB_URL" | sed -n 's#.*://[^:]*:\([^@]*\)@.*#\1#p')
DB_HOST=$(echo "$APPSMITH_DB_URL" | sed -n 's#.*://[^@]*@\([^:]*\):.*#\1#p')
DB_PORT=$(echo "$APPSMITH_DB_URL" | sed -n 's#.*://[^@]*@[^:]*:\([^/]*\)/.*#\1#p')
DB_NAME=$(echo "$APPSMITH_DB_URL" | sed -n 's#.*://[^@]*@[^/]*/\([^?]*\).*#\1#p')
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved

# Set defaults for host, port, and database name if not set
DB_HOST=${DB_HOST:-localhost}
DB_PORT=${DB_PORT:-5432}
DB_NAME=${DB_NAME:-appsmith}

for i in {1..60}; do
PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c "SELECT 1;" &> /dev/null
if [ $? -eq 0 ]; then
echo "PostgreSQL is available!"
break
else
echo "PostgreSQL is unavailable - waiting..."
sleep 10
fi

# If PostgreSQL isn't available after 30 attempts (60 seconds), exit with failure
if [ $i -eq 30 ]; then
echo "PostgreSQL is still unavailable after multiple attempts. Exiting..."
exit 1
fi
done
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved

echo "Connecting to PostgreSQL at $DB_HOST:$DB_PORT with user $DB_USER"

# Execute SQL to create the appsmith schema if it doesn't exist (single line)
PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c "CREATE SCHEMA IF NOT EXISTS appsmith;"
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved

# Check if the schema creation was successful
if [ $? -eq 0 ]; then
echo "Schema 'appsmith' created or already exists."
else
echo "Failed to create schema 'appsmith'."
exit 1
fi
echo "PostgreSQL initialization completed."
Copy link
Contributor

@abhvsn abhvsn Sep 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we not creating the appsmith user?

else
echo "APPSMITH_DB_URL is either empty or not a PostgreSQL URL. Skipping PostgreSQL initialization."
fi
}

run_pg_db
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")
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved

# 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"
13 changes: 13 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

AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved
if match-proxy-url "${HTTP_PROXY-}"; then
extra_args+=(-Dhttp.proxyHost="$proxy_host" -Dhttp.proxyPort="$proxy_port")
if [[ -n $proxy_user ]]; then
Expand Down Expand Up @@ -72,6 +81,10 @@ while ! curl --fail --silent localhost:"${APPSMITH_RTS_PORT:-8091}"/rts-api/v1/h
done
tlog 'RTS started.'

if [[ "$mode" == "pg" ]]; then
sh /opt/appsmith/pg-default-schema.sh &
AnaghHegde marked this conversation as resolved.
Show resolved Hide resolved
fi

sh /opt/appsmith/run-starting-page-init.sh &

# Ref -Dlog4j2.formatMsgNoLookups=true https://spring.io/blog/2021/12/10/log4j2-vulnerability-and-spring-boot
Expand Down
7 changes: 4 additions & 3 deletions deploy/docker/fs/opt/appsmith/templates/docker.env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

set -o nounset
MONGO_USER="$1"
MONGO_PASSWORD="$2"
DB_PASSWORD="$2"
ENCRYPTION_PASSWORD="$3"
ENCRYPTION_SALT="$4"
SUPERVISOR_PASSWORD="$5"
Expand Down Expand Up @@ -63,9 +63,10 @@ APPSMITH_RECAPTCHA_SITE_KEY=
APPSMITH_RECAPTCHA_SECRET_KEY=
APPSMITH_RECAPTCHA_ENABLED=

APPSMITH_DB_URL=mongodb://$MONGO_USER:$MONGO_PASSWORD@localhost:27017/appsmith
APPSMITH_DB_URL=mongodb://$MONGO_USER:$DB_PASSWORD@localhost:27017/appsmith
#APPSMITH_DB_URL=postgresql://appsmith:$DB_PASSWORD@localhost:5432/postgres
APPSMITH_MONGODB_USER=$MONGO_USER
APPSMITH_MONGODB_PASSWORD=$MONGO_PASSWORD
APPSMITH_MONGODB_PASSWORD=$DB_PASSWORD
APPSMITH_API_BASE_URL=http://localhost:8080/api/v1

APPSMITH_REDIS_URL=redis://127.0.0.1:6379
Expand Down
Loading