You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
proxysql/test/infra/docker-pgsql16-single/docker-compose-init.bash

163 lines
6.4 KiB

#!/bin/bash
# RELIABLY CAPTURE INFRA_ID FROM ENVIRONMENT OR DIRECTORY NAME
if [ -z "${INFRA_ID}" ]; then
export INFRA_ID=$(basename $(dirname $(pwd)) | sed 's/infra-//; s/docker-//')
fi
# Final safety: if INFRA_ID is still empty or ".", use a default
if [ -z "${INFRA_ID}" ] || [ "${INFRA_ID}" = "." ]; then
export INFRA_ID="dev-$USER"
fi
# Derive Workspace relative to script
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
export WORKSPACE="${REPO_ROOT}"
set -e
set -o pipefail
# SUDO helper: empty if root
SUDO=""
if [ "$(id -u)" != "0" ]; then SUDO="sudo"; fi
# relaunch self with timeout
[[ $(ps -o command= $(ps -o ppid= $$)) =~ timeout ]] || exec timeout -v -s 9 ${TIMEOUT:-600} "${BASH_SOURCE}" "$@"
# make sure we have correct cwd
pushd $(dirname $0) &>/dev/null
trap 'popd &>/dev/null' EXIT
# Load .env but ensure INFRA_ID is preserved
if [ ! -f .env ]; then echo "Error: .env not found"; exit 1; fi
SAVED_INFRA_ID="${INFRA_ID}"
set -a; . .env; set +a
export INFRA_ID="${SAVED_INFRA_ID}"
# Docker Compose version helper - prefer plugin (v2)
COMPOSE_CMD="docker compose"
if ! $COMPOSE_CMD version &>/dev/null; then
COMPOSE_CMD="docker-compose"
if ! $COMPOSE_CMD version &>/dev/null; then
echo "ERROR: Neither 'docker compose' nor 'docker-compose' found!"
exit 1
fi
fi
if [ -z "${INFRA_ID}" ]; then echo "Error: INFRA_ID must be set"; exit 1; fi
export ROOT_PASSWORD=$(echo -n "${INFRA_ID}" | sha256sum | head -c 10)
export INFRA=${PWD##*/}
export COMPOSE_PROJECT="${INFRA}-${INFRA_ID}"
export INFRA_LOGS_PATH=${INFRA_LOGS_PATH:-${WORKSPACE}/ci_infra_logs}
echo "================================================================================"
echo "Initializing CI Infra '${INFRA}' (Project: ${COMPOSE_PROJECT}) ..."
echo "================================================================================"
# 1. VERIFY NO EXISTING CONTAINERS ARE RUNNING FOR THIS PROJECT
if [ -n "$($COMPOSE_CMD -p "${COMPOSE_PROJECT}" ps -q 2>/dev/null)" ]; then
echo "ERROR: Containers for project ${COMPOSE_PROJECT} are already running."
echo "Please run teardown first."
exit 1
fi
# 2. Infrastructure-specific preparation (logs/data)
# We extract host paths that appear to be for logs or data.
echo "Scanning for volumes in docker-compose.yml..."
# CRITICAL: Exclude .crt and .key files from auto-mkdir logic to prevent "directory vs file" conflicts
MOUNTED_PATHS=$(grep -E '\$\{INFRA_LOGS_PATH\}|\./log/' docker-compose.yml | grep -vE "\.crt|\.key" | awk -F: '{print $1}' | sed 's/^[[:space:]-]*//' | sort -u || true)
for RAW_PATH in ${MOUNTED_PATHS}; do
# Skip relative paths that point to config files (e.g. ./conf/...)
if [[ "${RAW_PATH}" == "./conf/"* ]]; then continue; fi
# Expand variables like ${INFRA_LOGS_PATH} and ${COMPOSE_PROJECT}
eval "ACTUAL_PATH=${RAW_PATH}"
# Safety: Refuse to proceed if ACTUAL_PATH is a directory and is not empty
if [ -d "${ACTUAL_PATH}" ] && [ "$(ls -A "${ACTUAL_PATH}" 2>/dev/null)" ]; then
echo "ERROR: Directory '${ACTUAL_PATH}' is not empty."
echo "Please run teardown/cleanup first."
exit 1
fi
echo "Preparing directory: ${ACTUAL_PATH}"
$SUDO mkdir -p "${ACTUAL_PATH}"
$SUDO chmod -R 777 "${ACTUAL_PATH}"
# Aggressive postgres fix: UID 999
if [[ "${ACTUAL_PATH}" == *pgsql* ]] || [[ "${ACTUAL_PATH}" == *pgdb* ]]; then
echo "Applying postgres ownership (999:999) to ${ACTUAL_PATH}"
$SUDO chown -R 999:999 "${ACTUAL_PATH}"
fi
done
# 3. Inject dynamic variables into Orchestrator configs
if [ -d "./conf/orchestrator" ]; then
echo "Patching Orchestrator configurations..."
find ./conf/orchestrator -name "orchestrator.conf.json" -exec sed -i "s/\"MySQLTopologyPassword\": \".*\"/\"MySQLTopologyPassword\": \"${ROOT_PASSWORD}\"/g" {} +
find ./conf/orchestrator -name "orchestrator.conf.json" -exec sed -i "s/\${INFRA}/${INFRA}/g" {} +
fi
# 4. TRANSIENT SSL SETUP (Avoiding repo permission changes)
# We copy SSL files to a transient location and apply strict permissions there.
SSL_SRC="./conf/pgsql/ssl"
if [ -d "${SSL_SRC}" ]; then
SSL_DST="${INFRA_LOGS_PATH}/${COMPOSE_PROJECT}/ssl"
echo "Preparing transient SSL directory: ${SSL_DST}"
$SUDO mkdir -p "${SSL_DST}"
# SAFETY: Remove any directories that were mistakenly created with file names
[ -d "${SSL_DST}/server.crt" ] && $SUDO rm -rf "${SSL_DST}/server.crt" || true
[ -d "${SSL_DST}/server.key" ] && $SUDO rm -rf "${SSL_DST}/server.key" || true
$SUDO cp -rp "${SSL_SRC}/." "${SSL_DST}/"
# Strict permissions for postgres on the copies only
$SUDO chmod 0640 "${SSL_DST}/server.key" 2>/dev/null || true
$SUDO chown -R 0:999 "${SSL_DST}" 2>/dev/null || true
fi
# 5. Create a temporary env file for docker-compose to ensure it sees our variables
ENV_FILE=".env.isolated.${INFRA_ID}"
cat <<ENVEOF > "${ENV_FILE}"
INFRA_ID=${INFRA_ID}
ROOT_PASSWORD=${ROOT_PASSWORD}
INFRA=${INFRA}
COMPOSE_PROJECT=${COMPOSE_PROJECT}
INFRA_LOGS_PATH=${INFRA_LOGS_PATH}
ENVEOF
# 6. START CONTAINERS
if ! $COMPOSE_CMD --env-file .env --env-file "${ENV_FILE}" -p "${COMPOSE_PROJECT}" up -d; then
echo "ERROR: Docker Compose failed"; rm -f "${ENV_FILE}"; exit 1
fi
rm -f "${ENV_FILE}"
# 7. VERIFY ALL CONTAINERS STARTED SUCCESSFULLY
echo "Verifying container health..."
PROJECT_CONTAINERS=$($COMPOSE_CMD -p "${COMPOSE_PROJECT}" ps --format '{{.Name}}')
for C in ${PROJECT_CONTAINERS}; do
STATE=$(docker inspect -f '{{.State.Running}}' "${C}" 2>/dev/null || echo "false")
if [ "${STATE}" != "true" ]; then
echo -e "\nERROR: Container ${C} failed to start!"
echo ">>> Container Logs:"
docker logs "${C}" | tail -n 50
exit 1
fi
done
if [ -f /.dockerenv ]; then
RUNNER_ID=$(hostname)
docker network connect "${INFRA_ID}_backend" "${RUNNER_ID}" || true
fi
# 8. Run post-scripts if they exist
sleep 2 # wait a bit for engines to start
[ -f ./bin/docker-wait-pgsql.bash ] && ./bin/docker-wait-pgsql.bash
[ -f ./bin/docker-mysql-post.bash ] && ./bin/docker-mysql-post.bash
[ -f ./bin/docker-pgsql-post.bash ] && ./bin/docker-pgsql-post.bash
[ -f ./bin/docker-orchestrator-post.bash ] && ./bin/docker-orchestrator-post.bash
[ -f ./bin/docker-proxy-post.bash ] && ./bin/docker-proxy-post.bash "$1"
echo "================================================================================"
echo "Done."
echo "================================================================================"