diff --git a/backend/routers/agent.py b/backend/routers/agent.py index 2a7d65a..c6d90e5 100644 --- a/backend/routers/agent.py +++ b/backend/routers/agent.py @@ -996,6 +996,17 @@ async def agent_config_validation_failed(agent_name: str, notification_data: dic # Store validation error in config_versions table for UI display async with conn.transaction(): + # CRITICAL DEBUG: Log exact version being searched + logger.info(f"VALIDATION-FAILED: Searching for version_name='{version}' in cluster_id={cluster_id}") + + # First, check what versions exist for this cluster (for debugging) + existing_versions = await conn.fetch(""" + SELECT version_name, status, is_active FROM config_versions + WHERE cluster_id = $1 AND is_active = TRUE + ORDER BY created_at DESC LIMIT 3 + """, cluster_id) + logger.info(f"VALIDATION-FAILED: Active versions in cluster: {[v['version_name'] for v in existing_versions]}") + # Update the config_version with validation error result = await conn.execute(""" UPDATE config_versions @@ -1005,6 +1016,23 @@ async def agent_config_validation_failed(agent_name: str, notification_data: dic WHERE cluster_id = $2 AND version_name = $3 """, validation_error, cluster_id, version) + # CRITICAL: Check if UPDATE actually affected any rows + rows_affected = int(result.split()[-1]) if result else 0 + if rows_affected == 0: + logger.error(f"VALIDATION-FAILED: UPDATE affected 0 rows! version_name '{version}' NOT FOUND in cluster {cluster_id}") + # Try to update the active version instead as fallback + fallback_result = await conn.execute(""" + UPDATE config_versions + SET validation_error = $1, + validation_error_reported_at = CURRENT_TIMESTAMP, + updated_at = CURRENT_TIMESTAMP + WHERE cluster_id = $2 AND is_active = TRUE + """, validation_error, cluster_id) + fallback_rows = int(fallback_result.split()[-1]) if fallback_result else 0 + logger.info(f"VALIDATION-FAILED: Fallback UPDATE to active version affected {fallback_rows} rows") + else: + logger.info(f"VALIDATION-FAILED: UPDATE affected {rows_affected} rows for version '{version}'") + # Also update agent status to indicate validation failure await conn.execute(""" UPDATE agents diff --git a/backend/utils/agent_scripts/linux_install.sh b/backend/utils/agent_scripts/linux_install.sh index 488a010..9954742 100644 --- a/backend/utils/agent_scripts/linux_install.sh +++ b/backend/utils/agent_scripts/linux_install.sh @@ -1720,8 +1720,10 @@ check_config_updates() { # This prevents including 'listen stats' in global when it comes before defaults awk '/^(defaults|listen|frontend|backend)[[:space:]]/{exit} {print}' "$HAPROXY_CONFIG_PATH" > /tmp/haproxy-global-$$.cfg 2>/dev/null - # Extract defaults section (from 'defaults' until first 'frontend/backend/listen') - awk '/^defaults[[:space:]]*$/{flag=1} /^(frontend|backend|listen)[[:space:]]/{if(flag && !/^defaults/) exit} flag{print}' "$HAPROXY_CONFIG_PATH" > /tmp/haproxy-defaults-$$.cfg 2>/dev/null + # Extract defaults section (ONLY the FIRST defaults section) + # CRITICAL FIX: Exit at ANY section header including another 'defaults' + # This prevents capturing multiple defaults sections if config is malformed + awk 'BEGIN{started=0} /^defaults[[:space:]]*$/{if(started) exit; started=1} /^(frontend|backend|listen)[[:space:]]/{if(started) exit} started{print}' "$HAPROXY_CONFIG_PATH" > /tmp/haproxy-defaults-$$.cfg 2>/dev/null # Extract all listen sections (preserve existing listen blocks like stats monitoring) # This extracts ALL listen blocks from existing config to preserve them @@ -2897,9 +2899,10 @@ CONFIG_RESPONSE_EOF # This prevents including 'listen stats' in global when it comes before defaults awk '/^(defaults|listen|frontend|backend)[[:space:]]/{exit} {print}' "$HAPROXY_CONFIG" > /tmp/haproxy-global.cfg 2>/dev/null - # Extract defaults section (from 'defaults' to first 'frontend/backend/listen') - # CRITICAL FIX: Exit BEFORE printing the frontend/backend/listen line - awk '/^defaults[[:space:]]*$/{flag=1} /^(frontend|backend|listen)[[:space:]]/{if(flag && !/^defaults/) exit} flag{print}' "$HAPROXY_CONFIG" > /tmp/haproxy-defaults.cfg 2>/dev/null + # Extract defaults section (ONLY the FIRST defaults section) + # CRITICAL FIX: Exit at ANY section header including another 'defaults' + # This prevents capturing multiple defaults sections if config is malformed + awk 'BEGIN{started=0} /^defaults[[:space:]]*$/{if(started) exit; started=1} /^(frontend|backend|listen)[[:space:]]/{if(started) exit} started{print}' "$HAPROXY_CONFIG" > /tmp/haproxy-defaults.cfg 2>/dev/null # Extract all listen sections (preserve existing listen blocks like stats monitoring) # CRITICAL FIX: Extract ALL listen blocks from existing config to preserve them diff --git a/backend/utils/agent_scripts/macos_install.sh b/backend/utils/agent_scripts/macos_install.sh index d0c6c41..56bfd90 100644 --- a/backend/utils/agent_scripts/macos_install.sh +++ b/backend/utils/agent_scripts/macos_install.sh @@ -1666,8 +1666,10 @@ check_config_updates() { # This prevents including 'listen stats' in global when it comes before defaults awk '/^(defaults|listen|frontend|backend)[[:space:]]/{exit} {print}' "$HAPROXY_CONFIG_PATH" > /tmp/haproxy-global-$$.cfg 2>/dev/null - # Extract defaults section (from 'defaults' until first 'frontend/backend/listen') - awk '/^defaults[[:space:]]*$/{flag=1} /^(frontend|backend|listen)[[:space:]]/{if(flag && !/^defaults/) exit} flag{print}' "$HAPROXY_CONFIG_PATH" > /tmp/haproxy-defaults-$$.cfg 2>/dev/null + # Extract defaults section (ONLY the FIRST defaults section) + # CRITICAL FIX: Exit at ANY section header including another 'defaults' + # This prevents capturing multiple defaults sections if config is malformed + awk 'BEGIN{started=0} /^defaults[[:space:]]*$/{if(started) exit; started=1} /^(frontend|backend|listen)[[:space:]]/{if(started) exit} started{print}' "$HAPROXY_CONFIG_PATH" > /tmp/haproxy-defaults-$$.cfg 2>/dev/null # Extract all listen sections (preserve existing listen blocks like stats monitoring) # This extracts ALL listen blocks from existing config to preserve them @@ -2845,9 +2847,10 @@ CONFIG_RESPONSE_EOF # This prevents including 'listen stats' in global when it comes before defaults awk '/^(defaults|listen|frontend|backend)[[:space:]]/{exit} {print}' "$HAPROXY_CONFIG" > /tmp/haproxy-global.cfg 2>/dev/null - # Extract defaults section (from 'defaults' to first 'frontend/backend/listen') - # CRITICAL FIX: Exit BEFORE printing the frontend/backend/listen line - awk '/^defaults[[:space:]]*$/{flag=1} /^(frontend|backend|listen)[[:space:]]/{if(flag && !/^defaults/) exit} flag{print}' "$HAPROXY_CONFIG" > /tmp/haproxy-defaults.cfg 2>/dev/null + # Extract defaults section (ONLY the FIRST defaults section) + # CRITICAL FIX: Exit at ANY section header including another 'defaults' + # This prevents capturing multiple defaults sections if config is malformed + awk 'BEGIN{started=0} /^defaults[[:space:]]*$/{if(started) exit; started=1} /^(frontend|backend|listen)[[:space:]]/{if(started) exit} started{print}' "$HAPROXY_CONFIG" > /tmp/haproxy-defaults.cfg 2>/dev/null # Extract all listen sections (preserve existing listen blocks like stats monitoring) # CRITICAL FIX: Extract ALL listen blocks from existing config to preserve them