#!/bin/bash set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SECRETS_DIR="${SCRIPT_DIR}/secrets" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } usage() { echo "Usage: $0 " echo "" echo "Commands:" echo " init Initialize secrets directory with AppRole credentials" echo " start Start the application (migrations run automatically)" echo " stop Stop the application" echo " restart Safe restart (down + up, preserves startup order)" echo " logs View application logs" echo " rebuild Rebuild and restart (migrations run automatically)" echo " rebuild --no-cache Force full rebuild without Docker cache" echo "" echo "WARNING: Do not use 'docker compose restart ' directly!" echo " This breaks service dependencies. Always use './setup.sh restart'" echo "" echo "Environment variables (for init):" echo " VAULT_APP_ROLE_ID AppRole ID for nexus app runtime" echo " VAULT_APP_SECRET_ID AppRole Secret ID for nexus app runtime" echo " VAULT_MIGRATE_ROLE_ID AppRole ID for nexus migrations" echo " VAULT_MIGRATE_SECRET_ID AppRole Secret ID for nexus migrations" echo " VAULT_KRATOS_APP_ROLE_ID AppRole ID for kratos runtime" echo " VAULT_KRATOS_APP_SECRET_ID AppRole Secret ID for kratos runtime" echo " VAULT_KRATOS_MIGRATE_ROLE_ID AppRole ID for kratos migrations" echo " VAULT_KRATOS_MIGRATE_SECRET_ID AppRole Secret ID for kratos migrations" echo " VAULT_OATHKEEPER_ROLE_ID AppRole ID for oathkeeper runtime" echo " VAULT_OATHKEEPER_SECRET_ID AppRole Secret ID for oathkeeper runtime" } init_secrets() { log_info "Initializing secrets directory..." # Create directories for all services mkdir -p "${SECRETS_DIR}/app" "${SECRETS_DIR}/migrate" mkdir -p "${SECRETS_DIR}/kratos-app" "${SECRETS_DIR}/kratos-migrate" mkdir -p "${SECRETS_DIR}/oathkeeper" mkdir -p "${SCRIPT_DIR}/run/app" "${SCRIPT_DIR}/run/migrate" mkdir -p "${SCRIPT_DIR}/run/kratos" "${SCRIPT_DIR}/run/kratos-migrate" mkdir -p "${SCRIPT_DIR}/run/oathkeeper" # Check for required nexus environment variables if [ -z "$VAULT_APP_ROLE_ID" ] || [ -z "$VAULT_APP_SECRET_ID" ]; then log_error "VAULT_APP_ROLE_ID and VAULT_APP_SECRET_ID must be set" exit 1 fi if [ -z "$VAULT_MIGRATE_ROLE_ID" ] || [ -z "$VAULT_MIGRATE_SECRET_ID" ]; then log_error "VAULT_MIGRATE_ROLE_ID and VAULT_MIGRATE_SECRET_ID must be set" exit 1 fi # Check for required kratos environment variables if [ -z "$VAULT_KRATOS_APP_ROLE_ID" ] || [ -z "$VAULT_KRATOS_APP_SECRET_ID" ]; then log_error "VAULT_KRATOS_APP_ROLE_ID and VAULT_KRATOS_APP_SECRET_ID must be set" exit 1 fi if [ -z "$VAULT_KRATOS_MIGRATE_ROLE_ID" ] || [ -z "$VAULT_KRATOS_MIGRATE_SECRET_ID" ]; then log_error "VAULT_KRATOS_MIGRATE_ROLE_ID and VAULT_KRATOS_MIGRATE_SECRET_ID must be set" exit 1 fi # Check for required oathkeeper environment variables if [ -z "$VAULT_OATHKEEPER_ROLE_ID" ] || [ -z "$VAULT_OATHKEEPER_SECRET_ID" ]; then log_error "VAULT_OATHKEEPER_ROLE_ID and VAULT_OATHKEEPER_SECRET_ID must be set" exit 1 fi # Write nexus app credentials (644 for container read access) echo -n "$VAULT_APP_ROLE_ID" > "${SECRETS_DIR}/app/role-id" echo -n "$VAULT_APP_SECRET_ID" > "${SECRETS_DIR}/app/secret-id" chmod 644 "${SECRETS_DIR}/app/role-id" "${SECRETS_DIR}/app/secret-id" log_info "Nexus app credentials written to ${SECRETS_DIR}/app/" # Write nexus migrate credentials (644 for container read access) echo -n "$VAULT_MIGRATE_ROLE_ID" > "${SECRETS_DIR}/migrate/role-id" echo -n "$VAULT_MIGRATE_SECRET_ID" > "${SECRETS_DIR}/migrate/secret-id" chmod 644 "${SECRETS_DIR}/migrate/role-id" "${SECRETS_DIR}/migrate/secret-id" log_info "Nexus migrate credentials written to ${SECRETS_DIR}/migrate/" # Write kratos app credentials (644 for container read access) echo -n "$VAULT_KRATOS_APP_ROLE_ID" > "${SECRETS_DIR}/kratos-app/role-id" echo -n "$VAULT_KRATOS_APP_SECRET_ID" > "${SECRETS_DIR}/kratos-app/secret-id" chmod 644 "${SECRETS_DIR}/kratos-app/role-id" "${SECRETS_DIR}/kratos-app/secret-id" log_info "Kratos app credentials written to ${SECRETS_DIR}/kratos-app/" # Write kratos migrate credentials (644 for container read access) echo -n "$VAULT_KRATOS_MIGRATE_ROLE_ID" > "${SECRETS_DIR}/kratos-migrate/role-id" echo -n "$VAULT_KRATOS_MIGRATE_SECRET_ID" > "${SECRETS_DIR}/kratos-migrate/secret-id" chmod 644 "${SECRETS_DIR}/kratos-migrate/role-id" "${SECRETS_DIR}/kratos-migrate/secret-id" log_info "Kratos migrate credentials written to ${SECRETS_DIR}/kratos-migrate/" # Write oathkeeper credentials (644 for container read access) echo -n "$VAULT_OATHKEEPER_ROLE_ID" > "${SECRETS_DIR}/oathkeeper/role-id" echo -n "$VAULT_OATHKEEPER_SECRET_ID" > "${SECRETS_DIR}/oathkeeper/secret-id" chmod 644 "${SECRETS_DIR}/oathkeeper/role-id" "${SECRETS_DIR}/oathkeeper/secret-id" log_info "Oathkeeper credentials written to ${SECRETS_DIR}/oathkeeper/" log_info "All secrets initialized successfully!" } start_app() { log_info "Starting application..." if [ ! -f "${SECRETS_DIR}/app/role-id" ]; then log_error "Nexus secrets not initialized. Run '$0 init' first." exit 1 fi if [ ! -f "${SECRETS_DIR}/kratos-app/role-id" ]; then log_error "Kratos secrets not initialized. Run '$0 init' first." exit 1 fi if [ ! -f "${SECRETS_DIR}/oathkeeper/role-id" ]; then log_error "Oathkeeper secrets not initialized. Run '$0 init' first." exit 1 fi # Start all services (migrations run automatically before app) docker compose up -d log_info "Application started!" log_info "Health checks:" log_info " Nexus: curl http://localhost:5050/health/ready" log_info " Kratos: curl http://localhost:6050/health/alive" log_info " Oathkeeper: curl http://localhost:7250/health/alive" log_info " Frontend: curl http://localhost:5000/" } stop_app() { log_info "Stopping application..." docker compose down log_info "Application stopped!" } restart_app() { log_info "Restarting application (safe restart)..." if [ ! -f "${SECRETS_DIR}/app/role-id" ]; then log_error "Nexus secrets not initialized. Run '$0 init' first." exit 1 fi # Safe restart: down then up preserves dependency order docker compose down docker compose up -d log_info "Application restarted!" log_info "Health checks:" log_info " Nexus: curl http://localhost:5050/health/ready" log_info " Kratos: curl http://localhost:6050/health/alive" log_info " Oathkeeper: curl http://localhost:7250/health/alive" log_info " Frontend: curl http://localhost:5000/" } rebuild_app() { local no_cache="${1:-}" if [ "$no_cache" = "--no-cache" ]; then log_info "Rebuilding without cache and restarting application..." else log_info "Rebuilding and restarting application..." fi if [ ! -f "${SECRETS_DIR}/app/role-id" ]; then log_error "Nexus secrets not initialized. Run '$0 init' first." exit 1 fi if [ ! -f "${SECRETS_DIR}/kratos-app/role-id" ]; then log_error "Kratos secrets not initialized. Run '$0 init' first." exit 1 fi if [ ! -f "${SECRETS_DIR}/oathkeeper/role-id" ]; then log_error "Oathkeeper secrets not initialized. Run '$0 init' first." exit 1 fi # Pull latest code git pull # Rebuild and restart (migrations run automatically) if [ "$no_cache" = "--no-cache" ]; then docker compose build --no-cache docker compose up -d else docker compose up -d --build fi log_info "Application rebuilt and started!" log_info "Health checks:" log_info " Nexus: curl http://localhost:5050/health/ready" log_info " Kratos: curl http://localhost:6050/health/alive" log_info " Oathkeeper: curl http://localhost:7250/health/alive" log_info " Frontend: curl http://localhost:5000/" } view_logs() { local service="${1:-}" if [ -z "$service" ]; then docker compose logs -f nexus kratos oathkeeper frontend else docker compose logs -f "$service" fi } # Main case "${1:-}" in init) init_secrets ;; start) start_app ;; stop) stop_app ;; restart) restart_app ;; rebuild) rebuild_app "${2:-}" ;; logs) view_logs ;; *) usage exit 1 ;; esac