diff --git a/_unit-test/migrate-pgbouncer-test.sh b/_unit-test/migrate-pgbouncer-test.sh new file mode 100755 index 00000000000..b78ee633c04 --- /dev/null +++ b/_unit-test/migrate-pgbouncer-test.sh @@ -0,0 +1,197 @@ +#!/usr/bin/env bash + +source _unit-test/_test_setup.sh +source install/dc-detect-version.sh + +source install/ensure-files-from-examples.sh +cp $SENTRY_CONFIG_PY /tmp/sentry_conf_py +# Set the flag to apply automatic updates +export APPLY_AUTOMATIC_CONFIG_UPDATES=1 + +# Declare expected content +expected_db_config=$( + cat <<'EOF' +DATABASES = { + "default": { + "ENGINE": "sentry.db.postgres", + "NAME": "postgres", + "USER": "postgres", + "PASSWORD": "", + "HOST": "pgbouncer", + "PORT": "", + } +} +EOF +) + +echo "Test 1 (pre 25.9.0 release)" +# Modify the `DATABASES = {` to the next `}` line, with: +# DATABASES = { +# "default": { +# "ENGINE": "sentry.db.postgres", +# "NAME": "postgres", +# "USER": "postgres", +# "PASSWORD": "", +# "HOST": "postgres", +# "PORT": "", +# } +# } + +# Create the replacement text in a temp file +cat >/tmp/sentry_conf_py_db_config <<'EOF' +DATABASES = { + "default": { + "ENGINE": "sentry.db.postgres", + "NAME": "postgres", + "USER": "postgres", + "PASSWORD": "", + "HOST": "postgres", + "PORT": "", + } +} +EOF + +# Replace the block +sed -i '/^DATABASES = {$/,/^}$/{ + /^DATABASES = {$/r /tmp/sentry_conf_py_db_config + d +}' $SENTRY_CONFIG_PY + +# Clean up +rm /tmp/sentry_conf_py_db_config + +source install/migrate-pgbouncer.sh + +# Extract actual content +actual_db_config=$(sed -n '/^DATABASES = {$/,/^}$/p' $SENTRY_CONFIG_PY) + +# Compare +if [ "$actual_db_config" = "$expected_db_config" ]; then + echo "DATABASES section is correct" +else + echo "DATABASES section does not match" + echo "Expected:" + echo "$expected_db_config" + echo "Actual:" + echo "$actual_db_config" + exit 1 +fi + +# Reset the file +rm $SENTRY_CONFIG_PY +cp /tmp/sentry_conf_py $SENTRY_CONFIG_PY + +echo "Test 2 (post 25.9.0 release)" +# Modify the `DATABASES = {` to the next `}` line, with: +# DATABASES = { +# "default": { +# "ENGINE": "sentry.db.postgres", +# "NAME": "postgres", +# "USER": "postgres", +# "PASSWORD": "", +# "HOST": "pgbouncer", +# "PORT": "", +# } +# } + +# Create the replacement text in a temp file +cat >/tmp/sentry_conf_py_db_config <<'EOF' +DATABASES = { + "default": { + "ENGINE": "sentry.db.postgres", + "NAME": "postgres", + "USER": "postgres", + "PASSWORD": "", + "HOST": "pgbouncer", + "PORT": "", + } +} +EOF + +# Replace the block +sed -i '/^DATABASES = {$/,/^}$/{ + /^DATABASES = {$/r /tmp/sentry_conf_py_db_config + d +}' $SENTRY_CONFIG_PY + +# Clean up +rm /tmp/sentry_conf_py_db_config + +source install/migrate-pgbouncer.sh + +# Extract actual content +actual_db_config=$(sed -n '/^DATABASES = {$/,/^}$/p' $SENTRY_CONFIG_PY) + +# Compare +if [ "$actual_db_config" = "$expected_db_config" ]; then + echo "DATABASES section is correct" +else + echo "DATABASES section does not match" + echo "Expected:" + echo "$expected_db_config" + echo "Actual:" + echo "$actual_db_config" + exit 1 +fi + +# Reset the file +rm $SENTRY_CONFIG_PY +cp /tmp/sentry_conf_py $SENTRY_CONFIG_PY + +echo "Test 3 (custom postgres config)" +# Modify the `DATABASES = {` to the next `}` line, with: +# DATABASES = { +# "default": { +# "ENGINE": "sentry.db.postgres", +# "NAME": "postgres", +# "USER": "sentry", +# "PASSWORD": "sentry", +# "HOST": "postgres.internal", +# "PORT": "5432", +# } +# } + +# Create the replacement text in a temp file +cat >/tmp/sentry_conf_py_db_config <<'EOF' +DATABASES = { + "default": { + "ENGINE": "sentry.db.postgres", + "NAME": "postgres", + "USER": "sentry", + "PASSWORD": "sentry", + "HOST": "postgres.internal", + "PORT": "5432", + } +} +EOF + +# Replace the block +sed -i '/^DATABASES = {$/,/^}$/{ + /^DATABASES = {$/r /tmp/sentry_conf_py_db_config + d +}' $SENTRY_CONFIG_PY + +# Clean up +rm /tmp/sentry_conf_py_db_config + +source install/migrate-pgbouncer.sh + +# Extract actual content +actual_db_config=$(sed -n '/^DATABASES = {$/,/^}$/p' $SENTRY_CONFIG_PY) + +# THe file should NOT be modified +if [ "$actual_db_config" = "$expected_db_config" ]; then + echo "DATABASES section SHOULD NOT be modified" + echo "Expected:" + echo "$expected_db_config" + echo "Actual:" + echo "$actual_db_config" + exit 1 +else + echo "DATABASES section is correct" +fi + +# Remove the file +rm $SENTRY_CONFIG_PY /tmp/sentry_conf_py + +report_success diff --git a/install/migrate-pgbouncer.sh b/install/migrate-pgbouncer.sh new file mode 100644 index 00000000000..8c698c72d92 --- /dev/null +++ b/install/migrate-pgbouncer.sh @@ -0,0 +1,82 @@ +echo "${_group}Migrating Postgres config to PGBouncer..." +# If users has this EXACT configuration on their `sentry.conf.py` file: +# ```python +# DATABASES = { +# "default": { +# "ENGINE": "sentry.db.postgres", +# "NAME": "postgres", +# "USER": "postgres", +# "PASSWORD": "", +# "HOST": "postgres", +# "PORT": "", +# } +# } +# ``` +# We need to migrate it to this configuration: +# ```python +# DATABASES = { +# "default": { +# "ENGINE": "sentry.db.postgres", +# "NAME": "postgres", +# "USER": "postgres", +# "PASSWORD": "", +# "HOST": "pgbouncer", +# "PORT": "", +# } +# } +# ``` + +if sed -n '/^DATABASES = {$/,/^}$/p' "$SENTRY_CONFIG_PY" | grep -q '"HOST": "postgres"'; then + apply_config_changes_pgbouncer=0 + if [[ -z "${APPLY_AUTOMATIC_CONFIG_UPDATES:-}" ]]; then + echo + echo "We added PGBouncer to the default Compose stack, and to use that" + echo "you will need to modify your sentry.conf.py file contents." + echo "Do you want us to make this change automatically for you?" + echo + + yn="" + until [ ! -z "$yn" ]; do + read -p "y or n? " yn + case $yn in + y | yes | 1) + export apply_config_changes_pgbouncer=1 + echo + echo -n "Thank you." + ;; + n | no | 0) + export apply_config_changes_pgbouncer=0 + echo + echo -n "Alright, you will need to update your sentry.conf.py file manually before running 'docker compose up' or remove the $(pgbouncer) service if you don't want to use that." + ;; + *) yn="" ;; + esac + done + + echo + echo "To avoid this prompt in the future, use one of these flags:" + echo + echo " --apply-automatic-config-updates" + echo " --no-apply-automatic-config-updates" + echo + echo "or set the APPLY_AUTOMATIC_CONFIG_UPDATES environment variable:" + echo + echo " APPLY_AUTOMATIC_CONFIG_UPDATES=1 to apply automatic updates" + echo " APPLY_AUTOMATIC_CONFIG_UPDATES=0 to not apply automatic updates" + echo + sleep 5 + fi + + if [[ "$APPLY_AUTOMATIC_CONFIG_UPDATES" == 1 || "$apply_config_changes_pgbouncer" == 1 ]]; then + echo "Migrating $SENTRY_CONFIG_PY to use PGBouncer" + sed -i 's/"HOST": "postgres"/"HOST": "pgbouncer"/' "$SENTRY_CONFIG_PY" + echo "Migrated $SENTRY_CONFIG_PY to use PGBouncer" + fi +elif sed -n '/^DATABASES = {$/,/^}$/p' "$SENTRY_CONFIG_PY" | grep -q '"HOST": "pgbouncer"'; then + echo "Found pgbouncer in $SENTRY_CONFIG_PY, I'm assuming you're good! :)" +else + echo "⚠️ You don't have standard configuration for Postgres in $SENTRY_CONFIG_PY, skipping pgbouncer migration. I'm assuming you know what you're doing." + echo " For more information about PGBouncer, refer to https://github.com/getsentry/self-hosted/pull/3884" +fi + +echo "${_endgroup}" diff --git a/install/parse-cli.sh b/install/parse-cli.sh index b342033ca08..aec899c6398 100644 --- a/install/parse-cli.sh +++ b/install/parse-cli.sh @@ -31,6 +31,10 @@ Options: self-hosted instance upstream to Sentry. --container-engine-podman Use podman as the container engine. + --apply-automatic-config-updates + Apply automatic config file updates. + --no-apply-automatic-config-updates + Do not apply automatic config file updates. EOF } @@ -41,6 +45,7 @@ depwarn() { if [ ! -z "${SKIP_USER_PROMPT:-}" ]; then depwarn "SKIP_USER_PROMPT variable" "SKIP_USER_CREATION" SKIP_USER_CREATION="${SKIP_USER_PROMPT}" + APPLY_AUTOMATIC_CONFIG_UPDATES="${SKIP_USER_PROMPT}" fi SKIP_USER_CREATION="${SKIP_USER_CREATION:-}" @@ -49,6 +54,7 @@ SKIP_COMMIT_CHECK="${SKIP_COMMIT_CHECK:-}" REPORT_SELF_HOSTED_ISSUES="${REPORT_SELF_HOSTED_ISSUES:-}" SKIP_SSE42_REQUIREMENTS="${SKIP_SSE42_REQUIREMENTS:-}" CONTAINER_ENGINE_PODMAN="${CONTAINER_ENGINE_PODMAN:-}" +APPLY_AUTOMATIC_CONFIG_UPDATES="${APPLY_AUTOMATIC_CONFIG_UPDATES:-}" while (($#)); do case "$1" in @@ -71,6 +77,8 @@ while (($#)); do --no-report-self-hosted-issues) REPORT_SELF_HOSTED_ISSUES=0 ;; --skip-sse42-requirements) SKIP_SSE42_REQUIREMENTS=1 ;; --container-engine-podman) CONTAINER_ENGINE_PODMAN=1 ;; + --apply-automatic-config-updates) APPLY_AUTOMATIC_CONFIG_UPDATES=1 ;; + --no-apply-automatic-config-updates) APPLY_AUTOMATIC_CONFIG_UPDATES=0 ;; --) ;; *) echo "Unexpected argument: $1. Use --help for usage information."