From 9151abc2af96358172dafae8260a21fd412d21db Mon Sep 17 00:00:00 2001 From: Dan Notestein Date: Fri, 9 Jan 2026 14:30:12 -0500 Subject: [PATCH] feat: add shared extract-test-cache.sh script for HAF app test jobs Consolidates cache extraction logic from balance_tracker and haf_block_explorer into a shared script that all HAF apps can use. Features: - Exact cache key match only (no fallback to different app versions) - Marker file prevents redundant extractions in same pipeline - Optional PostgreSQL readiness wait with configurable timeout - Handles pgdata permission fixing - Proper error messages when cache not found Also adds .fetch_extract_test_cache template for apps to fetch the script. Apps can migrate from their local extract-cache-and-wait.sh scripts to use this shared version for consistency and easier maintenance. --- scripts/extract-test-cache.sh | 207 ++++++++++++++++++++++++ templates/haf_app_testing.gitlab-ci.yml | 23 +++ 2 files changed, 230 insertions(+) create mode 100755 scripts/extract-test-cache.sh diff --git a/scripts/extract-test-cache.sh b/scripts/extract-test-cache.sh new file mode 100755 index 0000000..4df4b03 --- /dev/null +++ b/scripts/extract-test-cache.sh @@ -0,0 +1,207 @@ +#!/bin/bash +# ============================================================================= +# Extract HAF App Test Cache +# ============================================================================= +# Shared script for HAF application CI test jobs to extract cached sync data. +# Consolidates common patterns from balance_tracker and haf_block_explorer. +# +# Features: +# - Exact cache key match only (no fallback to different app versions) +# - Marker file prevents redundant extractions in same pipeline +# - Optional PostgreSQL readiness wait +# - Handles pgdata permission fixing +# +# Usage: +# extract-test-cache.sh +# +# Arguments: +# cache-type - Cache type (e.g., haf_btracker_sync, haf_hafbe_sync) +# cache-key - Cache key (e.g., ${HAF_COMMIT}_${CI_COMMIT_SHORT_SHA}) +# dest-dir - Destination directory for extracted cache +# +# Environment variables: +# CACHE_MANAGER - Path to cache-manager.sh (fetched if not set) +# CACHE_MANAGER_REF - Git ref for cache-manager (default: develop) +# CI_PIPELINE_ID - GitLab pipeline ID (for marker file) +# POSTGRES_HOST - PostgreSQL host for readiness check (default: none) +# POSTGRES_PORT - PostgreSQL port (default: 5432) +# EXTRACT_TIMEOUT - Timeout for PostgreSQL wait in seconds (default: 300) +# SKIP_POSTGRES_WAIT - Set to "true" to skip PostgreSQL wait +# +# Exit codes: +# 0 - Success +# 1 - Error (cache not found, extraction failed, or timeout) +# ============================================================================= + +set -euo pipefail + +# Arguments +CACHE_TYPE="${1:?Usage: $0 }" +CACHE_KEY="${2:?Usage: $0 }" +DEST_DIR="${3:?Usage: $0 }" + +# Configuration from environment +CACHE_MANAGER="${CACHE_MANAGER:-/tmp/cache-manager.sh}" +CACHE_MANAGER_REF="${CACHE_MANAGER_REF:-develop}" +POSTGRES_HOST="${POSTGRES_HOST:-}" +POSTGRES_PORT="${POSTGRES_PORT:-5432}" +EXTRACT_TIMEOUT="${EXTRACT_TIMEOUT:-300}" +SKIP_POSTGRES_WAIT="${SKIP_POSTGRES_WAIT:-false}" + +# Marker file location +MARKER_FILE="${DEST_DIR}/.cache-ready" + +echo "=== HAF App Test Cache Extraction ===" +echo "Cache type: ${CACHE_TYPE}" +echo "Cache key: ${CACHE_KEY}" +echo "Dest dir: ${DEST_DIR}" +echo "Pipeline: ${CI_PIPELINE_ID:-local}" +echo "" + +# ----------------------------------------------------------------------------- +# Fetch cache-manager if needed +# ----------------------------------------------------------------------------- +if [[ ! -x "$CACHE_MANAGER" ]]; then + echo "Fetching cache-manager from common-ci-configuration (ref: ${CACHE_MANAGER_REF})..." + mkdir -p "$(dirname "$CACHE_MANAGER")" + curl -fsSL "https://gitlab.syncad.com/hive/common-ci-configuration/-/raw/${CACHE_MANAGER_REF}/scripts/cache-manager.sh" -o "$CACHE_MANAGER" + chmod +x "$CACHE_MANAGER" +fi + +# ----------------------------------------------------------------------------- +# Check if extraction already done for this pipeline +# ----------------------------------------------------------------------------- +if [[ -f "$MARKER_FILE" ]]; then + MARKER_PIPELINE=$(cat "$MARKER_FILE" 2>/dev/null || echo "") + if [[ "$MARKER_PIPELINE" == "${CI_PIPELINE_ID:-local}" ]]; then + echo "Cache already extracted for this pipeline (marker: ${MARKER_PIPELINE})" + echo "Skipping extraction" + # Still wait for postgres if needed + if [[ -n "$POSTGRES_HOST" ]] && [[ "$SKIP_POSTGRES_WAIT" != "true" ]]; then + echo "" + echo "=== Waiting for PostgreSQL ===" + WAITED=0 + while ! pg_isready -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -q 2>/dev/null; do + sleep 5 + WAITED=$((WAITED + 5)) + if [[ $WAITED -ge $EXTRACT_TIMEOUT ]]; then + echo "WARNING: PostgreSQL not ready after ${EXTRACT_TIMEOUT}s" + break + fi + echo "Waiting for PostgreSQL... (${WAITED}s)" + done + [[ $WAITED -lt $EXTRACT_TIMEOUT ]] && echo "PostgreSQL ready!" + fi + exit 0 + fi + echo "Marker file exists but for different pipeline: ${MARKER_PIPELINE}" +fi + +# ----------------------------------------------------------------------------- +# Check if PostgreSQL is already running (files may be in use) +# ----------------------------------------------------------------------------- +if [[ -n "$POSTGRES_HOST" ]]; then + if pg_isready -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -q 2>/dev/null; then + echo "PostgreSQL is already running - data may be in use" + echo "Updating marker and skipping extraction" + mkdir -p "${DEST_DIR}" + echo "${CI_PIPELINE_ID:-local}" > "$MARKER_FILE" + exit 0 + fi +fi + +# ----------------------------------------------------------------------------- +# Check if valid data already exists +# ----------------------------------------------------------------------------- +PGDATA="${DEST_DIR}/datadir/pgdata" +if [[ -d "$PGDATA" ]] && [[ -f "$PGDATA/PG_VERSION" ]]; then + echo "Valid PostgreSQL data exists at: $PGDATA" + echo "Updating marker and skipping extraction" + mkdir -p "${DEST_DIR}" + echo "${CI_PIPELINE_ID:-local}" > "$MARKER_FILE" + # Still wait for postgres if needed + if [[ -n "$POSTGRES_HOST" ]] && [[ "$SKIP_POSTGRES_WAIT" != "true" ]]; then + echo "" + echo "=== Waiting for PostgreSQL ===" + WAITED=0 + while ! pg_isready -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -q 2>/dev/null; do + sleep 5 + WAITED=$((WAITED + 5)) + if [[ $WAITED -ge $EXTRACT_TIMEOUT ]]; then + echo "WARNING: PostgreSQL not ready after ${EXTRACT_TIMEOUT}s" + break + fi + echo "Waiting for PostgreSQL... (${WAITED}s)" + done + [[ $WAITED -lt $EXTRACT_TIMEOUT ]] && echo "PostgreSQL ready!" + fi + exit 0 +fi + +# ----------------------------------------------------------------------------- +# Extract cache (exact key match only - no fallback) +# ----------------------------------------------------------------------------- +echo "=== Extracting Cache ===" +echo "Key: ${CACHE_TYPE}/${CACHE_KEY}" + +# Create destination and clean any partial data +mkdir -p "${DEST_DIR}" + +if CACHE_HANDLING=haf "$CACHE_MANAGER" get "${CACHE_TYPE}" "${CACHE_KEY}" "${DEST_DIR}"; then + echo "Cache extracted successfully" +else + echo "" + echo "ERROR: Cache not found for key: ${CACHE_KEY}" + echo "" + echo "The sync job must complete successfully before test jobs can run." + echo "Cache key includes both HAF commit and app commit to ensure schema compatibility." + echo "" + echo "Possible causes:" + echo " - Sync job did not complete successfully" + echo " - NFS cache not accessible from this runner" + echo " - Cache was cleaned up" + exit 1 +fi + +# ----------------------------------------------------------------------------- +# Fix PostgreSQL permissions (must be 700 for pg_ctl) +# ----------------------------------------------------------------------------- +if [[ -d "$PGDATA" ]]; then + echo "" + echo "=== Fixing PostgreSQL Permissions ===" + chmod 700 "$PGDATA" 2>/dev/null || sudo chmod 700 "$PGDATA" || true + echo "Set $PGDATA permissions to 700" +fi + +# ----------------------------------------------------------------------------- +# Write marker file +# ----------------------------------------------------------------------------- +echo "${CI_PIPELINE_ID:-local}" > "$MARKER_FILE" +echo "Created marker file: $MARKER_FILE" + +# ----------------------------------------------------------------------------- +# Wait for PostgreSQL if configured +# ----------------------------------------------------------------------------- +if [[ -n "$POSTGRES_HOST" ]] && [[ "$SKIP_POSTGRES_WAIT" != "true" ]]; then + echo "" + echo "=== Waiting for PostgreSQL ===" + echo "Host: ${POSTGRES_HOST}:${POSTGRES_PORT}" + echo "Timeout: ${EXTRACT_TIMEOUT}s" + + WAITED=0 + while ! pg_isready -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -q 2>/dev/null; do + sleep 5 + WAITED=$((WAITED + 5)) + if [[ $WAITED -ge $EXTRACT_TIMEOUT ]]; then + echo "" + echo "WARNING: PostgreSQL not ready after ${EXTRACT_TIMEOUT}s" + echo "Container may not have started yet - this is OK if docker-compose runs after this script" + exit 0 + fi + echo "Waiting for PostgreSQL... (${WAITED}s)" + done + echo "PostgreSQL ready after ${WAITED}s" +fi + +echo "" +echo "=== Done ===" diff --git a/templates/haf_app_testing.gitlab-ci.yml b/templates/haf_app_testing.gitlab-ci.yml index 88190b0..d124091 100644 --- a/templates/haf_app_testing.gitlab-ci.yml +++ b/templates/haf_app_testing.gitlab-ci.yml @@ -29,6 +29,8 @@ variables: # Cache manager configuration CACHE_MANAGER: "/tmp/cache-manager.sh" CACHE_MANAGER_REF: "develop" + # Test cache extraction script + EXTRACT_TEST_CACHE: "/tmp/extract-test-cache.sh" # NFS and local cache paths (standard across all builders) DATA_CACHE_NFS_PREFIX: "/nfs/ci-cache" @@ -201,6 +203,27 @@ include: echo "Cache manager ready: $CACHE_MANAGER (ref: ${CACHE_MANAGER_REF})" echo -e "\e[0Ksection_end:$(date +%s):cache_manager_setup\r\e[0K" +# Fetch extract-test-cache.sh script for test jobs +# This script handles cache extraction with marker files, PostgreSQL wait, and proper error handling. +# Usage: +# before_script: +# - !reference [.fetch_extract_test_cache, before_script] +# - $EXTRACT_TEST_CACHE "${APP_SYNC_CACHE_TYPE}" "${APP_CACHE_KEY}" "${HAF_DATA_DIRECTORY}" +# +# Environment variables (optional): +# POSTGRES_HOST - If set, waits for PostgreSQL readiness +# SKIP_POSTGRES_WAIT - Set to "true" to skip wait +# EXTRACT_TIMEOUT - Timeout in seconds (default: 300) +.fetch_extract_test_cache: + before_script: + - | + echo -e "\e[0Ksection_start:$(date +%s):extract_cache_setup[collapsed=true]\r\e[0KSetting up extract-test-cache..." + EXTRACT_TEST_CACHE="/tmp/extract-test-cache.sh" + curl -fsSL "https://gitlab.syncad.com/hive/common-ci-configuration/-/raw/${CACHE_MANAGER_REF}/scripts/extract-test-cache.sh" -o "$EXTRACT_TEST_CACHE" + chmod +x "$EXTRACT_TEST_CACHE" + echo "Extract script ready: $EXTRACT_TEST_CACHE (ref: ${CACHE_MANAGER_REF})" + echo -e "\e[0Ksection_end:$(date +%s):extract_cache_setup\r\e[0K" + # ============================================================================= # CHANGE DETECTION TEMPLATE # ============================================================================= -- GitLab