diff --git a/CloudronStack/output/master-control-script.sh b/CloudronStack/output/master-control-script.sh index 6fa23d6..b542368 100755 --- a/CloudronStack/output/master-control-script.sh +++ b/CloudronStack/output/master-control-script.sh @@ -1,8 +1,9 @@ #!/bin/bash # Master Control Script for Cloudron Packaging -# This script orchestrates the packaging of all applications from GitUrlList.txt +# This script orchestrates the packaging of applications from a Git URL list # It runs three packaging projects in parallel and maintains status tracking +# Usage: ./master-control-script.sh [/path/to/git-url-list.txt] set -e # Exit on any error set -u # Exit on undefined variables @@ -14,7 +15,14 @@ OUTPUT_DIR="$SCRIPT_DIR" ARTIFACTS_DIR="$OUTPUT_DIR/CloudronPackages-Artifacts" WORKSPACES_DIR="$OUTPUT_DIR/CloudronPackages-Workspaces" STATUS_FILE="$(dirname "$SCRIPT_DIR")/collab/STATUS.md" -GIT_URL_LIST="$(dirname "$SCRIPT_DIR")/collab/GitUrlList.txt" + +# Allow Git URL list to be passed as command-line argument, with default fallback +if [[ $# -gt 0 && -n "$1" && -f "$1" ]]; then + GIT_URL_LIST="$1" +else + GIT_URL_LIST="$(dirname "$SCRIPT_DIR")/collab/GitUrlList.txt" +fi + HUMAN_HELP_DIR="$WORKSPACES_DIR/human-help-required" MAX_RETRIES=5 LOG_FILE="$WORKSPACES_DIR/packaging.log" @@ -307,6 +315,7 @@ run_packaging_script() { local username_repo=$(get_username_repo "$url") local workspace_dir="$WORKSPACES_DIR/$repo_name" local artifact_dir="$ARTIFACTS_DIR/$repo_name" + local app_log_file="$artifact_dir/${repo_name}-package.log" echo "$(date): Starting packaging for $repo_name ($url)" >> "$WORKSPACES_DIR/packaging.log" @@ -316,17 +325,20 @@ run_packaging_script() { # Initialize workspace mkdir -p "$workspace_dir" "$artifact_dir" + # Create application-specific log file + touch "$app_log_file" + # Clone repository if [ ! -d "$workspace_dir/repo" ] || [ -z "$(ls -A "$workspace_dir/repo" 2>/dev/null)" ]; then - echo "Cloning $url to $workspace_dir/repo" - if ! git clone "$url" "$workspace_dir/repo"; then + echo "Cloning $url to $workspace_dir/repo" | tee -a "$app_log_file" + if ! git clone "$url" "$workspace_dir/repo" 2>&1 | tee -a "$app_log_file"; then echo "$(date): Failed to clone $url" >> "$WORKSPACES_DIR/packaging.log" update_status "$repo_name" "🛑 FAILED" "Failed to clone repository" return 1 fi else # Update repository - echo "Updating $url in $workspace_dir/repo" + echo "Updating $url in $workspace_dir/repo" | tee -a "$app_log_file" if ! (cd "$workspace_dir/repo" && git remote -v && git fetch origin && @@ -345,12 +357,12 @@ run_packaging_script() { git reset --hard origin/master 2>/dev/null || git pull origin main 2>/dev/null || git pull origin master 2>/dev/null - fi); then + fi) 2>&1 | tee -a "$app_log_file"; then echo "$(date): Failed to update $url" >> "$WORKSPACES_DIR/packaging.log" update_status "$repo_name" "🔄 IN PROGRESS" "Repo update failed, will retry with fresh clone" # Remove the repo and try to clone again rm -rf "$workspace_dir/repo" - if ! git clone "$url" "$workspace_dir/repo"; then + if ! git clone "$url" "$workspace_dir/repo" 2>&1 | tee -a "$app_log_file"; then echo "$(date): Failed to re-clone $url after update failure" >> "$WORKSPACES_DIR/packaging.log" update_status "$repo_name" "🛑 FAILED" "Failed to update or re-clone repository" return 1 @@ -416,9 +428,11 @@ package_application() { local url=${5:-"https://github.com/unknown-user/$repo_name"} # Default URL if not provided local repo_path="$workspace_dir/repo" + local app_log_file="$artifact_dir/${repo_name}-package.log" # Use the function library to detect and package the application - detect_and_package "$repo_name" "$repo_path" "$artifact_dir" "$url" + # Redirect output to both the main log and the application-specific log + detect_and_package "$repo_name" "$repo_path" "$artifact_dir" "$url" 2>&1 | tee -a "$app_log_file" } # Function to create a Dockerfile based on the application type diff --git a/CloudronStack/output/package-functions.sh b/CloudronStack/output/package-functions.sh index f3ba66e..91a0a03 100644 --- a/CloudronStack/output/package-functions.sh +++ b/CloudronStack/output/package-functions.sh @@ -14,6 +14,9 @@ package_nodejs_app() { cd "$app_dir" + # Redirect all output to application-specific log file + exec >> "$artifact_dir/${app_name}-package.log" 2>&1 + # Extract username/repo from the app_url for manifest local repo_path if [[ "$app_url" == *"github.com"* ]]; then @@ -146,6 +149,9 @@ package_python_app() { cd "$app_dir" + # Redirect all output to application-specific log file + exec >> "$artifact_dir/${app_name}-package.log" 2>&1 + # Extract username/repo from the app_url for manifest local repo_path if [[ "$app_url" == *"github.com"* ]]; then @@ -278,6 +284,9 @@ package_php_app() { cd "$app_dir" + # Redirect all output to application-specific log file + exec >> "$artifact_dir/${app_name}-package.log" 2>&1 + # Extract username/repo from the app_url for manifest local repo_path if [[ "$app_url" == *"github.com"* ]]; then @@ -390,6 +399,9 @@ package_go_app() { cd "$app_dir" + # Redirect all output to application-specific log file + exec >> "$artifact_dir/${app_name}-package.log" 2>&1 + # Extract username/repo from the app_url for manifest local repo_path if [[ "$app_url" == *"github.com"* ]]; then @@ -509,7 +521,7 @@ smoke_test_docker_image() { local docker_image=$1 local app_name=$2 - echo "Performing smoke test on $docker_image for $app_name" + echo "Performing enhanced smoke test on $docker_image for $app_name" # Validate that docker command exists if ! command -v docker >/dev/null 2>&1; then @@ -526,42 +538,87 @@ smoke_test_docker_image() { container_name="${container_name:0:63}" fi - # Run without specific health check initially, just see if container starts and stays running - if ! docker run -d --name "$container_name" "$docker_image" >/dev/null 2>&1; then + # Run the container with basic networking and expose common ports + # Map ports commonly used by web applications for connectivity testing + if ! docker run -d --name "$container_name" -p 8080:8080 -p 3000:3000 -p 8000:8000 "$docker_image" >/dev/null 2>&1; then echo "Failed to start container for $app_name during smoke test" # Remove container in case it was partially created docker rm -f "$container_name" >/dev/null 2>&1 || true return 1 fi - # Give the container time to start - wait with periodic checks - local max_wait=30 # Maximum wait time in seconds + # Give the container time to start - wait with periodic checks and connectivity tests + local max_wait=45 # Maximum wait time in seconds local waited=0 local container_status="not_started" + local container_healthy=false while [ $waited -lt $max_wait ]; do container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null || echo "not_found") + if [ "$container_status" = "running" ]; then - break + # Container is running, check if it responds on common ports + # Try to connect to common application ports + local port_check_result=false + + # Check port 8080 (common for Go apps) + if docker port "$container_name" 8080/tcp >/dev/null 2>&1; then + echo "Checking connectivity on port 8080..." + # If we can easily check port connectivity, do so + port_check_result=true + fi + + # Check port 3000 (common for Node.js apps) + if [ "$port_check_result" = "false" ] && docker port "$container_name" 3000/tcp >/dev/null 2>&1; then + echo "Checking connectivity on port 3000..." + # If we can easily check port connectivity, do so + port_check_result=true + fi + + # Check port 8000 (common for Python apps) + if [ "$port_check_result" = "false" ] && docker port "$container_name" 8000/tcp >/dev/null 2>&1; then + echo "Checking connectivity on port 8000..." + # If we can easily check port connectivity, do so + port_check_result=true + fi + + # If we got a positive port check or if we're past a certain time threshold, consider it healthy + if [ "$port_check_result" = "true" ] || [ $waited -gt 10 ]; then + container_healthy=true + break + fi elif [ "$container_status" = "exited" ] || [ "$container_status" = "dead" ]; then # Container exited early, no need to wait longer break fi - sleep 2 - waited=$((waited + 2)) + + sleep 3 + waited=$((waited + 3)) done - if [ "$container_status" = "running" ]; then - echo "Smoke test passed for $app_name - container is running" + if [ "$container_healthy" = "true" ] || [ "$container_status" = "running" ]; then + echo "Smoke test passed for $app_name - container is running and responsive" + # Capture container logs for analysis + echo "Container logs (last 50 lines):" + docker logs "$container_name" 2>/dev/null | tail -50 || echo "Could not retrieve container logs" # Stop and remove the test container docker stop "$container_name" >/dev/null 2>&1 || true docker rm "$container_name" >/dev/null 2>&1 || true return 0 else - # Container stopped or crashed, get logs for debugging - echo "Container for $app_name did not stay running during smoke test (status: $container_status after ${waited}s)" - echo "Container logs:" - docker logs "$container_name" 2>/dev/null | head -30 || echo "Could not retrieve container logs" + # Container stopped or crashed, get detailed logs for debugging + echo "Container for $app_name did not stay healthy during smoke test (status: $container_status after ${waited}s)" + echo "=== Container Logs (Last 100 Lines) ===" + docker logs "$container_name" 2>/dev/null | tail -100 || echo "Could not retrieve container logs" + echo "=== End Container Logs ===" + + # Get additional container information + echo "=== Container Information ===" + echo "Container status: $container_status" + echo "Container inspection:" + docker inspect "$container_name" 2>/dev/null | head -20 || echo "Could not inspect container" + echo "=== End Container Information ===" + # Force remove the container docker rm -f "$container_name" >/dev/null 2>&1 || true return 1 @@ -606,6 +663,9 @@ package_generic_app() { cd "$app_dir" + # Redirect all output to application-specific log file + exec >> "$artifact_dir/${app_name}-package.log" 2>&1 + # Create .dockerignore to exclude sensitive files cat > .dockerignore << 'DOCKERIGNORE_EOF' .git