init_guac
This commit is contained in:
398
guacamole_test_11_26/deploy.sh
Executable file
398
guacamole_test_11_26/deploy.sh
Executable file
@ -0,0 +1,398 @@
|
||||
#!/bin/bash
|
||||
# Automated deployment for Remote Access API + Guacamole
|
||||
# with automatic secure administrator generation
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
echo "=========================================="
|
||||
echo " Remote Access API Deployment"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# Output colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[OK]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Check required commands
|
||||
check_requirements() {
|
||||
log_info "Checking requirements..."
|
||||
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_error "Docker not found! Please install Docker first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
log_error "Python 3 not found! Please install Python 3."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! docker compose version &> /dev/null; then
|
||||
log_error "Docker Compose V2 not found! Please install Docker Compose V2."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "All requirements met"
|
||||
}
|
||||
|
||||
# Load environment variables
|
||||
load_env() {
|
||||
log_info "Loading environment variables..."
|
||||
|
||||
if [ ! -f ".env" ] && [ ! -f "production.env" ]; then
|
||||
log_error "No .env or production.env file found!"
|
||||
log_error "Please create one from encryption.env.example or production.env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use production.env by default
|
||||
ENV_FILE=".env"
|
||||
if [ -f "production.env" ]; then
|
||||
ENV_FILE="production.env"
|
||||
log_info "Using production.env"
|
||||
fi
|
||||
|
||||
# Load variables
|
||||
set -a
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
|
||||
log_success "Environment loaded from $ENV_FILE"
|
||||
}
|
||||
|
||||
# Check critical passwords
|
||||
check_critical_passwords() {
|
||||
log_info "Checking critical passwords..."
|
||||
|
||||
local has_issues=0
|
||||
|
||||
# Check REDIS_PASSWORD
|
||||
if [ -z "$REDIS_PASSWORD" ] || [ "$REDIS_PASSWORD" == "redis_pass" ]; then
|
||||
log_error "REDIS_PASSWORD is not set or using default value!"
|
||||
log_error "Set a secure password in $ENV_FILE"
|
||||
has_issues=1
|
||||
fi
|
||||
|
||||
# Check POSTGRES_PASSWORD
|
||||
if [ -z "$POSTGRES_PASSWORD" ] || [ "$POSTGRES_PASSWORD" == "guacamole_pass" ]; then
|
||||
log_error "POSTGRES_PASSWORD is not set or using default value!"
|
||||
log_error "Set a secure password in $ENV_FILE"
|
||||
has_issues=1
|
||||
fi
|
||||
|
||||
# Check SYSTEM_ADMIN credentials
|
||||
if [ -z "$SYSTEM_ADMIN_USERNAME" ] || [ -z "$SYSTEM_ADMIN_PASSWORD" ]; then
|
||||
log_error "SYSTEM_ADMIN_USERNAME and SYSTEM_ADMIN_PASSWORD must be set!"
|
||||
log_error "Please update your $ENV_FILE file"
|
||||
has_issues=1
|
||||
fi
|
||||
|
||||
if [ $has_issues -eq 1 ]; then
|
||||
log_error ""
|
||||
log_error "Critical passwords are missing or insecure!"
|
||||
log_error "Update the following in $ENV_FILE:"
|
||||
log_error " - REDIS_PASSWORD=<secure_random_password>"
|
||||
log_error " - POSTGRES_PASSWORD=<secure_random_password>"
|
||||
log_error " - SYSTEM_ADMIN_PASSWORD=<secure_random_password>"
|
||||
log_error ""
|
||||
log_error "Generate secure passwords:"
|
||||
log_error " openssl rand -base64 32"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "All critical passwords are set"
|
||||
}
|
||||
|
||||
# Auto-generate admin if password is not default
|
||||
generate_admin_sql() {
|
||||
log_info "Checking admin credentials..."
|
||||
|
||||
# Check if default password is used
|
||||
if [ "$SYSTEM_ADMIN_PASSWORD" == "guacadmin" ] || \
|
||||
[ "$SYSTEM_ADMIN_PASSWORD" == "guacadmin_change_in_production" ] || \
|
||||
[[ "$SYSTEM_ADMIN_PASSWORD" == *"CHANGE_ME"* ]]; then
|
||||
log_warning "Default or placeholder password detected!"
|
||||
log_warning "Username: $SYSTEM_ADMIN_USERNAME"
|
||||
log_warning "Password: $SYSTEM_ADMIN_PASSWORD"
|
||||
log_warning ""
|
||||
log_warning "This is INSECURE for production!"
|
||||
log_warning "Using default 002-create-admin-user.sql"
|
||||
log_warning ""
|
||||
read -p "Continue anyway? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
log_info "Deployment cancelled. Please update your credentials."
|
||||
exit 1
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
log_success "Custom password detected - generating secure admin SQL"
|
||||
log_info "Username: $SYSTEM_ADMIN_USERNAME"
|
||||
log_info "Password length: ${#SYSTEM_ADMIN_PASSWORD} characters"
|
||||
|
||||
# Create backup of original SQL (if not already created)
|
||||
if [ -f "002-create-admin-user.sql" ] && [ ! -f "002-create-admin-user-DEFAULT-BACKUP.sql" ]; then
|
||||
log_info "Creating backup of default SQL..."
|
||||
cp 002-create-admin-user.sql 002-create-admin-user-DEFAULT-BACKUP.sql
|
||||
log_success "Backup created: 002-create-admin-user-DEFAULT-BACKUP.sql"
|
||||
fi
|
||||
|
||||
# Generate new SQL
|
||||
log_info "Generating SQL with custom password..."
|
||||
python3 generate_guacamole_user.py \
|
||||
--username "$SYSTEM_ADMIN_USERNAME" \
|
||||
--password "$SYSTEM_ADMIN_PASSWORD" \
|
||||
--admin \
|
||||
--verify \
|
||||
> 002-create-admin-user-GENERATED.sql
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
log_error "Failed to generate SQL!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Replace SQL
|
||||
mv 002-create-admin-user-GENERATED.sql 002-create-admin-user.sql
|
||||
log_success "Admin SQL generated and applied"
|
||||
log_info "File: 002-create-admin-user.sql (auto-generated)"
|
||||
}
|
||||
|
||||
# Validate docker-compose.yml
|
||||
check_compose_file() {
|
||||
log_info "Validating docker-compose.yml..."
|
||||
|
||||
if docker compose config > /dev/null 2>&1; then
|
||||
log_success "docker-compose.yml is valid"
|
||||
else
|
||||
log_error "Invalid docker-compose.yml!"
|
||||
docker compose config
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Start containers
|
||||
start_containers() {
|
||||
log_info "Starting containers..."
|
||||
|
||||
# Stop existing containers (if any)
|
||||
docker compose down 2>/dev/null || true
|
||||
|
||||
# Start
|
||||
docker compose up -d
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
log_success "Containers started successfully"
|
||||
else
|
||||
log_error "Failed to start containers!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Wait for services to be ready
|
||||
wait_for_services() {
|
||||
log_info "Waiting for services to be ready..."
|
||||
|
||||
# Wait for PostgreSQL
|
||||
log_info "Waiting for PostgreSQL..."
|
||||
for i in {1..30}; do
|
||||
if docker compose exec -T postgres pg_isready -U guacamole_user &>/dev/null; then
|
||||
log_success "PostgreSQL is ready"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq 30 ]; then
|
||||
log_error "PostgreSQL failed to start!"
|
||||
docker compose logs postgres
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Wait for Guacamole
|
||||
log_info "Waiting for Guacamole..."
|
||||
local guacamole_ready=0
|
||||
for i in {1..60}; do
|
||||
if curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/guacamole/ | grep -q "200\|302"; then
|
||||
log_success "Guacamole is ready"
|
||||
guacamole_ready=1
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ $guacamole_ready -eq 0 ]; then
|
||||
log_warning "Guacamole might not be ready yet (timeout after 120s)"
|
||||
log_info "Check logs: docker compose logs guacamole"
|
||||
fi
|
||||
|
||||
# Wait for Redis
|
||||
log_info "Waiting for Redis..."
|
||||
local redis_ready=0
|
||||
for i in {1..20}; do
|
||||
if docker compose exec -T redis redis-cli -a "$REDIS_PASSWORD" ping &>/dev/null | grep -q "PONG"; then
|
||||
log_success "Redis is ready"
|
||||
redis_ready=1
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [ $redis_ready -eq 0 ]; then
|
||||
log_warning "Redis might not be ready yet (timeout after 20s)"
|
||||
fi
|
||||
|
||||
# Wait for API
|
||||
log_info "Waiting for API..."
|
||||
local api_ready=0
|
||||
for i in {1..45}; do
|
||||
if docker compose logs remote_access_api 2>&1 | grep -q "Application startup complete"; then
|
||||
log_info "API startup detected, checking health endpoint..."
|
||||
sleep 2 # Give it a moment to fully initialize
|
||||
|
||||
# Check health endpoint
|
||||
if curl -s http://localhost:8000/api/health | grep -q '"overall_status":"ok"'; then
|
||||
log_success "API is ready and healthy"
|
||||
api_ready=1
|
||||
break
|
||||
elif curl -s http://localhost:8000/api/health | grep -q '"overall_status"'; then
|
||||
log_warning "API is running but some components have issues"
|
||||
log_info "Check: curl http://localhost:8000/api/health | jq"
|
||||
api_ready=1
|
||||
break
|
||||
fi
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ $api_ready -eq 0 ]; then
|
||||
log_error "API failed to start properly (timeout after 90s)"
|
||||
log_info "Check logs: docker compose logs remote_access_api"
|
||||
log_info "Last 30 lines:"
|
||||
docker compose logs --tail=30 remote_access_api
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Verify deployment
|
||||
verify_deployment() {
|
||||
log_info "Verifying deployment..."
|
||||
|
||||
# Check that admin user was created
|
||||
ADMIN_CHECK=$(docker compose exec -T postgres psql -U guacamole_user -d guacamole_db -t -c \
|
||||
"SELECT COUNT(*) FROM guacamole_user u
|
||||
JOIN guacamole_entity e ON u.entity_id = e.entity_id
|
||||
WHERE e.name = '$SYSTEM_ADMIN_USERNAME';" 2>/dev/null | tr -d ' ')
|
||||
|
||||
if [ "$ADMIN_CHECK" == "1" ]; then
|
||||
log_success "Admin user '$SYSTEM_ADMIN_USERNAME' exists in database"
|
||||
else
|
||||
log_warning "Could not verify admin user in database"
|
||||
fi
|
||||
|
||||
# Check API health endpoint
|
||||
log_info "Checking API health endpoint..."
|
||||
HEALTH_RESPONSE=$(curl -s http://localhost:8000/api/health)
|
||||
|
||||
if echo "$HEALTH_RESPONSE" | grep -q '"overall_status":"ok"'; then
|
||||
log_success "API health check: OK"
|
||||
|
||||
# Parse component statuses (if jq is available)
|
||||
if command -v jq &> /dev/null; then
|
||||
echo "$HEALTH_RESPONSE" | jq -r '.components | to_entries[] | " - \(.key): \(.value.status)"' 2>/dev/null || true
|
||||
fi
|
||||
elif echo "$HEALTH_RESPONSE" | grep -q '"overall_status"'; then
|
||||
local status=$(echo "$HEALTH_RESPONSE" | grep -o '"overall_status":"[^"]*"' | cut -d'"' -f4)
|
||||
log_warning "API health check: $status (some components have issues)"
|
||||
|
||||
if command -v jq &> /dev/null; then
|
||||
echo "$HEALTH_RESPONSE" | jq -r '.components | to_entries[] | " - \(.key): \(.value.status)"' 2>/dev/null || true
|
||||
else
|
||||
log_info "Install 'jq' for detailed component status"
|
||||
fi
|
||||
else
|
||||
log_error "API health check failed!"
|
||||
log_info "Response: $HEALTH_RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check API logs for authentication
|
||||
if docker compose logs remote_access_api 2>&1 | grep -q "System token refreshed successfully\|authenticated with system credentials"; then
|
||||
log_success "API successfully authenticated with system credentials"
|
||||
else
|
||||
log_warning "Could not verify API system authentication in logs"
|
||||
log_info "This may be normal if using cached tokens"
|
||||
fi
|
||||
}
|
||||
|
||||
# Print deployment summary
|
||||
print_summary() {
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " Deployment Complete!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
log_success "Services are running"
|
||||
echo ""
|
||||
echo "Access URLs:"
|
||||
echo " - Guacamole UI: http://localhost:8080/guacamole/"
|
||||
echo " - API Health: http://localhost:8000/api/health"
|
||||
echo " - API Docs: http://localhost:8000/docs (if enabled)"
|
||||
echo ""
|
||||
echo "Admin Credentials:"
|
||||
echo " - Username: $SYSTEM_ADMIN_USERNAME"
|
||||
echo " - Password: ${SYSTEM_ADMIN_PASSWORD:0:3}***${SYSTEM_ADMIN_PASSWORD: -3} (length: ${#SYSTEM_ADMIN_PASSWORD})"
|
||||
echo ""
|
||||
echo "Useful Commands:"
|
||||
echo " - View logs: docker compose logs -f"
|
||||
echo " - API logs: docker compose logs -f remote_access_api"
|
||||
echo " - Check health: curl http://localhost:8000/api/health | jq"
|
||||
echo " - Stop: docker compose down"
|
||||
echo " - Restart: docker compose restart"
|
||||
echo ""
|
||||
|
||||
if [ -f "002-create-admin-user-DEFAULT-BACKUP.sql" ]; then
|
||||
log_info "Original SQL backed up to: 002-create-admin-user-DEFAULT-BACKUP.sql"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main deployment flow
|
||||
main() {
|
||||
check_requirements
|
||||
load_env
|
||||
check_critical_passwords
|
||||
generate_admin_sql
|
||||
check_compose_file
|
||||
start_containers
|
||||
wait_for_services
|
||||
verify_deployment
|
||||
print_summary
|
||||
}
|
||||
|
||||
# Run
|
||||
main
|
||||
|
||||
Reference in New Issue
Block a user