#!/bin/bash ############################################################################# # CF Deployer - Simple Chunked Upload Deployment Script # # This script deploys a Java application to Cloud Foundry using chunked # uploads to bypass nginx size restrictions and async deployment to avoid # timeout issues. # # This is a simplified version without cert/key/header authentication. # # Usage: # ./deploy-chunked-simple.sh # # Configuration: # Edit the variables below to match your environment ############################################################################# set -e # Exit on error ############################################################################# # CONFIGURATION - Update these values for your deployment ############################################################################# # API endpoint API_BASE="http://localhost:8080/api/cf" # Files to deploy JAR_FILE="./app.jar" MANIFEST_FILE="./manifest.yml" # Chunk size (bytes) # Recommended: 1MB (1048576) for Tanzu with memory constraints # Options: 512KB (524288), 1MB (1048576), 2MB (2097152), 5MB (5242880) CHUNK_SIZE=1048576 # 1MB # Cloud Foundry configuration CF_API_ENDPOINT="https://api.cf.example.com" CF_USERNAME="your-username" CF_PASSWORD="your-password" CF_ORGANIZATION="your-org" CF_SPACE="your-space" CF_APP_NAME="your-app" CF_SKIP_SSL="false" # Use "true" for self-signed certificates # Polling configuration POLL_INTERVAL=5 # seconds between status checks MAX_WAIT=600 # maximum wait time in seconds (10 minutes) # Debug mode (set to "true" to see curl commands and responses) DEBUG_MODE="false" ############################################################################# # SCRIPT - Do not modify below this line ############################################################################# # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Helper functions log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } # Check if files exist if [ ! -f "$JAR_FILE" ]; then log_error "JAR file not found: $JAR_FILE" exit 1 fi if [ ! -f "$MANIFEST_FILE" ]; then log_error "Manifest file not found: $MANIFEST_FILE" exit 1 fi # Check if curl is available if ! command -v curl &> /dev/null; then log_error "curl is not installed. Please install curl to use this script." exit 1 fi # Build CF configuration JSON CF_CONFIG=$(cat < "$TEMP_JSON" # Execute curl command if [ "$DEBUG_MODE" = "true" ]; then INIT_RESPONSE=$(curl -v -X POST "$API_BASE/upload/init" \ -H "Content-Type: application/json" \ -d @"$TEMP_JSON") else INIT_RESPONSE=$(curl -s -X POST "$API_BASE/upload/init" \ -H "Content-Type: application/json" \ -d @"$TEMP_JSON") fi # Clean up temporary file rm -f "$TEMP_JSON" CURL_EXIT_CODE=$? if [ "$DEBUG_MODE" = "true" ]; then echo "DEBUG: Curl exit code: $CURL_EXIT_CODE" echo "DEBUG: Response:" echo "$INIT_RESPONSE" fi if [ $CURL_EXIT_CODE -ne 0 ]; then log_error "Failed to initialize upload session (curl exit code: $CURL_EXIT_CODE)" echo "$INIT_RESPONSE" exit 1 fi # Debug output if [ -z "$INIT_RESPONSE" ]; then log_error "Empty response from server" exit 1 fi SESSION_ID=$(echo "$INIT_RESPONSE" | grep -o '"uploadSessionId":"[^"]*' | cut -d'"' -f4) if [ -z "$SESSION_ID" ]; then log_error "Failed to get session ID from response:" echo "$INIT_RESPONSE" exit 1 fi log_success "Upload session created: $SESSION_ID" echo "" ############################################################################# # FUNCTION: Upload file in chunks ############################################################################# upload_file_in_chunks() { local file_path=$1 local file_type=$2 local file_name=$(basename "$file_path") # Get file size (cross-platform) if [[ "$OSTYPE" == "darwin"* ]]; then local file_size=$(stat -f%z "$file_path") else local file_size=$(stat -c%s "$file_path") fi local total_chunks=$(( ($file_size + $CHUNK_SIZE - 1) / $CHUNK_SIZE )) local file_size_mb=$(awk "BEGIN {printf \"%.2f\", $file_size / 1048576}") log_info "Uploading $file_type: $file_name (${file_size_mb}MB, $total_chunks chunks)" # Create temporary directory for chunks local temp_dir=$(mktemp -d) # Split file into chunks split -b $CHUNK_SIZE "$file_path" "$temp_dir/chunk_" local chunk_index=0 for chunk_file in "$temp_dir"/chunk_*; do printf " Chunk %3d/%3d... " "$((chunk_index + 1))" "$total_chunks" if [ "$DEBUG_MODE" = "true" ]; then echo "" echo "DEBUG: SESSION_ID='$SESSION_ID'" echo "DEBUG: Uploading chunk to: $API_BASE/upload/chunk?uploadSessionId=$SESSION_ID&fileType=$file_type&chunkIndex=$chunk_index&totalChunks=$total_chunks&fileName=$file_name" fi # Base64 encode the chunk to a temp file so Java proxy can handle it as text/String # This prevents corruption when proxy reads binary data as String # Use temp file to avoid "Argument list too long" error CHUNK_BASE64_FILE=$(mktemp) base64 < "$chunk_file" > "$CHUNK_BASE64_FILE" RESPONSE=$(curl -s -X POST "$API_BASE/upload/chunk?uploadSessionId=$SESSION_ID&fileType=$file_type&chunkIndex=$chunk_index&totalChunks=$total_chunks&fileName=$file_name" \ -H "Content-Type: text/plain" \ -H "X-Chunk-Encoding: base64" \ -d @"$CHUNK_BASE64_FILE") # Clean up temp file rm -f "$CHUNK_BASE64_FILE" if [ "$DEBUG_MODE" = "true" ]; then echo "DEBUG: Chunk response: $RESPONSE" fi SUCCESS=$(echo "$RESPONSE" | grep -o '"success":[^,}]*' | cut -d':' -f2) if [ "$SUCCESS" != "true" ]; then echo -e "${RED}FAILED${NC}" log_error "Failed to upload chunk $((chunk_index + 1))/$total_chunks" echo "DEBUG: SESSION_ID='$SESSION_ID'" echo "DEBUG: fileType='$file_type'" echo "DEBUG: chunkIndex='$chunk_index'" echo "DEBUG: totalChunks='$total_chunks'" echo "DEBUG: fileName='$file_name'" echo "$RESPONSE" rm -rf "$temp_dir" exit 1 fi echo -e "${GREEN}OK${NC}" chunk_index=$((chunk_index + 1)) done # Cleanup temporary directory rm -rf "$temp_dir" log_success "$file_type upload completed ($total_chunks chunks)" echo "" } ############################################################################# # STEP 2: Upload JAR file ############################################################################# log_info "Step 2/5: Uploading JAR file..." upload_file_in_chunks "$JAR_FILE" "jarFile" ############################################################################# # STEP 3: Upload manifest file ############################################################################# log_info "Step 3/5: Uploading manifest file..." upload_file_in_chunks "$MANIFEST_FILE" "manifest" ############################################################################# # STEP 4: Start async deployment ############################################################################# log_info "Step 4/5: Starting async deployment..." FINALIZE_RESPONSE=$(curl -s -X POST "$API_BASE/upload/finalize?uploadSessionId=$SESSION_ID&async=true" \ -H "Content-Length: 0") STATUS=$(echo "$FINALIZE_RESPONSE" | grep -o '"status":"[^"]*' | cut -d'"' -f4) if [ "$STATUS" != "IN_PROGRESS" ]; then log_error "Failed to start deployment. Status: $STATUS" echo "$FINALIZE_RESPONSE" exit 1 fi log_success "Deployment started successfully" log_info "Step 5/5: Polling deployment status (max wait: ${MAX_WAIT}s)..." echo "" ############################################################################# # STEP 5: Poll deployment status ############################################################################# elapsed=0 last_message="" while [ $elapsed -lt $MAX_WAIT ]; do sleep $POLL_INTERVAL elapsed=$((elapsed + POLL_INTERVAL)) STATUS_RESPONSE=$(curl -s "$API_BASE/deployment/status/$SESSION_ID" 2>/dev/null) if [ $? -ne 0 ]; then log_warning "Failed to fetch status, retrying..." continue fi CURRENT_STATUS=$(echo "$STATUS_RESPONSE" | grep -o '"status":"[^"]*' | cut -d'"' -f4) MESSAGE=$(echo "$STATUS_RESPONSE" | grep -o '"message":"[^"]*' | cut -d'"' -f4) PROGRESS=$(echo "$STATUS_RESPONSE" | grep -o '"progress":[0-9]*' | cut -d':' -f2) # Only print if message changed to reduce clutter if [ "$MESSAGE" != "$last_message" ]; then printf " [%3ds] Status: %-15s Progress: %3s%% - %s\n" \ "$elapsed" "$CURRENT_STATUS" "${PROGRESS:-0}" "$MESSAGE" last_message="$MESSAGE" fi # Check if deployment completed if [ "$CURRENT_STATUS" = "COMPLETED" ]; then echo "" log_success "Deployment completed successfully!" echo "" log_info "Deployment details:" echo "$STATUS_RESPONSE" | python -m json.tool 2>/dev/null || echo "$STATUS_RESPONSE" exit 0 fi # Check if deployment failed if [ "$CURRENT_STATUS" = "FAILED" ]; then echo "" log_error "Deployment failed!" echo "" log_info "Error details:" echo "$STATUS_RESPONSE" | python -m json.tool 2>/dev/null || echo "$STATUS_RESPONSE" exit 1 fi done # Timeout reached echo "" log_warning "Deployment timeout reached after ${MAX_WAIT}s" log_info "The deployment may still be running. Check status manually:" echo " curl $API_BASE/deployment/status/$SESSION_ID" exit 1