644 lines
23 KiB
Bash
644 lines
23 KiB
Bash
#!/bin/bash
|
|
|
|
# Better signal handling - forward signals to child processes
|
|
trap 'kill -TERM $SERVER_PID; exit' TERM INT
|
|
|
|
set -eu
|
|
|
|
echo "==> Starting Ente Cloudron app..."
|
|
|
|
# Create necessary directories
|
|
mkdir -p /app/data/config /app/data/storage /app/data/go /app/data/logs
|
|
|
|
# Add comment about Cloudron filesystem limitations
|
|
echo "==> NOTE: Running in Cloudron environment with limited write access"
|
|
echo "==> Writable directories: /app/data, /tmp, /run"
|
|
|
|
# Define the server directory
|
|
SERVER_DIR="/app/code/server"
|
|
if [ ! -d "$SERVER_DIR" ]; then
|
|
if [ -d "/app/code/museum" ]; then
|
|
SERVER_DIR="/app/code/museum"
|
|
else
|
|
# Look for main.go in likely places
|
|
SERVER_DIR=$(dirname $(find /app/code -name "main.go" -path "*/server*" -o -path "*/museum*" | head -1))
|
|
if [ ! -d "$SERVER_DIR" ]; then
|
|
echo "==> WARNING: Could not find server directory, using /app/code as fallback"
|
|
SERVER_DIR="/app/code"
|
|
fi
|
|
fi
|
|
fi
|
|
echo "==> Using server directory: $SERVER_DIR"
|
|
|
|
# One-time initialization tracking
|
|
if [[ ! -f /app/data/.initialized ]]; then
|
|
echo "==> Fresh installation, setting up data directory..."
|
|
|
|
echo "==> DEBUG: Full repository structure at /app/code"
|
|
find /app/code -type d -maxdepth 3 -not -path "*/node_modules/*" -not -path "*/\.*" | sort
|
|
|
|
echo "==> DEBUG: Looking for Go files"
|
|
find /app/code -name "*.go" | grep -v test | sort | head -10
|
|
|
|
echo "==> DEBUG: Looking for server-related directories"
|
|
find /app/code -type d -path "*/server*" -o -path "*/museum*" | sort
|
|
|
|
echo "==> DEBUG: All package.json files in repository"
|
|
find /app/code -name "package.json" -not -path "*/node_modules/*" | sort
|
|
|
|
echo "==> DEBUG: Looking for web app directories"
|
|
find /app/code -type d -path "*/web*" | sort
|
|
|
|
echo "==> DEBUG: Web app directories in /app/web (if they exist)"
|
|
if [ -d "/app/web" ]; then
|
|
ls -la /app/web
|
|
else
|
|
echo "Web app directory not yet copied to /app/web"
|
|
fi
|
|
|
|
# Create config template file on first run
|
|
echo "==> First run - creating configuration template"
|
|
|
|
# Generate random secrets
|
|
JWT_SECRET=$(openssl rand -hex 32)
|
|
SESSION_SECRET=$(openssl rand -hex 32)
|
|
MASTER_KEY=$(openssl rand -hex 32)
|
|
|
|
# Replace variables in template for things we know
|
|
sed \
|
|
-e "s|%%POSTGRESQL_HOST%%|${CLOUDRON_POSTGRESQL_HOST}|g" \
|
|
-e "s|%%POSTGRESQL_PORT%%|${CLOUDRON_POSTGRESQL_PORT}|g" \
|
|
-e "s|%%POSTGRESQL_USERNAME%%|${CLOUDRON_POSTGRESQL_USERNAME}|g" \
|
|
-e "s|%%POSTGRESQL_PASSWORD%%|${CLOUDRON_POSTGRESQL_PASSWORD}|g" \
|
|
-e "s|%%POSTGRESQL_DATABASE%%|${CLOUDRON_POSTGRESQL_DATABASE}|g" \
|
|
-e "s|%%APP_ORIGIN%%|${CLOUDRON_APP_ORIGIN}|g" \
|
|
-e "s|%%MAIL_SMTP_SERVER%%|${CLOUDRON_MAIL_SMTP_SERVER}|g" \
|
|
-e "s|%%MAIL_SMTP_PORT%%|${CLOUDRON_MAIL_SMTP_PORT}|g" \
|
|
-e "s|%%MAIL_SMTP_USERNAME%%|${CLOUDRON_MAIL_SMTP_USERNAME}|g" \
|
|
-e "s|%%MAIL_SMTP_PASSWORD%%|${CLOUDRON_MAIL_SMTP_PASSWORD}|g" \
|
|
-e "s|%%MAIL_FROM%%|${CLOUDRON_MAIL_FROM}|g" \
|
|
-e "s|%%MAIL_FROM_DISPLAY_NAME%%|${CLOUDRON_MAIL_FROM_DISPLAY_NAME}|g" \
|
|
-e "s|%%JWT_SECRET%%|${JWT_SECRET}|g" \
|
|
-e "s|%%SESSION_SECRET%%|${SESSION_SECRET}|g" \
|
|
-e "s|%%MASTER_KEY%%|${MASTER_KEY}|g" \
|
|
/app/pkg/config.template.yaml > /app/data/config/config.yaml
|
|
|
|
# Create an S3 configuration file template
|
|
cat > /app/data/config/s3.env.template <<EOT
|
|
# S3 Configuration for Ente
|
|
# Please copy this file to s3.env and fill in your S3 credentials
|
|
|
|
# S3 endpoint URL (example: https://s3.amazonaws.com or https://s3.eu-central-2.wasabisys.com)
|
|
S3_ENDPOINT=https://your-s3-endpoint
|
|
|
|
# S3 region (example: us-east-1)
|
|
S3_REGION=your-region
|
|
|
|
# S3 bucket name
|
|
S3_BUCKET=your-bucket-name
|
|
|
|
# S3 access key
|
|
S3_ACCESS_KEY=your-access-key
|
|
|
|
# S3 secret key
|
|
S3_SECRET_KEY=your-secret-key
|
|
|
|
# Optional: prefix for objects within the bucket (example: ente/)
|
|
S3_PREFIX=
|
|
EOT
|
|
|
|
echo "==> IMPORTANT: S3 storage configuration required"
|
|
echo "==> Please configure your S3 storage as follows:"
|
|
echo "1. Log into your Cloudron dashboard"
|
|
echo "2. Go to the app's configuration page"
|
|
echo "3. Edit the file /app/data/config/s3.env"
|
|
echo "4. Restart the app"
|
|
|
|
# Mark initialization as complete
|
|
touch /app/data/.initialized
|
|
echo "==> Initialization complete"
|
|
fi
|
|
|
|
# Check if configuration exists
|
|
if [ ! -f "/app/data/config/s3.env" ]; then
|
|
echo "==> First run - creating configuration template"
|
|
mkdir -p /app/data/config
|
|
|
|
# Create a template S3 configuration file
|
|
echo "==> Creating S3 configuration template"
|
|
cat > /app/data/config/s3.env.template <<EOT
|
|
# S3 Configuration for Ente
|
|
# Please copy this file to s3.env and fill in your S3 credentials
|
|
|
|
# S3 endpoint URL (example: https://s3.amazonaws.com or https://s3.eu-central-2.wasabisys.com)
|
|
S3_ENDPOINT=https://your-s3-endpoint
|
|
|
|
# S3 region (example: us-east-1)
|
|
S3_REGION=your-region
|
|
|
|
# S3 bucket name
|
|
S3_BUCKET=your-bucket-name
|
|
|
|
# S3 access key
|
|
S3_ACCESS_KEY=your-access-key
|
|
|
|
# S3 secret key
|
|
S3_SECRET_KEY=your-secret-key
|
|
|
|
# Optional: prefix for objects within the bucket (example: ente/)
|
|
S3_PREFIX=
|
|
EOT
|
|
|
|
# Create an empty s3.env file to prevent errors
|
|
touch /app/data/config/s3.env
|
|
|
|
# Display an important notice about S3 configuration
|
|
echo "==> IMPORTANT: S3 storage configuration required"
|
|
echo "==> Please configure your S3 storage as follows:"
|
|
echo "1. Log into your Cloudron dashboard"
|
|
echo "2. Go to the app's configuration page"
|
|
echo "3. Edit the file /app/data/config/s3.env"
|
|
echo "4. Restart the app"
|
|
else
|
|
echo "==> Using existing S3 configuration"
|
|
fi
|
|
|
|
# Check if s3.env is empty
|
|
if [ ! -s "/app/data/config/s3.env" ]; then
|
|
echo "==> WARNING: S3 configuration file is empty. The app will not function correctly until configured."
|
|
echo "==> Please refer to the template at /app/data/config/s3.env.template for instructions."
|
|
fi
|
|
|
|
# Source S3 configuration
|
|
if [ -f /app/data/config/s3.env ]; then
|
|
echo "==> Sourcing S3 configuration from /app/data/config/s3.env"
|
|
source /app/data/config/s3.env
|
|
fi
|
|
|
|
# Display S3 configuration (masking sensitive values)
|
|
echo "==> S3 Configuration:"
|
|
echo "Endpoint: ${S3_ENDPOINT}"
|
|
echo "Region: ${S3_REGION}"
|
|
echo "Bucket: ${S3_BUCKET}"
|
|
echo "Prefix: ${S3_PREFIX:-}"
|
|
|
|
# Create museum.yaml for proper S3 configuration
|
|
echo "==> Creating museum.yaml configuration"
|
|
cat > /app/data/config/museum.yaml <<EOT
|
|
s3:
|
|
are_local_buckets: false
|
|
use_path_style_urls: true
|
|
s3-storage:
|
|
key: ${S3_ACCESS_KEY}
|
|
secret: ${S3_SECRET_KEY}
|
|
endpoint: ${S3_ENDPOINT}
|
|
region: ${S3_REGION}
|
|
bucket: ${S3_BUCKET}
|
|
EOT
|
|
echo "==> Created museum.yaml with S3 configuration"
|
|
|
|
# Update the config file with S3 credentials
|
|
sed -i \
|
|
-e "s|%%S3_ENDPOINT%%|${S3_ENDPOINT}|g" \
|
|
-e "s|%%S3_REGION%%|${S3_REGION}|g" \
|
|
-e "s|%%S3_BUCKET%%|${S3_BUCKET}|g" \
|
|
-e "s|%%S3_ACCESS_KEY%%|${S3_ACCESS_KEY}|g" \
|
|
-e "s|%%S3_SECRET_KEY%%|${S3_SECRET_KEY}|g" \
|
|
-e "s|%%S3_PREFIX%%|${S3_PREFIX:-}|g" \
|
|
/app/data/config/config.yaml
|
|
|
|
# Set storage type to S3 in config
|
|
sed -i 's|storage.type: "local"|storage.type: "s3"|g' /app/data/config/config.yaml
|
|
sed -i 's|s3.are_local_buckets: true|s3.are_local_buckets: false|g' /app/data/config/config.yaml
|
|
|
|
# Set up the API endpoint for the web apps
|
|
API_ENDPOINT="${CLOUDRON_APP_ORIGIN}/api"
|
|
echo "==> Setting API endpoint to $API_ENDPOINT"
|
|
|
|
# Set environment variables for the web apps
|
|
export ENTE_API_ENDPOINT=$API_ENDPOINT
|
|
export NEXT_PUBLIC_ENTE_ENDPOINT=$API_ENDPOINT
|
|
export REACT_APP_ENTE_ENDPOINT=$API_ENDPOINT
|
|
export VUE_APP_ENTE_ENDPOINT=$API_ENDPOINT
|
|
echo "==> Set environment variables for web apps"
|
|
|
|
# Create directory for configuration files
|
|
mkdir -p /app/data/public
|
|
mkdir -p /app/data/scripts
|
|
mkdir -p /app/data/logs
|
|
|
|
# Define ports
|
|
API_PORT=8080
|
|
|
|
# Check if ports are available
|
|
echo "==> Checking port availability"
|
|
if lsof -i:$API_PORT > /dev/null 2>&1; then
|
|
echo "==> WARNING: Port $API_PORT is already in use"
|
|
else
|
|
echo "==> Port $API_PORT is available for API server"
|
|
fi
|
|
|
|
# Determine available memory and set limits accordingly
|
|
if [[ -f /sys/fs/cgroup/cgroup.controllers ]]; then # cgroup v2
|
|
memory_limit=$(cat /sys/fs/cgroup/memory.max)
|
|
if [[ "$memory_limit" != "max" ]]; then
|
|
MEMORY_MB=$((memory_limit / 1024 / 1024))
|
|
else
|
|
MEMORY_MB=$(free -m | awk '/^Mem:/{print $2}')
|
|
fi
|
|
else # cgroup v1
|
|
if [ -f /sys/fs/cgroup/memory/memory.limit_in_bytes ]; then
|
|
memory_limit=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)
|
|
MEMORY_MB=$((memory_limit / 1024 / 1024))
|
|
else
|
|
MEMORY_MB=$(free -m | awk '/^Mem:/{print $2}')
|
|
fi
|
|
fi
|
|
|
|
echo "==> Available memory: ${MEMORY_MB}MB"
|
|
|
|
# Test database connectivity
|
|
echo "==> Checking database connectivity"
|
|
PGPASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}" psql -h ${CLOUDRON_POSTGRESQL_HOST} -p ${CLOUDRON_POSTGRESQL_PORT} -U ${CLOUDRON_POSTGRESQL_USERNAME} -d ${CLOUDRON_POSTGRESQL_DATABASE} -c "SELECT 1" > /dev/null
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "==> ERROR: Failed to connect to database"
|
|
echo "Host: ${CLOUDRON_POSTGRESQL_HOST}"
|
|
echo "Port: ${CLOUDRON_POSTGRESQL_PORT}"
|
|
echo "User: ${CLOUDRON_POSTGRESQL_USERNAME}"
|
|
echo "Database: ${CLOUDRON_POSTGRESQL_DATABASE}"
|
|
exit 1
|
|
fi
|
|
echo "==> Successfully connected to database"
|
|
|
|
# Create proper Go module environment
|
|
echo "==> Setting up Go module environment"
|
|
if [ -f "$SERVER_DIR/go.mod" ]; then
|
|
echo "==> Found go.mod in $SERVER_DIR"
|
|
mkdir -p /app/data/go
|
|
cp "$SERVER_DIR/go.mod" "/app/data/go/go.mod"
|
|
if [ -f "$SERVER_DIR/go.sum" ]; then
|
|
cp "$SERVER_DIR/go.sum" "/app/data/go/go.sum"
|
|
fi
|
|
echo "==> Copied go.mod to /app/data/go/go.mod"
|
|
else
|
|
echo "==> WARNING: No go.mod found in $SERVER_DIR"
|
|
# Create a minimal go.mod file
|
|
mkdir -p /app/data/go
|
|
cat > /app/data/go/go.mod <<EOT
|
|
module ente.io/museum
|
|
|
|
go 1.24
|
|
EOT
|
|
echo "==> Created minimal go.mod in /app/data/go/go.mod"
|
|
fi
|
|
# Ensure the right permissions
|
|
chmod 644 /app/data/go/go.mod
|
|
# Setup Go directories with proper permissions
|
|
mkdir -p /app/data/go/pkg/mod /app/data/go/cache
|
|
chmod -R 777 /app/data/go
|
|
chown -R cloudron:cloudron /app/data/go
|
|
|
|
# Set necessary environment variables - MOVED EARLIER IN THE SCRIPT
|
|
export MUSEUM_CONFIG="/app/data/config/museum.yaml"
|
|
export MUSEUM_DB_HOST="${CLOUDRON_POSTGRESQL_HOST}"
|
|
export MUSEUM_DB_PORT="${CLOUDRON_POSTGRESQL_PORT}"
|
|
export MUSEUM_DB_USER="${CLOUDRON_POSTGRESQL_USERNAME}"
|
|
export MUSEUM_DB_PASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}"
|
|
export MUSEUM_DB_NAME="${CLOUDRON_POSTGRESQL_DATABASE}"
|
|
export ENTE_LOG_LEVEL=debug
|
|
export GOMODCACHE="/app/data/go/pkg/mod"
|
|
export GOCACHE="/app/data/go/cache"
|
|
export GO111MODULE=on
|
|
export GOFLAGS="-modfile=/app/data/go/go.mod -mod=mod"
|
|
|
|
# Standard PostgreSQL environment variables (critical for Go's database/sql driver)
|
|
export PGHOST="${CLOUDRON_POSTGRESQL_HOST}"
|
|
export PGPORT="${CLOUDRON_POSTGRESQL_PORT}"
|
|
export PGUSER="${CLOUDRON_POSTGRESQL_USERNAME}"
|
|
export PGPASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}"
|
|
export PGDATABASE="${CLOUDRON_POSTGRESQL_DATABASE}"
|
|
export PGSSLMODE="disable"
|
|
|
|
# Try to modify hosts file to block localhost PostgreSQL connections (may not work in containers)
|
|
if [ -w /etc/hosts ]; then
|
|
echo "==> Adding entry to /etc/hosts to redirect localhost PostgreSQL"
|
|
echo "127.0.0.1 postgres-unavailable # Added by Ente startup script" >> /etc/hosts
|
|
echo "::1 postgres-unavailable # Added by Ente startup script" >> /etc/hosts
|
|
else
|
|
echo "==> Cannot modify /etc/hosts (read-only filesystem)"
|
|
fi
|
|
|
|
# Patch source code directly for maximum effectiveness
|
|
if [ -d "$SERVER_DIR/cmd/museum" ]; then
|
|
MAIN_GO="$SERVER_DIR/cmd/museum/main.go"
|
|
if [ -f "$MAIN_GO" ]; then
|
|
echo "==> Patching main.go to force correct database host"
|
|
|
|
# Create a backup of the original file
|
|
cp "$MAIN_GO" "${MAIN_GO}.orig"
|
|
|
|
# Look for setupDatabase function and patch it
|
|
DB_SETUP_LINE=$(grep -n "func setupDatabase" "$MAIN_GO" | cut -d: -f1)
|
|
|
|
if [ -n "$DB_SETUP_LINE" ]; then
|
|
echo "==> Found setupDatabase function at line $DB_SETUP_LINE"
|
|
|
|
# Insert code at the beginning of the function
|
|
sed -i "${DB_SETUP_LINE}a\\
|
|
\\tlog.Printf(\"Forcing database host to %s\", \"${CLOUDRON_POSTGRESQL_HOST}\")\\
|
|
\\tos.Setenv(\"PGHOST\", \"${CLOUDRON_POSTGRESQL_HOST}\")\\
|
|
\\tos.Setenv(\"PGHOSTADDR\", \"${CLOUDRON_POSTGRESQL_HOST}\")" "$MAIN_GO"
|
|
|
|
echo "==> Patched setupDatabase function"
|
|
fi
|
|
|
|
# If there's a connection string being built, patch that too
|
|
CONN_STR_LINE=$(grep -n "postgres://" "$MAIN_GO" | head -1 | cut -d: -f1)
|
|
if [ -n "$CONN_STR_LINE" ]; then
|
|
echo "==> Found connection string at line $CONN_STR_LINE"
|
|
|
|
# Backup again just to be safe
|
|
cp "$MAIN_GO" "${MAIN_GO}.conn_patch"
|
|
|
|
# Replace localhost or [::1] with the actual host
|
|
sed -i "s/localhost/${CLOUDRON_POSTGRESQL_HOST}/g" "$MAIN_GO"
|
|
sed -i "s/\[::1\]/${CLOUDRON_POSTGRESQL_HOST}/g" "$MAIN_GO"
|
|
|
|
echo "==> Patched connection string"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Fix database migration state if needed
|
|
echo "==> Checking database migration state"
|
|
if [ -d "$SERVER_DIR/cmd/museum" ]; then
|
|
echo "==> Attempting to fix dirty migration state"
|
|
|
|
# Create migrations log directory
|
|
mkdir -p /app/data/logs/migrations
|
|
|
|
echo "==> Forcing migration version to 25"
|
|
# Execute as the cloudron user but use a proper script instead of env cd
|
|
cat > /tmp/run_migration.sh <<EOF
|
|
#!/bin/bash
|
|
cd "$SERVER_DIR" && \
|
|
PGHOST="${CLOUDRON_POSTGRESQL_HOST}" \
|
|
PGPORT="${CLOUDRON_POSTGRESQL_PORT}" \
|
|
PGUSER="${CLOUDRON_POSTGRESQL_USERNAME}" \
|
|
PGPASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}" \
|
|
PGDATABASE="${CLOUDRON_POSTGRESQL_DATABASE}" \
|
|
PGSSLMODE="disable" \
|
|
ENTE_PG_HOST="${MUSEUM_DB_HOST}" \
|
|
ENTE_PG_PORT="${MUSEUM_DB_PORT}" \
|
|
ENTE_PG_USER="${MUSEUM_DB_USER}" \
|
|
ENTE_PG_PASSWORD="${MUSEUM_DB_PASSWORD}" \
|
|
ENTE_PG_DATABASE="${MUSEUM_DB_NAME}" \
|
|
ENTE_PG_DSN="postgres://${MUSEUM_DB_USER}:${MUSEUM_DB_PASSWORD}@${MUSEUM_DB_HOST}:${MUSEUM_DB_PORT}/${MUSEUM_DB_NAME}?sslmode=disable&host=${MUSEUM_DB_HOST}" \
|
|
CLOUDRON_POSTGRESQL_HOST="${CLOUDRON_POSTGRESQL_HOST}" \
|
|
CLOUDRON_POSTGRESQL_PORT="${CLOUDRON_POSTGRESQL_PORT}" \
|
|
CLOUDRON_POSTGRESQL_USERNAME="${CLOUDRON_POSTGRESQL_USERNAME}" \
|
|
CLOUDRON_POSTGRESQL_PASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}" \
|
|
CLOUDRON_POSTGRESQL_DATABASE="${CLOUDRON_POSTGRESQL_DATABASE}" \
|
|
go run -ldflags "-X 'github.com/lib/pq.defaulthost=${MUSEUM_DB_HOST}'" overrides/db_override.go cmd/museum/main.go db force 25
|
|
EOF
|
|
chmod +x /tmp/run_migration.sh
|
|
|
|
if /usr/local/bin/gosu cloudron:cloudron bash /tmp/run_migration.sh > /app/data/logs/migrations/force.log 2>&1; then
|
|
echo "==> Successfully forced migration version"
|
|
else
|
|
echo "==> WARNING: Could not force migration version"
|
|
echo "==> Migration force log:"
|
|
cat /app/data/logs/migrations/force.log || echo "==> No migration log was created"
|
|
fi
|
|
else
|
|
echo "==> Skipping migration state check: cmd/museum not found"
|
|
fi
|
|
|
|
# Start the Museum server with proper environment variables
|
|
echo "==> Starting Museum server"
|
|
cd "$SERVER_DIR"
|
|
|
|
# Check if there's a pre-built binary
|
|
MUSEUM_BIN=""
|
|
if [ -f "$SERVER_DIR/bin/museum" ] && [ -x "$SERVER_DIR/bin/museum" ]; then
|
|
echo "==> Found Museum binary at $SERVER_DIR/bin/museum"
|
|
MUSEUM_BIN="$SERVER_DIR/bin/museum"
|
|
elif [ -f "/app/data/go/bin/museum" ] && [ -x "/app/data/go/bin/museum" ]; then
|
|
echo "==> Found Museum binary at /app/data/go/bin/museum"
|
|
MUSEUM_BIN="/app/data/go/bin/museum"
|
|
fi
|
|
|
|
# Start server
|
|
if [ -n "$MUSEUM_BIN" ]; then
|
|
echo "==> Starting Museum from binary: $MUSEUM_BIN"
|
|
$MUSEUM_BIN serve > /app/data/logs/museum.log 2>&1 &
|
|
SERVER_PID=$!
|
|
elif [ -d "$SERVER_DIR/cmd/museum" ]; then
|
|
echo "==> Starting Museum from source"
|
|
# Create a startup script
|
|
cat > /tmp/run_server.sh <<EOF
|
|
#!/bin/bash
|
|
cd "$SERVER_DIR" && \
|
|
PGHOST="${CLOUDRON_POSTGRESQL_HOST}" \
|
|
PGPORT="${CLOUDRON_POSTGRESQL_PORT}" \
|
|
PGUSER="${CLOUDRON_POSTGRESQL_USERNAME}" \
|
|
PGPASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}" \
|
|
PGDATABASE="${CLOUDRON_POSTGRESQL_DATABASE}" \
|
|
PGSSLMODE="disable" \
|
|
ENTE_PG_HOST="${MUSEUM_DB_HOST}" \
|
|
ENTE_PG_PORT="${MUSEUM_DB_PORT}" \
|
|
ENTE_PG_USER="${MUSEUM_DB_USER}" \
|
|
ENTE_PG_PASSWORD="${MUSEUM_DB_PASSWORD}" \
|
|
ENTE_PG_DATABASE="${MUSEUM_DB_NAME}" \
|
|
ENTE_PG_DSN="postgres://${MUSEUM_DB_USER}:${MUSEUM_DB_PASSWORD}@${MUSEUM_DB_HOST}:${MUSEUM_DB_PORT}/${MUSEUM_DB_NAME}?sslmode=disable&host=${MUSEUM_DB_HOST}" \
|
|
CLOUDRON_POSTGRESQL_HOST="${CLOUDRON_POSTGRESQL_HOST}" \
|
|
CLOUDRON_POSTGRESQL_PORT="${CLOUDRON_POSTGRESQL_PORT}" \
|
|
CLOUDRON_POSTGRESQL_USERNAME="${CLOUDRON_POSTGRESQL_USERNAME}" \
|
|
CLOUDRON_POSTGRESQL_PASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}" \
|
|
CLOUDRON_POSTGRESQL_DATABASE="${CLOUDRON_POSTGRESQL_DATABASE}" \
|
|
go run -ldflags "-X 'github.com/lib/pq.defaulthost=${MUSEUM_DB_HOST}'" overrides/db_override.go cmd/museum/main.go serve
|
|
EOF
|
|
chmod +x /tmp/run_server.sh
|
|
|
|
/usr/local/bin/gosu cloudron:cloudron env \
|
|
GOCACHE="$GOCACHE" \
|
|
GOMODCACHE="$GOMODCACHE" \
|
|
GO111MODULE=on \
|
|
GOFLAGS="$GOFLAGS" \
|
|
MUSEUM_CONFIG="$MUSEUM_CONFIG" \
|
|
MUSEUM_DB_HOST="$MUSEUM_DB_HOST" \
|
|
MUSEUM_DB_PORT="$MUSEUM_DB_PORT" \
|
|
MUSEUM_DB_USER="$MUSEUM_DB_USER" \
|
|
MUSEUM_DB_PASSWORD="$MUSEUM_DB_PASSWORD" \
|
|
MUSEUM_DB_NAME="$MUSEUM_DB_NAME" \
|
|
ENTE_PG_DSN="postgres://${MUSEUM_DB_USER}:${MUSEUM_DB_PASSWORD}@${MUSEUM_DB_HOST}:${MUSEUM_DB_PORT}/${MUSEUM_DB_NAME}?sslmode=disable" \
|
|
ENTE_PG_HOST="$MUSEUM_DB_HOST" \
|
|
ENTE_PG_PORT="$MUSEUM_DB_PORT" \
|
|
ENTE_PG_USER="$MUSEUM_DB_USER" \
|
|
ENTE_PG_PASSWORD="$MUSEUM_DB_PASSWORD" \
|
|
ENTE_PG_DATABASE="$MUSEUM_DB_NAME" \
|
|
PGHOST="$PGHOST" \
|
|
PGPORT="$PGPORT" \
|
|
PGUSER="$PGUSER" \
|
|
PGPASSWORD="$PGPASSWORD" \
|
|
PGDATABASE="$PGDATABASE" \
|
|
PGSSLMODE="$PGSSLMODE" \
|
|
ENTE_LOG_LEVEL=debug \
|
|
bash /tmp/run_server.sh > /app/data/logs/museum.log 2>&1 &
|
|
SERVER_PID=$!
|
|
else
|
|
echo "==> ERROR: Museum server not found"
|
|
echo "==> Starting a mock server"
|
|
|
|
# Create a temporary directory for a simple Go server
|
|
mkdir -p /tmp/mock-server
|
|
cat > /tmp/mock-server/main.go <<EOT
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
func main() {
|
|
// Log environment variables
|
|
log.Println("Starting mock API server with environment variables:")
|
|
log.Println("MUSEUM_DB_HOST:", os.Getenv("MUSEUM_DB_HOST"))
|
|
log.Println("MUSEUM_DB_PORT:", os.Getenv("MUSEUM_DB_PORT"))
|
|
log.Println("MUSEUM_DB_USER:", os.Getenv("MUSEUM_DB_USER"))
|
|
log.Println("ENTE_PG_HOST:", os.Getenv("ENTE_PG_HOST"))
|
|
log.Println("ENTE_PG_DSN:", os.Getenv("ENTE_PG_DSN"))
|
|
log.Println("PGHOST:", os.Getenv("PGHOST"))
|
|
log.Println("PGPORT:", os.Getenv("PGPORT"))
|
|
log.Println("PGUSER:", os.Getenv("PGUSER"))
|
|
log.Println("PGDATABASE:", os.Getenv("PGDATABASE"))
|
|
log.Println("PGSSLMODE:", os.Getenv("PGSSLMODE"))
|
|
|
|
// Add a health endpoint
|
|
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
fmt.Fprint(w, `{"status":"ok","message":"Mock server running","time":"` + time.Now().String() + `"}`)
|
|
})
|
|
|
|
// Handle all other requests
|
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
log.Printf("Received request for %s via %s", r.URL.Path, r.Method)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
fmt.Fprintf(w, `{"status":"mock","endpoint":"%s","method":"%s","time":"%s"}`,
|
|
r.URL.Path, r.Method, time.Now().String())
|
|
})
|
|
|
|
// Start the server
|
|
log.Printf("Starting mock server on port 8080\n")
|
|
|
|
if err := http.ListenAndServe(":8080", nil); err != nil {
|
|
log.Fatalf("Failed to start server: %v", err)
|
|
}
|
|
}
|
|
EOT
|
|
|
|
# Run the mock server with environment variables
|
|
cd /tmp/mock-server
|
|
export ENTE_PG_HOST="${MUSEUM_DB_HOST}"
|
|
export ENTE_PG_PORT="${MUSEUM_DB_PORT}"
|
|
export ENTE_PG_USER="${MUSEUM_DB_USER}"
|
|
export ENTE_PG_PASSWORD="${MUSEUM_DB_PASSWORD}"
|
|
export ENTE_PG_DATABASE="${MUSEUM_DB_NAME}"
|
|
export ENTE_PG_DSN="postgres://${MUSEUM_DB_USER}:${MUSEUM_DB_PASSWORD}@${MUSEUM_DB_HOST}:${MUSEUM_DB_PORT}/${MUSEUM_DB_NAME}?sslmode=disable"
|
|
|
|
# Make sure we pass the standard PostgreSQL environment variables too
|
|
export PGHOST="${CLOUDRON_POSTGRESQL_HOST}"
|
|
export PGPORT="${CLOUDRON_POSTGRESQL_PORT}"
|
|
export PGUSER="${CLOUDRON_POSTGRESQL_USERNAME}"
|
|
export PGPASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}"
|
|
export PGDATABASE="${CLOUDRON_POSTGRESQL_DATABASE}"
|
|
export PGSSLMODE="disable"
|
|
|
|
go run main.go > /app/data/logs/museum.log 2>&1 &
|
|
SERVER_PID=$!
|
|
|
|
echo "==> Mock server started with PID $SERVER_PID"
|
|
fi
|
|
|
|
echo "==> Server started with PID $SERVER_PID"
|
|
|
|
# Test if API is responding
|
|
echo "==> Testing API connectivity"
|
|
for i in {1..5}; do
|
|
if curl -s --max-time 2 --fail http://localhost:$API_PORT/health > /dev/null; then
|
|
echo "==> API is responding on port $API_PORT"
|
|
break
|
|
else
|
|
if [ $i -eq 5 ]; then
|
|
echo "==> WARNING: API is not responding after several attempts"
|
|
echo "==> Last 20 lines of museum.log:"
|
|
tail -20 /app/data/logs/museum.log || echo "==> No museum.log available"
|
|
else
|
|
echo "==> Attempt $i: Waiting for API to start... (2 seconds)"
|
|
sleep 2
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo "==> Application is now running"
|
|
echo "==> Access your Ente instance at: $CLOUDRON_APP_ORIGIN"
|
|
|
|
echo "==> Entering wait state - press Ctrl+C to stop"
|
|
# Wait for all background processes to complete (or for user to interrupt)
|
|
wait $SERVER_PID
|
|
|
|
# Create a new go file to inject into the build that overrides the database connection
|
|
mkdir -p "$SERVER_DIR/overrides"
|
|
cat > "$SERVER_DIR/overrides/db_override.go" <<EOF
|
|
// Override database functions - will be added to museum build
|
|
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
_ "github.com/lib/pq" // Import the postgres driver
|
|
)
|
|
|
|
// This will run before main() and override the database functions
|
|
func init() {
|
|
log.Println("Database override patch is active")
|
|
|
|
host := os.Getenv("CLOUDRON_POSTGRESQL_HOST")
|
|
if host == "" {
|
|
host = os.Getenv("PGHOST")
|
|
}
|
|
|
|
if host == "" {
|
|
log.Println("WARNING: No PostgreSQL host found in environment, using default")
|
|
return
|
|
}
|
|
|
|
// Force the PGHOST environment variable
|
|
os.Setenv("PGHOST", host)
|
|
|
|
log.Printf("Forcing database connections to use host: %s", host)
|
|
}
|
|
|
|
// Force correct database setup - this will be called instead of the original setupDatabase
|
|
func forceCorrectDatabase() (*sql.DB, error) {
|
|
host := os.Getenv("CLOUDRON_POSTGRESQL_HOST")
|
|
port := os.Getenv("CLOUDRON_POSTGRESQL_PORT")
|
|
user := os.Getenv("CLOUDRON_POSTGRESQL_USERNAME")
|
|
password := os.Getenv("CLOUDRON_POSTGRESQL_PASSWORD")
|
|
dbname := os.Getenv("CLOUDRON_POSTGRESQL_DATABASE")
|
|
|
|
connStr := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
|
|
host, port, user, password, dbname)
|
|
|
|
log.Printf("Opening database connection with: %s", connStr)
|
|
return sql.Open("postgres", connStr)
|
|
}
|
|
EOF |