#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" . "$ROOT_DIR/scripts/lib.sh" load_env TIMESTAMP="$(date +%Y%m%d%H%M%S)" DIAG_DIR="$ROOT_DIR/dist/doctor-${TIMESTAMP}" DIAG_ARCHIVE="$ROOT_DIR/dist/doctor-${TIMESTAMP}.tar.gz" audit "doctor" "STARTED" "collecting diagnostics" progress "doctor" "STARTED" "collecting diagnostics" mkdir -p "$DIAG_DIR" # System info { printf '=== System Info ===\n' uname -a 2>/dev/null || true printf '\n=== Docker Version ===\n' docker version 2>/dev/null || true printf '\n=== Disk Usage ===\n' df -h "$ROOT_DIR" 2>/dev/null || true printf '\n=== Memory ===\n' free -h 2>/dev/null || vm_stat 2>/dev/null || true } > "$DIAG_DIR/system.txt" # Container states compose ps 2>/dev/null > "$DIAG_DIR/containers.txt" || true # Last healthcheck (already sanitized — no secrets) [ -f "$ROOT_DIR/.deploy-state/last-healthcheck.json" ] && \ cp "$ROOT_DIR/.deploy-state/last-healthcheck.json" "$DIAG_DIR/" # Deploy state cp "$ROOT_DIR/.deploy-state/progress.md" "$DIAG_DIR/" 2>/dev/null || true # Sanitized env (strip secrets) grep -v -E '(PASSWORD|SECRET|TOKEN|KEY|SMTP|AUTH)' "$ROOT_DIR/.env" 2>/dev/null \ > "$DIAG_DIR/env-sanitized.txt" || true grep -v -E '(PASSWORD|SECRET|TOKEN|KEY|SMTP|AUTH)' "$ROOT_DIR/config/xuqm.env" 2>/dev/null \ >> "$DIAG_DIR/env-sanitized.txt" || true # Recent audit log (last 200 lines) tail -200 "$ROOT_DIR/logs/audit.log" 2>/dev/null > "$DIAG_DIR/audit-recent.log" || true # Recent container logs (last 100 lines per service, sanitized) for svc in tenant-service file-service nginx im-service push-service update-service license-service; do CTR="$(compose ps -q "$svc" 2>/dev/null | head -1 || true)" if [ -n "$CTR" ]; then docker logs --tail=100 "$CTR" 2>&1 | \ grep -v -E '(password|secret|token|Authorization)' \ > "$DIAG_DIR/log-${svc}.txt" 2>/dev/null || true fi done # Vendor API connectivity checks (DNS + TCP only, no credentials sent) { printf '=== Vendor API Connectivity ===\n' vendor_check() { local name="$1" local host="$2" local port="${3:-443}" printf '\n%s (%s:%s): ' "$name" "$host" "$port" if command -v nc >/dev/null 2>&1; then if nc -z -w5 "$host" "$port" 2>/dev/null; then printf 'TCP OK\n' else printf 'TCP FAIL\n' fi elif command -v curl >/dev/null 2>&1; then HTTP_CODE="$(curl -skL -o /dev/null -w '%{http_code}' --max-time 5 "https://$host" 2>/dev/null || echo '000')" printf 'HTTP %s\n' "$HTTP_CODE" else printf 'SKIPPED (no nc/curl)\n' fi } if [ "${ENABLE_PUSH:-false}" = "true" ]; then vendor_check "Huawei Push" "push-api.cloud.huawei.com" 443 vendor_check "Xiaomi Push" "api.xmpush.xiaomi.com" 443 vendor_check "OPPO Push" "api.push.oppomobile.com" 443 vendor_check "vivo Push" "api-push.vivo.com.cn" 443 vendor_check "APNs" "api.push.apple.com" 443 fi if [ "${ENABLE_UPDATE:-false}" = "true" ]; then vendor_check "Huawei AppGallery" "connect-api.cloud.huawei.com" 443 vendor_check "Xiaomi Store" "api.developer.xiaomi.com" 443 vendor_check "OPPO Store" "oop-openapi.oppomobile.com" 443 vendor_check "vivo Store" "developer.vivo.com.cn" 443 vendor_check "Honor Store" "developer.hihonor.com" 443 fi } > "$DIAG_DIR/vendor-connectivity.txt" 2>&1 # Certificate expiry check if [ -n "${CONSOLE_DOMAIN:-}" ] && command -v openssl >/dev/null 2>&1; then HOST="$(printf '%s' "${CONSOLE_DOMAIN#https://}" | cut -d'/' -f1)" { printf '=== TLS Certificate Expiry ===\n' printf '%s\n' "$HOST" openssl s_client -connect "${HOST}:443" -servername "$HOST" /dev/null | \ openssl x509 -noout -dates 2>/dev/null || printf 'Could not check certificate\n' } > "$DIAG_DIR/cert-expiry.txt" 2>&1 fi # Package into archive tar -czf "$DIAG_ARCHIVE" -C "$ROOT_DIR/dist" "doctor-${TIMESTAMP}" rm -rf "$DIAG_DIR" audit "doctor" "DONE" "archive=$DIAG_ARCHIVE" progress "doctor" "DONE" "archive=$DIAG_ARCHIVE" printf 'Diagnostics collected: %s\n' "$DIAG_ARCHIVE"