Files
cozystack/hack/cozyreport-summary.sh
Myasnikov DaniilandClaude Opus 4.7 b40ab290eb fix(cozyreport): portability and Ready-filter fixes from review
- Resolve hack/cozyreport-summary.sh via SCRIPT_DIR so cozyreport.sh
  can be invoked from any working directory, not only the repo root.
- Discover Talos node IPs via `kubectl get nodes` (with the existing
  192.168.123.11-13 list as fallback) instead of hardcoding the E2E
  sandbox topology.
- Replace broken `awk '$NF != "True"'` filter on the cozystack-apps
  loop with a jsonpath check against the Ready condition; the previous
  filter compared AGE ("10m" etc.) against "True" and let every
  resource through, defeating the non-Ready filter.
- Switch the Flux source CRD summary loop from column parsing to
  jsonpath (column positions differ between HelmRepository and
  OCIRepository printer columns) and add ExternalArtifact, matching
  what cozyreport.sh already collects.
- Add `kubectl get crd` guards before HR/source CRD queries so the
  summary script does not abort under `set -eu` when Flux v2 is not
  installed.
- Relabel "OOMKilled in last 30 min" to "Recent OOMKilled events
  (last 20)" — the kubectl call only limits count, not time.

Surfaced from coderabbit and gemini review on #2553.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-05-04 11:17:35 +05:00

70 lines
2.6 KiB
Bash
Executable File

#!/bin/sh
# Emit a human-readable summary of "what is broken" to a single file.
# Reads the live cluster (not the report dir) so it can use kubectl JSONPath.
# Usage: cozyreport-summary.sh > summary.txt
set -eu
echo "# Cozystack E2E Diagnostic Summary"
echo "Generated: $(date -Iseconds)"
echo
echo "## HelmReleases not Ready"
echo
if kubectl get crd helmreleases.helm.toolkit.fluxcd.io >/dev/null 2>&1; then
kubectl get hr -A --no-headers 2>/dev/null \
| awk '$4 != "True" {printf " %s/%s — %s\n", $1, $2, $5}' \
| head -40
fi
echo
echo "## Pods not Running/Succeeded"
echo
kubectl get pod -A --no-headers 2>/dev/null \
| awk '$4 !~ /Running|Succeeded|Completed/ {printf " %s/%s — %s (restarts=%s, age=%s)\n", $1, $2, $4, $5, $6}' \
| head -40
echo
echo "## ImagePullBackOff / ErrImagePull"
echo
kubectl get pod -A --no-headers 2>/dev/null \
| awk '$4 ~ /ImagePullBackOff|ErrImagePull/ {printf " %s/%s — %s\n", $1, $2, $4}'
echo
echo "## Recent OOMKilled events (last 20)"
echo
kubectl get events -A --field-selector reason=OOMKilling --sort-by=.lastTimestamp 2>/dev/null \
| tail -20
echo
echo "## Recent Warning events (top 30)"
echo
kubectl get events -A --field-selector type=Warning --sort-by=.lastTimestamp 2>/dev/null \
| tail -30
echo
echo "## cert-manager: Certificates not Ready"
echo
if kubectl get crd certificates.cert-manager.io >/dev/null 2>&1; then
kubectl get certificates.cert-manager.io -A --no-headers 2>/dev/null \
| awk '$3 != "True" {printf " %s/%s — Ready=%s\n", $1, $2, $3}'
fi
echo
echo "## Flux Sources not Ready"
echo
for kind in helmrepositories.source.toolkit.fluxcd.io ocirepositories.source.toolkit.fluxcd.io gitrepositories.source.toolkit.fluxcd.io externalartifacts.source.toolkit.fluxcd.io; do
kubectl get crd "$kind" >/dev/null 2>&1 || continue
short=${kind%%.*}
kubectl get "$kind" -A -o jsonpath='{range .items[?(@.status.conditions[?(@.type=="Ready")].status!="True")]} '"$short"' {.metadata.namespace}/{.metadata.name} — Ready={.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}' 2>/dev/null
done
echo
echo "## Storage: PVCs not Bound, PVs not Bound"
echo
kubectl get pvc -A --no-headers 2>/dev/null | awk '$3 != "Bound" {printf " PVC %s/%s — %s\n", $1, $2, $3}'
kubectl get pv --no-headers 2>/dev/null | awk '$5 != "Bound" {printf " PV %s — %s\n", $1, $5}'
echo
echo "## Node Conditions"
kubectl get nodes -o custom-columns=NAME:.metadata.name,READY:.status.conditions[?\(@.type==\"Ready\"\)].status,DISK:.status.conditions[?\(@.type==\"DiskPressure\"\)].status,MEM:.status.conditions[?\(@.type==\"MemoryPressure\"\)].status 2>/dev/null