2025-10-22 12:09:18 -05:00
2025-10-22 09:31:42 -05:00
2025-10-20 11:07:35 -05:00
2025-10-22 09:18:11 -05:00
2025-10-20 11:07:35 -05:00
2025-10-20 23:25:13 -05:00
2025-10-22 09:18:11 -05:00
2025-10-21 18:48:35 -05:00
2025-10-22 12:09:18 -05:00
2025-10-20 11:07:35 -05:00
2025-10-20 11:07:35 -05:00
2025-10-21 15:06:53 -05:00
2025-10-22 09:18:11 -05:00
2025-10-22 09:31:42 -05:00
2025-10-22 09:18:11 -05:00

CF Deployer - Cloud Foundry Deployment Service

A Spring Boot application that provides a REST API for deploying Java applications to Cloud Foundry/Tanzu environments.

Prerequisites

  • Java 21
  • Gradle 8.14

Build and Run

Build the application

./gradlew clean build

Run the application

./gradlew bootRun

Or run the JAR directly:

java -jar build/libs/cf-uploader-1.0.0.jar

The application will start on http://localhost:8080

API Endpoints

Deployment Options

This service provides two deployment methods:

  1. Traditional Upload (/api/cf/deploy) - Single request deployment (may hit nginx size/timeout limits)
  2. Chunked Upload (/api/cf/upload/*) - Chunked upload with async deployment (recommended for production)

Option 1: Traditional Deploy (Simple, may timeout with large files)

Endpoint: POST /api/cf/deploy

Content-Type: multipart/form-data

Request Parts:

  • request (JSON string): Deployment configuration
  • jarFile (file): The Java application JAR file
  • manifest (file): Cloud Foundry manifest.yml file

Sample cURL Request

curl -X POST http://localhost:8080/api/cf/deploy \
  -F 'request={
    "apiEndpoint": "https://api.cf.example.com",
    "username": "your-username",
    "password": "your-password",
    "organization": "your-org",
    "space": "your-space",
    "appName": "my-app",
    "skipSslValidation": false
  }' \
  -F 'jarFile=@/path/to/your/application.jar' \
  -F 'manifest=@/path/to/manifest.yml'

Sample Request with Skip SSL Validation

curl -X POST http://localhost:8080/api/cf/deploy \
  -F 'request={
    "apiEndpoint": "https://api.sys.tanzu.example.com",
    "username": "admin",
    "password": "admin123",
    "organization": "development",
    "space": "dev",
    "appName": "sample-app",
    "skipSslValidation": true
  }' \
  -F 'jarFile=@./sample-app.jar' \
  -F 'manifest=@./manifest.yml'

Why use chunked upload?

  • Bypasses nginx client_max_body_size restrictions
  • Avoids nginx timeout issues during deployment
  • Better for large JAR files (>10MB)
  • More resilient to network interruptions

Quick Start: Using the Deployment Script

The easiest way to deploy using chunked upload is with the provided bash script:

  1. Configure the script:

    # Edit deploy-chunked.sh and set your values:
    API_BASE="https://your-cf-deployer.example.com/api/cf"
    JAR_FILE="./your-app.jar"
    MANIFEST_FILE="./manifest.yml"
    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"
    
  2. Make it executable and run:

    chmod +x deploy-chunked.sh
    ./deploy-chunked.sh
    

The script handles:

  • File chunking (1MB chunks by default)
  • Progress tracking
  • Async deployment
  • Status polling
  • Error handling

Manual cURL Commands (For Custom Integration)

Step 1: Initialize Upload Session

SESSION_ID=$(curl -s -X POST "http://localhost:8080/api/cf/upload/init" \
  -H "Content-Type: application/json" \
  -d '{
    "apiEndpoint": "https://api.cf.example.com",
    "username": "your-username",
    "password": "your-password",
    "organization": "your-org",
    "space": "your-space",
    "appName": "my-app",
    "skipSslValidation": false
  }' | grep -o '"uploadSessionId":"[^"]*' | cut -d'"' -f4)

echo "Session ID: $SESSION_ID"

Step 2: Upload JAR File in Chunks

# Split your JAR into 1MB chunks and upload each
CHUNK_SIZE=1048576  # 1MB
FILE="./app.jar"
TOTAL_CHUNKS=$(( ($(stat -c%s "$FILE") + CHUNK_SIZE - 1) / CHUNK_SIZE ))

# Split file and upload each chunk
split -b $CHUNK_SIZE "$FILE" chunk_
CHUNK_INDEX=0

for chunk_file in chunk_*; do
  curl -X POST "http://localhost:8080/api/cf/upload/chunk" \
    -F "uploadSessionId=$SESSION_ID" \
    -F "fileType=jarFile" \
    -F "chunkIndex=$CHUNK_INDEX" \
    -F "totalChunks=$TOTAL_CHUNKS" \
    -F "fileName=app.jar" \
    -F "chunk=@$chunk_file"

  CHUNK_INDEX=$((CHUNK_INDEX + 1))
done

rm chunk_*  # Cleanup

Step 3: Upload Manifest

curl -X POST "http://localhost:8080/api/cf/upload/chunk" \
  -F "uploadSessionId=$SESSION_ID" \
  -F "fileType=manifest" \
  -F "chunkIndex=0" \
  -F "totalChunks=1" \
  -F "fileName=manifest.yml" \
  -F "chunk=@./manifest.yml"

Step 4: Start Async Deployment

curl -X POST "http://localhost:8080/api/cf/upload/finalize?uploadSessionId=$SESSION_ID&async=true"

# Response: {"uploadSessionId":"...","status":"IN_PROGRESS","message":"Deployment started...","progress":0}

Step 5: Poll Deployment Status

# Check deployment status every 5 seconds
while true; do
  STATUS=$(curl -s "http://localhost:8080/api/cf/deployment/status/$SESSION_ID")
  echo "$STATUS"

  # Check if completed or failed
  if echo "$STATUS" | grep -q '"status":"COMPLETED"'; then
    echo "Deployment successful!"
    break
  elif echo "$STATUS" | grep -q '"status":"FAILED"'; then
    echo "Deployment failed!"
    break
  fi

  sleep 5
done

For more details, see:

  • deploy-chunked.sh - Complete working script
  • CHUNKED_UPLOAD_GUIDE.md - Detailed API documentation
  • TIMEOUT_SOLUTION.md - Architecture and design details
  • CHUNK_SIZE_GUIDE.md - Chunk size recommendations
  • MEMORY_FIX.md - JVM memory configuration for Tanzu

2. List Applications

Endpoint: POST /api/cf/apps

Content-Type: application/json

Lists all applications in the specified organization and space.

Sample cURL Request

curl -X POST http://localhost:8080/api/cf/apps \
  -H "Content-Type: application/json" \
  -d '{
    "apiEndpoint": "https://api.cf.example.com",
    "username": "your-username",
    "password": "your-password",
    "organization": "your-org",
    "space": "your-space",
    "appName": "",
    "skipSslValidation": false
  }'

3. List Routes

Endpoint: POST /api/cf/routes

Content-Type: application/json

Lists all routes in the specified organization and space.

Sample cURL Request

curl -X POST http://localhost:8080/api/cf/routes \
  -H "Content-Type: application/json" \
  -d '{
    "apiEndpoint": "https://api.cf.example.com",
    "username": "your-username",
    "password": "your-password",
    "organization": "your-org",
    "space": "your-space",
    "appName": "",
    "skipSslValidation": false
  }'

4. Get Application Details

Endpoint: POST /api/cf/app/{appName}

Content-Type: application/json

Gets detailed information about a specific application.

Sample cURL Request

curl -X POST http://localhost:8080/api/cf/app/my-app \
  -H "Content-Type: application/json" \
  -d '{
    "apiEndpoint": "https://api.cf.example.com",
    "username": "your-username",
    "password": "your-password",
    "organization": "your-org",
    "space": "your-space",
    "appName": "",
    "skipSslValidation": false
  }'

5. Get Application Logs

Endpoint: POST /api/cf/logs/{appName}?recent=true

Content-Type: application/json

Query Parameters:

  • recent (optional, default: true): If true, gets recent logs; if false, tails logs

Gets logs for a specific application.

Sample cURL Request (Recent Logs)

curl -X POST "http://localhost:8080/api/cf/logs/my-app?recent=true" \
  -H "Content-Type: application/json" \
  -d '{
    "apiEndpoint": "https://api.cf.example.com",
    "username": "your-username",
    "password": "your-password",
    "organization": "your-org",
    "space": "your-space",
    "appName": "",
    "skipSslValidation": false
  }'

Sample Manifest File (manifest.yml)

---
applications:
- name: sample-app
  memory: 1G
  instances: 2
  path: sample-app.jar
  buildpacks:
  - java_buildpack
  env:
    SPRING_PROFILES_ACTIVE: production

Common Request Parameters

All endpoints require the following CF credentials and target information:

Field Type Required Description
apiEndpoint String Yes Cloud Foundry API endpoint URL
username String Yes CF username
password String Yes CF password
organization String Yes Target CF organization
space String Yes Target CF space
appName String No* Application name (required only for /deploy endpoint)
skipSslValidation Boolean Yes Skip SSL certificate validation

Note: Even though appName is not used by utility endpoints (/apps, /routes, /app/{appName}, /logs/{appName}), it must still be included in the JSON request body (can be empty string). The organization and space determine which apps/routes are listed or queried.

Response Format

Success Response

{
  "success": true,
  "message": "Application deployed successfully",
  "deploymentId": "123e4567-e89b-12d3-a456-426614174000",
  "output": "CF CLI output logs...",
  "error": null
}

Error Response

{
  "success": false,
  "message": "Application deployment failed",
  "deploymentId": "123e4567-e89b-12d3-a456-426614174000",
  "output": "CF CLI output logs...",
  "error": "Error details..."
}

Configuration

Application settings can be configured in src/main/resources/application.properties:

# Server port
server.port=8080

# Max file size (default: 500MB)
spring.servlet.multipart.max-file-size=500MB
spring.servlet.multipart.max-request-size=500MB

# CF CLI timeout in seconds (default: 600)
cf.cli.timeout=600

# Optional: Custom CF CLI path (if not using bundled binaries)
cf.cli.path=

Features

  • Application Deployment: Deploy JAR files to Cloud Foundry with manifest support
  • Chunked Upload Support: Upload large files in chunks to bypass nginx size restrictions (NEW)
  • Async Deployment: Non-blocking deployment with status polling to avoid timeout issues (NEW)
  • Application Management: List apps, view details, and access logs
  • Route Management: List all routes in your CF space
  • Automatic CF CLI Management: Bundled CF CLI binaries for Linux, macOS, and Windows
  • Secure Password Handling: Passwords are masked in all log output
  • Comprehensive Logging: Detailed DEBUG-level logging for troubleshooting deployments
  • Configurable Timeouts: Adjustable timeout for long-running deployments (default: 600s)
  • Large File Support: Chunked uploads support files of any size
  • Automatic Cleanup: Temporary files are automatically cleaned up after operations
  • Error Handling: Comprehensive exception handling with detailed error messages
  • Production Ready: Memory-optimized for Tanzu deployments with low-memory instances

Error Handling

The API handles various error scenarios:

  • 400 Bad Request: Invalid request parameters or file validation errors
  • 413 Payload Too Large: Files exceed 500MB limit
  • 500 Internal Server Error: Deployment failures or unexpected errors

Development

Project Structure

src/main/java/com/cfdeployer/
├── controller/          # REST controllers
├── service/            # Business logic
├── model/              # DTOs
└── exception/          # Exception handlers

src/main/resources/
├── application.properties
└── cf-cli/             # CF CLI binaries (auto-downloaded)

Build with Custom CF CLI Version

Edit build.gradle to change the CF CLI version:

def cfCliVersion = '8.7.10'  // Change this version

License

This project is licensed under the MIT License.

Description
No description provided
Readme 18 MiB
Languages
Java 54.1%
Shell 20.4%
TypeScript 10.5%
CSS 7.1%
HTML 6.6%
Other 1.3%