fix: defaults extraction captures only first defaults section

CRITICAL BUG FIX:
- Previous awk pattern allowed multiple defaults sections to be captured
- Pattern `!/^defaults/` meant "don't exit if line IS defaults"
- This caused duplicate defaults when config had listen before defaults

New pattern uses `started` flag:
- First `defaults` line: set started=1, begin capturing
- Second `defaults` line: started is set, EXIT immediately
- Any `frontend/backend/listen`: started is set, EXIT

Also includes: debug logging for validation error storage with fallback

Tested scenarios:
- Normal config (defaults → listen → frontend): ✓
- Listen before defaults: ✓
- Two defaults sections: ✓ Only first captured
- No defaults section: ✓ Empty output
- Defaults at end of file: ✓
- Empty defaults section: ✓
This commit is contained in:
taylanbakircioglu
2026-01-26 15:25:15 +03:00
parent 4a6bc1b139
commit 995d87df43
3 changed files with 44 additions and 10 deletions
+28
View File
@@ -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
+8 -5
View File
@@ -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
+8 -5
View File
@@ -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