#!/bin/bash # Calejo Control Adapter - One-Click Server Setup Script # Single command to provision server, install dependencies, deploy application, and start dashboard set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Default configuration ENVIRONMENT="production" SERVER_HOST="" SSH_USERNAME="" SSH_KEY_FILE="" AUTO_DETECT=true VERBOSE=false DRY_RUN=false # Function to print colored output print_status() { echo -e "${BLUE}[INFO]${NC} $1" } print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } # Function to display usage usage() { echo "Calejo Control Adapter - One-Click Server Setup" echo "==================================================" echo "" echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " -e, --environment Deployment environment (production, staging) [default: production]" echo " -h, --host Server hostname or IP address" echo " -u, --user SSH username" echo " -k, --key SSH private key file" echo " --no-auto Disable auto-detection (manual configuration)" echo " --verbose Enable verbose output" echo " --dry-run Show what would be done without making changes" echo " --help Show this help message" echo "" echo "Examples:" echo " $0 # Auto-detect and setup local machine" echo " $0 -h 192.168.1.100 -u ubuntu -k ~/.ssh/id_rsa # Setup remote server" echo " $0 --dry-run # Show setup steps without executing" echo "" } # Function to read deployment configuration from files read_deployment_config() { local config_dir="deploy" # Read from production.yml if it exists if [[ -f "$config_dir/config/production.yml" ]]; then print_status "Reading configuration from $config_dir/config/production.yml" # Extract values from production.yml if [[ -z "$SSH_HOST" ]]; then SSH_HOST=$(grep -E "^\s*host:\s*" "$config_dir/config/production.yml" | head -1 | sed 's/^[[:space:]]*host:[[:space:]]*//' | sed 's/^"//' | sed 's/"$//' | tr -d '\r') fi if [[ -z "$SSH_USERNAME" ]]; then SSH_USERNAME=$(grep -E "^\s*username:\s*" "$config_dir/config/production.yml" | head -1 | sed 's/^[[:space:]]*username:[[:space:]]*//' | sed 's/^"//' | sed 's/"$//' | tr -d '\r') fi if [[ -z "$SSH_KEY_FILE" ]]; then SSH_KEY_FILE=$(grep -E "^\s*key_file:\s*" "$config_dir/config/production.yml" | head -1 | sed 's/^[[:space:]]*key_file:[[:space:]]*//' | sed 's/^"//' | sed 's/"$//' | tr -d '\r') fi fi # Read from staging.yml if it exists and environment is staging if [[ "$ENVIRONMENT" == "staging" && -f "$config_dir/config/staging.yml" ]]; then print_status "Reading configuration from $config_dir/config/staging.yml" if [[ -z "$SSH_HOST" ]]; then SSH_HOST=$(grep -E "^\s*host:\s*" "$config_dir/config/staging.yml" | head -1 | sed 's/^[[:space:]]*host:[[:space:]]*//' | sed 's/^"//' | sed 's/"$//' | tr -d '\r') fi if [[ -z "$SSH_USERNAME" ]]; then SSH_USERNAME=$(grep -E "^\s*username:\s*" "$config_dir/config/staging.yml" | head -1 | sed 's/^[[:space:]]*username:[[:space:]]*//' | sed 's/^"//' | sed 's/"$//' | tr -d '\r') fi if [[ -z "$SSH_KEY_FILE" ]]; then SSH_KEY_FILE=$(grep -E "^\s*key_file:\s*" "$config_dir/config/staging.yml" | head -1 | sed 's/^[[:space:]]*key_file:[[:space:]]*//' | sed 's/^"//' | sed 's/"$//' | tr -d '\r') fi fi # Check for existing remote deployment script configuration if [[ -f "$config_dir/ssh/deploy-remote.sh" ]]; then print_status "Found existing remote deployment script: $config_dir/ssh/deploy-remote.sh" # Extract default values from deploy-remote.sh if [[ -z "$SSH_HOST" ]]; then SSH_HOST=$(grep -E "SSH_HOST=" "$config_dir/ssh/deploy-remote.sh" | head -1 | cut -d'=' -f2 | tr -d '\"' | tr -d '\'') fi if [[ -z "$SSH_USERNAME" ]]; then SSH_USERNAME=$(grep -E "SSH_USER=" "$config_dir/ssh/deploy-remote.sh" | head -1 | cut -d'=' -f2 | tr -d '\"' | tr -d '\'') fi if [[ -z "$SSH_KEY_FILE" ]]; then SSH_KEY_FILE=$(grep -E "SSH_KEY=" "$config_dir/ssh/deploy-remote.sh" | head -1 | cut -d'=' -f2 | tr -d '\"' | tr -d '\'') fi fi # Set defaults if still empty ENVIRONMENT=${ENVIRONMENT:-production} SSH_HOST=${SSH_HOST:-localhost} SSH_USERNAME=${SSH_USERNAME:-$USER} SSH_KEY_FILE=${SSH_KEY_FILE:-~/.ssh/id_rsa} # Use SSH_HOST as SERVER_HOST if not specified SERVER_HOST=${SERVER_HOST:-$SSH_HOST} } # Function to parse command line arguments parse_arguments() { while [[ $# -gt 0 ]]; do case $1 in -e|--environment) ENVIRONMENT="$2" shift 2 ;; -h|--host) SERVER_HOST="$2" AUTO_DETECT=false shift 2 ;; -u|--user) SSH_USERNAME="$2" AUTO_DETECT=false shift 2 ;; -k|--key) SSH_KEY_FILE="$2" AUTO_DETECT=false shift 2 ;; --no-auto) AUTO_DETECT=false shift ;; --verbose) VERBOSE=true shift ;; --dry-run) DRY_RUN=true shift ;; --help) usage exit 0 ;; *) print_error "Unknown option: $1" usage exit 1 ;; esac done } # Function to detect if running locally or needs remote setup detect_deployment_type() { if [[ -n "$SERVER_HOST" && "$SERVER_HOST" != "localhost" && "$SERVER_HOST" != "127.0.0.1" ]]; then echo "remote" else echo "local" fi } # Function to check local prerequisites check_local_prerequisites() { print_status "Checking local prerequisites..." # Check if script is running with sufficient privileges if [[ $EUID -eq 0 ]]; then print_warning "Running as root - this is not recommended for security reasons" fi # Check Docker if ! command -v docker &> /dev/null; then print_error "Docker is not installed locally" echo "Please install Docker first: https://docs.docker.com/get-docker/" exit 1 fi # Check Docker Compose if ! command -v docker-compose &> /dev/null; then print_error "Docker Compose is not installed locally" echo "Please install Docker Compose first: https://docs.docker.com/compose/install/" exit 1 fi print_success "Local prerequisites check passed" } # Function to check remote prerequisites via SSH check_remote_prerequisites() { print_status "Checking remote server prerequisites..." local ssh_cmd="ssh -i $SSH_KEY_FILE $SSH_USERNAME@$SERVER_HOST" if [[ "$DRY_RUN" == "true" ]]; then echo " [DRY RUN] Would check remote prerequisites" return 0 fi # Check Docker if ! $ssh_cmd "command -v docker" &> /dev/null; then print_error "Docker is not installed on remote server" return 1 fi # Check Docker Compose if ! $ssh_cmd "command -v docker-compose" &> /dev/null; then print_error "Docker Compose is not installed on remote server" return 1 fi # Check disk space local disk_usage=$($ssh_cmd "df / | awk 'NR==2 {print \$5}' | sed 's/%//'") if [[ $disk_usage -gt 90 ]]; then print_warning "Low disk space on remote server: ${disk_usage}%" fi print_success "Remote prerequisites check passed" } # Function to setup local deployment setup_local_deployment() { print_status "Setting up local deployment..." if [[ "$DRY_RUN" == "true" ]]; then echo " [DRY RUN] Would setup local deployment" return 0 fi # Create necessary directories mkdir -p ./data/postgres mkdir -p ./logs mkdir -p ./certs # Set permissions chmod 755 ./data chmod 755 ./logs chmod 700 ./certs # Generate default configuration if not exists if [[ ! -f ".env" ]]; then print_status "Creating default configuration..." cp config/.env.example .env # Generate secure JWT secret local jwt_secret=$(openssl rand -hex 32 2>/dev/null || echo "default-secret-change-in-production") sed -i.bak "s/your-secret-key-change-in-production/$jwt_secret/" .env rm -f .env.bak print_success "Default configuration created with secure JWT secret" fi # Build and start services print_status "Building and starting services..." docker-compose up --build -d # Wait for services to be ready wait_for_services "localhost" print_success "Local deployment completed successfully" } # Function to setup remote deployment setup_remote_deployment() { print_status "Setting up remote deployment on $SERVER_HOST..." if [[ "$DRY_RUN" == "true" ]]; then echo " [DRY RUN] Would setup remote deployment on $SERVER_HOST" return 0 fi # Use existing deployment script if [[ -f "deploy/ssh/deploy-remote.sh" ]]; then print_status "Using existing remote deployment script..." # Create temporary configuration local temp_config=$(mktemp) cat > "$temp_config" << EOF ssh: host: $SERVER_HOST port: 22 username: $SSH_USERNAME key_file: $SSH_KEY_FILE deployment: target_dir: /opt/calejo-control-adapter backup_dir: /var/backup/calejo log_dir: /var/log/calejo config_dir: /etc/calejo EOF # Run deployment ./deploy/ssh/deploy-remote.sh -e "$ENVIRONMENT" -c "$temp_config" # Cleanup rm -f "$temp_config" else print_error "Remote deployment script not found" return 1 fi print_success "Remote deployment completed successfully" } # Function to wait for services to be ready wait_for_services() { local host="$1" local max_attempts=30 local attempt=1 print_status "Waiting for services to start..." while [[ $attempt -le $max_attempts ]]; do if curl -s "http://$host:8080/health" > /dev/null 2>&1; then print_success "Services are ready and responding" return 0 fi echo " Waiting... (attempt $attempt/$max_attempts)" sleep 5 ((attempt++)) done print_error "Services failed to start within expected time" return 1 } # Function to generate SSL certificates for production generate_ssl_certificates() { if [[ "$ENVIRONMENT" == "production" ]]; then print_status "Setting up SSL certificates for production..." if [[ "$DRY_RUN" == "true" ]]; then echo " [DRY RUN] Would generate SSL certificates" return 0 fi mkdir -p ./certs # Generate self-signed certificate for development # In production, you should use Let's Encrypt or proper CA if openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout ./certs/server.key \ -out ./certs/server.crt \ -subj "/C=US/ST=State/L=City/O=Organization/CN=localhost" 2>/dev/null; then print_success "SSL certificates generated" else print_warning "SSL certificate generation failed - using development mode" fi print_success "SSL certificates configured" fi } # Function to display setup completion message display_completion_message() { local deployment_type="$1" local host="$2" echo "" echo "==================================================" echo " SETUP COMPLETED SUCCESSFULLY!" echo "==================================================" echo "" echo "🎉 Calejo Control Adapter is now running!" echo "" echo "🌍 Access URLs:" echo " Dashboard: http://$host:8080/dashboard" echo " REST API: http://$host:8080" echo " Health Check: http://$host:8080/health" echo "" echo "🔧 Next Steps:" echo " 1. Open the dashboard in your browser" echo " 2. Configure your SCADA systems and hardware" echo " 3. Set up safety limits and user accounts" echo " 4. Integrate with your existing infrastructure" echo "" echo "📚 Documentation:" echo " Full documentation: ./docs/" echo " Quick start: ./docs/INSTALLATION_CONFIGURATION.md" echo " Dashboard guide: ./docs/OPERATIONS_MAINTENANCE.md" echo "" if [[ "$deployment_type" == "local" ]]; then echo "💡 Local Development Tips:" echo " - View logs: docker-compose logs -f" echo " - Stop services: docker-compose down" echo " - Restart: docker-compose up -d" else echo "💡 Remote Server Tips:" echo " - View logs: ssh -i $SSH_KEY_FILE $SSH_USERNAME@$host 'cd /opt/calejo-control-adapter && docker-compose logs -f'" echo " - Stop services: ssh -i $SSH_KEY_FILE $SSH_USERNAME@$host 'cd /opt/calejo-control-adapter && docker-compose down'" echo " - Restart: ssh -i $SSH_KEY_FILE $SSH_USERNAME@$host 'cd /opt/calejo-control-adapter && docker-compose up -d'" fi echo "" echo "==================================================" echo "" } # Function to validate setup validate_setup() { local host="$1" print_status "Validating setup..." if [[ "$DRY_RUN" == "true" ]]; then echo " [DRY RUN] Would validate setup" return 0 fi # Test health endpoint if ! curl -s "http://$host:8080/health" > /dev/null; then print_error "Health check failed" return 1 fi # Test dashboard endpoint if ! curl -s "http://$host:8080/dashboard" > /dev/null; then print_error "Dashboard check failed" return 1 fi # Test API endpoint if ! curl -s "http://$host:8080/api/v1/status" > /dev/null; then print_warning "API status check failed (may require authentication)" fi print_success "Setup validation passed" return 0 } # Main setup function main() { echo "" echo "🚀 Calejo Control Adapter - One-Click Server Setup" echo "==================================================" echo "" # Parse command line arguments parse_arguments "$@" # Read deployment configuration from files read_deployment_config # Detect deployment type local deployment_type=$(detect_deployment_type) # Display setup information echo "Setup Configuration:" echo " Environment: $ENVIRONMENT" echo " Deployment: $deployment_type" if [[ "$deployment_type" == "remote" ]]; then echo " Server: $SERVER_HOST" echo " User: $SSH_USERNAME" else echo " Server: localhost" fi if [[ "$DRY_RUN" == "true" ]]; then echo " Mode: DRY RUN" fi echo "" # Check prerequisites if [[ "$deployment_type" == "local" ]]; then check_local_prerequisites else if [[ -z "$SERVER_HOST" || -z "$SSH_USERNAME" || -z "$SSH_KEY_FILE" ]]; then print_error "Remote deployment requires --host, --user, and --key parameters" usage exit 1 fi check_remote_prerequisites fi # Generate SSL certificates for production generate_ssl_certificates # Perform deployment if [[ "$deployment_type" == "local" ]]; then setup_local_deployment local final_host="localhost" else setup_remote_deployment local final_host="$SERVER_HOST" fi # Validate setup validate_setup "$final_host" # Display completion message display_completion_message "$deployment_type" "$final_host" echo "" print_success "One-click setup completed!" echo "" } # Run main function main "$@"