Files
dc-observatio/create_bd/create-service-dbs.sh
T
Дмитрий Соловьев c3a1a8b4a1 Add PCP architecture docs and TGU ops updates
Capture current PCP architecture notes, service-map prototypes, TGU operations UI/map work, local configuration updates, database helper scripts, and request/sample JSON artifacts.
2026-05-30 14:18:19 +03:00

286 lines
6.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
NAMESPACE="${NAMESPACE:-pcp-dev}"
POSTGRES_SERVICE="${POSTGRES_SERVICE:-pcp-postgres}"
CLUSTER_DOMAIN="${CLUSTER_DOMAIN:-altum.local}"
POSTGRES_IMAGE="${POSTGRES_IMAGE:-postgis/postgis:15-3.3}"
ADMIN_SECRET="${ADMIN_SECRET:-pcp-postgres-admin}"
ADMIN_PASSWORD_KEY="${ADMIN_PASSWORD_KEY:-POSTGRES_PASSWORD}"
POSTGRES_HOST="${POSTGRES_SERVICE}.${NAMESPACE}.svc.${CLUSTER_DOMAIN}"
usage() {
cat <<EOF
Usage:
$0 <db_name> [db_name...]
$0 -f databases.txt
Examples:
$0 pcp_satellite_catalog pcp_ballistics
cat > databases.txt <<LIST
pcp_satellite_catalog
pcp_ballistics
pcp_requests
LIST
$0 -f databases.txt
Environment overrides:
NAMESPACE=pcp-dev
POSTGRES_SERVICE=pcp-postgres
CLUSTER_DOMAIN=altum.local
POSTGRES_IMAGE=postgis/postgis:15-3.3
EOF
}
require_command() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "ERROR: required command not found: $1" >&2
exit 1
fi
}
validate_db_name() {
local db_name="$1"
if [[ ! "$db_name" =~ ^[a-z][a-z0-9_]*$ ]]; then
echo "ERROR: invalid database name: $db_name" >&2
echo "Allowed format: lowercase letters, digits, underscore; must start with a letter." >&2
exit 1
fi
}
secret_name_for_db() {
local db_name="$1"
local dashed="${db_name//_/-}"
echo "${dashed}-db"
}
user_name_for_db() {
local db_name="$1"
echo "${db_name}_user"
}
make_pod_name() {
local prefix="$1"
local db_name="$2"
local safe="${db_name//_/-}"
safe="${safe:0:35}"
echo "${prefix}-${safe}-${RANDOM}${RANDOM}"
}
get_admin_password() {
kubectl -n "$NAMESPACE" get secret "$ADMIN_SECRET" \
-o jsonpath="{.data.${ADMIN_PASSWORD_KEY}}" | base64 -d
}
get_or_create_service_password() {
local secret_name="$1"
if kubectl -n "$NAMESPACE" get secret "$secret_name" >/dev/null 2>&1; then
kubectl -n "$NAMESPACE" get secret "$secret_name" \
-o jsonpath='{.data.SPRING_DATASOURCE_PASSWORD}' | base64 -d
else
openssl rand -base64 32 | tr -d '/+=' | head -c 32
fi
}
create_database_and_user() {
local db_name="$1"
local db_user="$2"
local db_password="$3"
local admin_password="$4"
local pod_name
pod_name="$(make_pod_name "psql-create" "$db_name")"
echo "Creating/updating database and user:"
echo " database: $db_name"
echo " user: $db_user"
kubectl -n "$NAMESPACE" run --rm -i "$pod_name" \
--image="$POSTGRES_IMAGE" \
--restart=Never \
--env="PGPASSWORD=$admin_password" \
--command -- psql \
-h "$POSTGRES_HOST" \
-U postgres \
-d postgres <<SQL
DO \$\$
BEGIN
IF NOT EXISTS (
SELECT FROM pg_roles WHERE rolname = '$db_user'
) THEN
CREATE ROLE "$db_user" LOGIN PASSWORD '$db_password';
ELSE
ALTER ROLE "$db_user" WITH LOGIN PASSWORD '$db_password';
END IF;
END
\$\$;
SELECT 'CREATE DATABASE "$db_name" OWNER "$db_user"'
WHERE NOT EXISTS (
SELECT FROM pg_database WHERE datname = '$db_name'
) \gexec
ALTER DATABASE "$db_name" OWNER TO "$db_user";
GRANT CONNECT ON DATABASE "$db_name" TO "$db_user";
SQL
}
enable_postgis() {
local db_name="$1"
local db_user="$2"
local admin_password="$3"
local pod_name
pod_name="$(make_pod_name "psql-postgis" "$db_name")"
echo "Enabling PostGIS:"
echo " database: $db_name"
kubectl -n "$NAMESPACE" run --rm -i "$pod_name" \
--image="$POSTGRES_IMAGE" \
--restart=Never \
--env="PGPASSWORD=$admin_password" \
--command -- psql \
-h "$POSTGRES_HOST" \
-U postgres \
-d "$db_name" <<SQL
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS postgis_topology;
ALTER SCHEMA public OWNER TO "$db_user";
GRANT USAGE, CREATE ON SCHEMA public TO "$db_user";
SQL
}
create_or_update_secret() {
local db_name="$1"
local db_user="$2"
local db_password="$3"
local secret_name="$4"
echo "Creating/updating Kubernetes Secret:"
echo " secret: $secret_name"
kubectl -n "$NAMESPACE" create secret generic "$secret_name" \
--from-literal=SPRING_DATASOURCE_USERNAME="$db_user" \
--from-literal=SPRING_DATASOURCE_PASSWORD="$db_password" \
--dry-run=client -o yaml | kubectl apply -f -
}
check_database() {
local db_name="$1"
local db_user="$2"
local db_password="$3"
local pod_name
pod_name="$(make_pod_name "psql-check" "$db_name")"
echo "Checking database:"
echo " database: $db_name"
echo " user: $db_user"
kubectl -n "$NAMESPACE" run --rm -i "$pod_name" \
--image="$POSTGRES_IMAGE" \
--restart=Never \
--env="PGPASSWORD=$db_password" \
--command -- psql \
-h "$POSTGRES_HOST" \
-U "$db_user" \
-d "$db_name" \
-c 'select current_database(), current_user, postgis_full_version();'
}
read_db_list() {
if [[ $# -eq 0 ]]; then
usage
exit 1
fi
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
usage
exit 0
fi
if [[ "$1" == "-f" || "$1" == "--file" ]]; then
if [[ $# -ne 2 ]]; then
echo "ERROR: file path is required after $1" >&2
exit 1
fi
local file="$2"
if [[ ! -f "$file" ]]; then
echo "ERROR: file not found: $file" >&2
exit 1
fi
grep -vE '^\s*($|#)' "$file"
else
printf '%s\n' "$@"
fi
}
main() {
require_command kubectl
require_command openssl
require_command base64
echo "Namespace: $NAMESPACE"
echo "Postgres host: $POSTGRES_HOST"
echo "Postgres image: $POSTGRES_IMAGE"
echo "Admin secret: $ADMIN_SECRET"
echo
local admin_password
admin_password="$(get_admin_password)"
mapfile -t databases < <(read_db_list "$@")
if [[ "${#databases[@]}" -eq 0 ]]; then
echo "ERROR: database list is empty" >&2
exit 1
fi
for db_name in "${databases[@]}"; do
validate_db_name "$db_name"
local db_user
local secret_name
local db_password
local jdbc_url
db_user="$(user_name_for_db "$db_name")"
secret_name="$(secret_name_for_db "$db_name")"
db_password="$(get_or_create_service_password "$secret_name")"
jdbc_url="jdbc:postgresql://${POSTGRES_HOST}:5432/${db_name}"
echo
echo "============================================================"
echo "Processing database: $db_name"
echo "============================================================"
create_database_and_user "$db_name" "$db_user" "$db_password" "$admin_password"
enable_postgis "$db_name" "$db_user" "$admin_password"
create_or_update_secret "$db_name" "$db_user" "$db_password" "$secret_name"
check_database "$db_name" "$db_user" "$db_password"
echo
echo "Done:"
echo " database: $db_name"
echo " user: $db_user"
echo " secret: $secret_name"
echo " JDBC URL: $jdbc_url"
done
echo
echo "All databases processed successfully."
}
main "$@"