Skip to content

Instantly share code, notes, and snippets.

@venkata-qa
Last active April 9, 2025 17:29
Show Gist options
  • Save venkata-qa/ac45986cceb15268a1053ec1ecad3dd5 to your computer and use it in GitHub Desktop.
Save venkata-qa/ac45986cceb15268a1053ec1ecad3dd5 to your computer and use it in GitHub Desktop.

Revisions

  1. venkata-qa revised this gist Apr 9, 2025. 1 changed file with 38 additions and 21 deletions.
    59 changes: 38 additions & 21 deletions k8s_report_v4.sh
    Original file line number Diff line number Diff line change
    @@ -17,8 +17,9 @@ add_subheading() {
    echo -e "\n### $1\n" >> "$REPORT_FILE"
    }

    # Report header
    cat <<EOF > "$REPORT_FILE"
    # Kubernetes Release Report
    # πŸš€ Kubernetes Release Report
    - **Namespace**: \`$NAMESPACE\`
    - **Generated**: \`$TIMESTAMP\`
    @@ -43,67 +44,82 @@ echo '| Status | Count |' >> "$REPORT_FILE"
    echo '|--------|-------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" --no-headers -o custom-columns=STATUS:.status.phase | sort | uniq -c | awk '{printf "| %s | %s |\n", $2, $1}' >> "$REPORT_FILE"


    # 3. Pod Health Summary
    echo "## πŸ”Ή Pod Health Summary"
    # 3.0 Expected vs Running Pods
    add_subheading "3.0 Expected vs Running Pods"
    DEPLOY_REPLICAS=$(kubectl get deployments -n "$NAMESPACE" -o json | jq '[.items[].spec.replicas // 0] | add')
    STS_REPLICAS=$(kubectl get statefulsets -n "$NAMESPACE" -o json | jq '[.items[].spec.replicas // 0] | add')
    DS_REPLICAS=$(kubectl get daemonsets -n "$NAMESPACE" -o json | jq '[.items[].status.desiredNumberScheduled // 0] | add')
    EXPECTED=$((DEPLOY_REPLICAS + STS_REPLICAS + DS_REPLICAS))
    RUNNING=$(kubectl get pods -n "$NAMESPACE" --field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l)

    echo '| Source | Expected Pods |' >> "$REPORT_FILE"
    echo '|---------------|----------------|' >> "$REPORT_FILE"
    echo "| Deployments | $DEPLOY_REPLICAS |" >> "$REPORT_FILE"
    echo "| StatefulSets | $STS_REPLICAS |" >> "$REPORT_FILE"
    echo "| DaemonSets | $DS_REPLICAS |" >> "$REPORT_FILE"
    echo "| **Total Expected** | **$EXPECTED** |" >> "$REPORT_FILE"
    echo "| **Running Pods** | **$RUNNING** |" >> "$REPORT_FILE"

    # 3.1 Pod Health Summary (to file)
    add_subheading "3.1 Pod Health Summary"
    POD_TOTAL=$(kubectl get pods -n "$NAMESPACE" --no-headers 2>/dev/null | wc -l)
    POD_RUNNING=$(kubectl get pods -n "$NAMESPACE" --field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l)
    CRASHING_PODS=$(kubectl get pods -n "$NAMESPACE" -o json 2>/dev/null | jq '[.items[] | select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff")] | length')

    echo "- **Total Pods**: $POD_TOTAL"
    echo "- **Running Pods**: $POD_RUNNING"
    echo "- **CrashLoopBackOff Pods**: $CRASHING_PODS"
    echo ""
    echo "- **Total Pods**: $POD_TOTAL" >> "$REPORT_FILE"
    echo "- **Running Pods**: $POD_RUNNING" >> "$REPORT_FILE"
    echo "- **CrashLoopBackOff Pods**: $CRASHING_PODS" >> "$REPORT_FILE"

    # 3.2 CrashLoopBackOff Pods
    add_subheading "3.1 CrashLoopBackOff Pods"
    add_subheading "3.2 CrashLoopBackOff Pods"
    echo '| Pod Name | Node | Restarts |' >> "$REPORT_FILE"
    echo '|----------|------|----------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" -o json | jq -r '
    .items[] |
    select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff") |
    [.metadata.name, .spec.nodeName, .status.containerStatuses[0].restartCount] | @tsv' |
    [.metadata.name, .spec.nodeName, (.status.containerStatuses[0].restartCount // 0)] | @tsv' |
    while IFS=$'\t' read -r pod node restarts; do
    printf "| %s | %s | %s |\n" "$pod" "$node" "$restarts"
    done >> "$REPORT_FILE"

    # 4. Images Used
    # 4. Deployed Images
    add_heading "4. Deployed Images"

    # 4.1 App images
    add_subheading "4.1 Application Images"
    echo '| Image | Version |' >> "$REPORT_FILE"
    echo '|--------|---------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" -o json | jq -r '
    [.items[].spec.containers[].image] | unique | .[] | select(test("istio|proxy|envoy|sidecar") | not)' | sort |
    while read image; do
    while read -r image; do
    base=$(echo "$image" | cut -d":" -f1)
    tag=$(echo "$image" | cut -d":" -f2)
    echo "| $base | ${tag:-latest} |"
    done >> "$REPORT_FILE"


    # 4.2 Sidecar images
    add_subheading "4.2 Sidecar Images"
    echo '| Image | Version |' >> "$REPORT_FILE"
    echo '|--------|---------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" -o json | jq -r '
    [.items[].spec.containers[].image] | unique | .[] | select(test("istio|proxy|envoy|sidecar"))' | sort |
    while read image; do
    while read -r image; do
    base=$(echo "$image" | cut -d":" -f1)
    tag=$(echo "$image" | cut -d":" -f2)
    echo "| $base | ${tag:-latest} |"
    done >> "$REPORT_FILE"


    # 5. Top 5 Pods by CPU Usage
    # 5. Top Resource Usage Pods
    add_heading "5. Top Resource Usage Pods"
    echo '| Pod Name | CPU (m) | Memory (Mi) |' >> "$REPORT_FILE"
    echo '|----------|---------|-------------|' >> "$REPORT_FILE"
    kubectl top pods -n "$NAMESPACE" --no-headers 2>/dev/null | sort -k2 -rh | head -n 5 | awk '{printf "| %s | %s | %s |\n", $1, $2, $3}' >> "$REPORT_FILE" || echo '| Metrics unavailable | - | - |' >> "$REPORT_FILE"
    kubectl top pods -n "$NAMESPACE" --no-headers 2>/dev/null | sort -k2 -rh | head -n 5 |
    awk '{printf "| %s | %s | %s |\n", $1, $2, $3}' >> "$REPORT_FILE" || echo '| Metrics unavailable | - | - |' >> "$REPORT_FILE"

    # 6. Summary of Events
    add_heading "6. Recent Warnings"
    # 6. Recent Warnings
    add_heading "6. Recent Warning Events"
    echo '| Type | Reason | Message | Time |' >> "$REPORT_FILE"
    echo '|------|--------|---------|------|' >> "$REPORT_FILE"

    kubectl get events -n "$NAMESPACE" --sort-by=.lastTimestamp -o json 2>/dev/null | jq -r '
    .items[]
    | select(.type == "Warning")
    @@ -114,7 +130,8 @@ kubectl get events -n "$NAMESPACE" --sort-by=.lastTimestamp -o json 2>/dev/null
    time: (.lastTimestamp // "N/A")
    }
    | [.type, .reason, .message, .time]
    | @tsv' | tail -n 10 | while IFS=$'\t' read -r type reason msg time; do
    | @tsv' | tail -n 10 |
    while IFS=$'\t' read -r type reason msg time; do
    printf "| %s | %s | %s | %s |\n" "$type" "$reason" "$msg" "$time"
    done >> "$REPORT_FILE"

  2. venkata-qa revised this gist Apr 9, 2025. 1 changed file with 13 additions and 4 deletions.
    17 changes: 13 additions & 4 deletions k8s_report_v4.sh
    Original file line number Diff line number Diff line change
    @@ -103,10 +103,19 @@ kubectl top pods -n "$NAMESPACE" --no-headers 2>/dev/null | sort -k2 -rh | head
    add_heading "6. Recent Warnings"
    echo '| Type | Reason | Message | Time |' >> "$REPORT_FILE"
    echo '|------|--------|---------|------|' >> "$REPORT_FILE"
    kubectl get events -n "$NAMESPACE" --sort-by=.lastTimestamp -o json | jq -r '
    .items[] | select(.type == "Warning") | [.type, .reason, (.message | gsub("[\n\r]+"; " ") | sub("^(.{0,60}).*"; "\1...")), .lastTimestamp] | @tsv' | tail -n 10 |
    while IFS=$'\t' read -r type reason msg time; do
    printf "| %s | %s | %s | %s |\n" "$type" "$reason" "$msg" "$time"

    kubectl get events -n "$NAMESPACE" --sort-by=.lastTimestamp -o json 2>/dev/null | jq -r '
    .items[]
    | select(.type == "Warning")
    | {
    type: .type,
    reason: .reason,
    message: (.message // "N/A") | tostring | gsub("[\n\r\t]+"; " ") | sub("^(.{0,60}).*"; "\1..."),
    time: (.lastTimestamp // "N/A")
    }
    | [.type, .reason, .message, .time]
    | @tsv' | tail -n 10 | while IFS=$'\t' read -r type reason msg time; do
    printf "| %s | %s | %s | %s |\n" "$type" "$reason" "$msg" "$time"
    done >> "$REPORT_FILE"

    echo -e "\nβœ… Minimal release report generated: $REPORT_FILE"
  3. venkata-qa revised this gist Apr 9, 2025. 1 changed file with 12 additions and 0 deletions.
    12 changes: 12 additions & 0 deletions k8s_report_v4.sh
    Original file line number Diff line number Diff line change
    @@ -43,6 +43,18 @@ echo '| Status | Count |' >> "$REPORT_FILE"
    echo '|--------|-------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" --no-headers -o custom-columns=STATUS:.status.phase | sort | uniq -c | awk '{printf "| %s | %s |\n", $2, $1}' >> "$REPORT_FILE"


    # 3. Pod Health Summary
    echo "## πŸ”Ή Pod Health Summary"
    POD_TOTAL=$(kubectl get pods -n "$NAMESPACE" --no-headers 2>/dev/null | wc -l)
    POD_RUNNING=$(kubectl get pods -n "$NAMESPACE" --field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l)
    CRASHING_PODS=$(kubectl get pods -n "$NAMESPACE" -o json 2>/dev/null | jq '[.items[] | select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff")] | length')

    echo "- **Total Pods**: $POD_TOTAL"
    echo "- **Running Pods**: $POD_RUNNING"
    echo "- **CrashLoopBackOff Pods**: $CRASHING_PODS"
    echo ""

    # 3.2 CrashLoopBackOff Pods
    add_subheading "3.1 CrashLoopBackOff Pods"
    echo '| Pod Name | Node | Restarts |' >> "$REPORT_FILE"
  4. venkata-qa revised this gist Apr 9, 2025. 1 changed file with 12 additions and 8 deletions.
    20 changes: 12 additions & 8 deletions k8s_report_v4.sh
    Original file line number Diff line number Diff line change
    @@ -61,22 +61,26 @@ add_subheading "4.1 Application Images"
    echo '| Image | Version |' >> "$REPORT_FILE"
    echo '|--------|---------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" -o json | jq -r '
    [.items[].spec.containers[]?.image] | unique[] | select(test("istio|proxy|envoy|sidecar") | not)' | sort | while read image; do
    base=$(echo "$image" | cut -d":" -f1)
    tag=$(echo "$image" | cut -d":" -f2)
    echo "| $base | ${tag:-latest} |"
    [.items[].spec.containers[].image] | unique | .[] | select(test("istio|proxy|envoy|sidecar") | not)' | sort |
    while read image; do
    base=$(echo "$image" | cut -d":" -f1)
    tag=$(echo "$image" | cut -d":" -f2)
    echo "| $base | ${tag:-latest} |"
    done >> "$REPORT_FILE"


    add_subheading "4.2 Sidecar Images"
    echo '| Image | Version |' >> "$REPORT_FILE"
    echo '|--------|---------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" -o json | jq -r '
    [.items[].spec.containers[]?.image] | unique[] | select(test("istio|proxy|envoy|sidecar"))' | sort | while read image; do
    base=$(echo "$image" | cut -d":" -f1)
    tag=$(echo "$image" | cut -d":" -f2)
    echo "| $base | ${tag:-latest} |"
    [.items[].spec.containers[].image] | unique | .[] | select(test("istio|proxy|envoy|sidecar"))' | sort |
    while read image; do
    base=$(echo "$image" | cut -d":" -f1)
    tag=$(echo "$image" | cut -d":" -f2)
    echo "| $base | ${tag:-latest} |"
    done >> "$REPORT_FILE"


    # 5. Top 5 Pods by CPU Usage
    add_heading "5. Top Resource Usage Pods"
    echo '| Pod Name | CPU (m) | Memory (Mi) |' >> "$REPORT_FILE"
  5. venkata-qa revised this gist Apr 9, 2025. 1 changed file with 83 additions and 62 deletions.
    145 changes: 83 additions & 62 deletions k8s_report_v4.sh
    Original file line number Diff line number Diff line change
    @@ -2,74 +2,95 @@

    NAMESPACE=$1
    if [[ -z "$NAMESPACE" ]]; then
    echo "❌ Usage: $0 <namespace>"
    exit 1
    echo "❌ Usage: $0 <namespace>"
    exit 1
    fi

    DATE=$(date "+%Y-%m-%d %H:%M:%S")
    REPORT_BASENAME="k8s_release_report_${NAMESPACE}_$(date +%Y%m%d)"
    MD_FILE="${REPORT_BASENAME}.md"
    TXT_FILE="${REPORT_BASENAME}.txt"

    # Common report header
    {
    echo "# πŸš€ Kubernetes Release Snapshot"
    echo ""
    echo "- **Namespace**: \`$NAMESPACE\`"
    echo "- **Cluster**: \`$(kubectl config current-context)\`"
    echo "- **Generated On**: \`$DATE\`"
    echo ""
    echo "---"
    echo ""
    TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
    REPORT_FILE="k8s_release_report_${NAMESPACE}_$(date +%Y%m%d).md"

    add_heading() {
    echo -e "\n## $1\n" >> "$REPORT_FILE"
    }

    add_subheading() {
    echo -e "\n### $1\n" >> "$REPORT_FILE"
    }

    cat <<EOF > "$REPORT_FILE"
    # Kubernetes Release Report
    - **Namespace**: \`$NAMESPACE\`
    - **Generated**: \`$TIMESTAMP\`
    - **Cluster Context**: \`$(kubectl config current-context 2>/dev/null)\`
    ---
    EOF

    # 1. Namespace Overview
    echo "## πŸ”Ή Namespace Overview"
    kubectl describe namespace "$NAMESPACE" --request-timeout=30s 2>/dev/null | grep -E 'Name:|Labels:|Status:' || echo "❌ Namespace not found"
    echo ""
    add_heading "1. Namespace Overview"
    kubectl describe namespace "$NAMESPACE" --request-timeout=30s 2>/dev/null | grep -E 'Name:|Labels:|Status:' >> "$REPORT_FILE"

    # 2. Deployment Summary
    echo "## πŸ”Ή Deployment Summary"
    kubectl get deployments -n "$NAMESPACE" -o wide --no-headers 2>/dev/null | \
    awk '{printf "- `%s` | Ready: **%s** | UpToDate: %s | Available: %s\n", $1, $2, $3, $4}' || echo "❌ No deployments found"
    echo ""

    # 3. Pod Health Summary
    echo "## πŸ”Ή Pod Health Summary"
    POD_TOTAL=$(kubectl get pods -n "$NAMESPACE" --no-headers 2>/dev/null | wc -l)
    POD_RUNNING=$(kubectl get pods -n "$NAMESPACE" --field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l)
    CRASHING_PODS=$(kubectl get pods -n "$NAMESPACE" -o json 2>/dev/null | jq '[.items[] | select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff")] | length')

    echo "- **Total Pods**: $POD_TOTAL"
    echo "- **Running Pods**: $POD_RUNNING"
    echo "- **CrashLoopBackOff Pods**: $CRASHING_PODS"
    echo ""

    # 4. CrashLoopBackOff Pods
    if [[ "$CRASHING_PODS" -gt 0 ]]; then
    echo "### πŸ”Έ CrashLoopBackOff Pods"
    echo '| Pod Name | Node | Restarts |'
    echo '|----------|------|----------|'
    kubectl get pods -n "$NAMESPACE" -o json 2>/dev/null |
    jq -r '
    .items[] |
    select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff") |
    [.metadata.name, .spec.nodeName, .status.containerStatuses[0].restartCount] |
    @tsv' | while IFS=$'\t' read -r pod node restarts; do
    echo "| $pod | $node | $restarts |"
    done
    echo ""
    fi
    add_heading "2. Deployment Summary"
    echo '| Deployment | Ready Replicas | Up-to-date | Available |' >> "$REPORT_FILE"
    echo '|------------|----------------|------------|-----------|' >> "$REPORT_FILE"
    kubectl get deployments -n "$NAMESPACE" --no-headers | awk '{printf "| %s | %s | %s | %s |\n", $1, $2, $3, $4}' >> "$REPORT_FILE"

    # 3. Pod Summary
    add_heading "3. Pod Summary"
    echo '| Status | Count |' >> "$REPORT_FILE"
    echo '|--------|-------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" --no-headers -o custom-columns=STATUS:.status.phase | sort | uniq -c | awk '{printf "| %s | %s |\n", $2, $1}' >> "$REPORT_FILE"

    # 3.2 CrashLoopBackOff Pods
    add_subheading "3.1 CrashLoopBackOff Pods"
    echo '| Pod Name | Node | Restarts |' >> "$REPORT_FILE"
    echo '|----------|------|----------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" -o json | jq -r '
    .items[] |
    select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff") |
    [.metadata.name, .spec.nodeName, .status.containerStatuses[0].restartCount] | @tsv' |
    while IFS=$'\t' read -r pod node restarts; do
    printf "| %s | %s | %s |\n" "$pod" "$node" "$restarts"
    done >> "$REPORT_FILE"

    # 4. Images Used
    add_heading "4. Deployed Images"
    add_subheading "4.1 Application Images"
    echo '| Image | Version |' >> "$REPORT_FILE"
    echo '|--------|---------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" -o json | jq -r '
    [.items[].spec.containers[]?.image] | unique[] | select(test("istio|proxy|envoy|sidecar") | not)' | sort | while read image; do
    base=$(echo "$image" | cut -d":" -f1)
    tag=$(echo "$image" | cut -d":" -f2)
    echo "| $base | ${tag:-latest} |"
    done >> "$REPORT_FILE"

    add_subheading "4.2 Sidecar Images"
    echo '| Image | Version |' >> "$REPORT_FILE"
    echo '|--------|---------|' >> "$REPORT_FILE"
    kubectl get pods -n "$NAMESPACE" -o json | jq -r '
    [.items[].spec.containers[]?.image] | unique[] | select(test("istio|proxy|envoy|sidecar"))' | sort | while read image; do
    base=$(echo "$image" | cut -d":" -f1)
    tag=$(echo "$image" | cut -d":" -f2)
    echo "| $base | ${tag:-latest} |"
    done >> "$REPORT_FILE"

    # 5. Deployed Images
    echo "## πŸ”Ή Deployed Images"
    kubectl get pods -n "$NAMESPACE" -o json 2>/dev/null |
    jq -r '.items[].spec.containers[].image' | sort -u |
    sed 's/^/- `/;s/$/`/'
    echo ""
    # 5. Top 5 Pods by CPU Usage
    add_heading "5. Top Resource Usage Pods"
    echo '| Pod Name | CPU (m) | Memory (Mi) |' >> "$REPORT_FILE"
    echo '|----------|---------|-------------|' >> "$REPORT_FILE"
    kubectl top pods -n "$NAMESPACE" --no-headers 2>/dev/null | sort -k2 -rh | head -n 5 | awk '{printf "| %s | %s | %s |\n", $1, $2, $3}' >> "$REPORT_FILE" || echo '| Metrics unavailable | - | - |' >> "$REPORT_FILE"

    echo "---"
    echo "βœ… Report generated successfully"
    } | tee "$MD_FILE" | sed 's/`//g' > "$TXT_FILE"
    # 6. Summary of Events
    add_heading "6. Recent Warnings"
    echo '| Type | Reason | Message | Time |' >> "$REPORT_FILE"
    echo '|------|--------|---------|------|' >> "$REPORT_FILE"
    kubectl get events -n "$NAMESPACE" --sort-by=.lastTimestamp -o json | jq -r '
    .items[] | select(.type == "Warning") | [.type, .reason, (.message | gsub("[\n\r]+"; " ") | sub("^(.{0,60}).*"; "\1...")), .lastTimestamp] | @tsv' | tail -n 10 |
    while IFS=$'\t' read -r type reason msg time; do
    printf "| %s | %s | %s | %s |\n" "$type" "$reason" "$msg" "$time"
    done >> "$REPORT_FILE"

    echo "πŸ“„ Markdown saved to: $MD_FILE"
    echo "πŸ“„ Plain text saved to: $TXT_FILE"
    echo -e "\nβœ… Minimal release report generated: $REPORT_FILE"
  6. venkata-qa created this gist Apr 9, 2025.
    75 changes: 75 additions & 0 deletions k8s_report_v4.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,75 @@
    #!/bin/bash

    NAMESPACE=$1
    if [[ -z "$NAMESPACE" ]]; then
    echo "❌ Usage: $0 <namespace>"
    exit 1
    fi

    DATE=$(date "+%Y-%m-%d %H:%M:%S")
    REPORT_BASENAME="k8s_release_report_${NAMESPACE}_$(date +%Y%m%d)"
    MD_FILE="${REPORT_BASENAME}.md"
    TXT_FILE="${REPORT_BASENAME}.txt"

    # Common report header
    {
    echo "# πŸš€ Kubernetes Release Snapshot"
    echo ""
    echo "- **Namespace**: \`$NAMESPACE\`"
    echo "- **Cluster**: \`$(kubectl config current-context)\`"
    echo "- **Generated On**: \`$DATE\`"
    echo ""
    echo "---"
    echo ""

    # 1. Namespace Overview
    echo "## πŸ”Ή Namespace Overview"
    kubectl describe namespace "$NAMESPACE" --request-timeout=30s 2>/dev/null | grep -E 'Name:|Labels:|Status:' || echo "❌ Namespace not found"
    echo ""

    # 2. Deployment Summary
    echo "## πŸ”Ή Deployment Summary"
    kubectl get deployments -n "$NAMESPACE" -o wide --no-headers 2>/dev/null | \
    awk '{printf "- `%s` | Ready: **%s** | UpToDate: %s | Available: %s\n", $1, $2, $3, $4}' || echo "❌ No deployments found"
    echo ""

    # 3. Pod Health Summary
    echo "## πŸ”Ή Pod Health Summary"
    POD_TOTAL=$(kubectl get pods -n "$NAMESPACE" --no-headers 2>/dev/null | wc -l)
    POD_RUNNING=$(kubectl get pods -n "$NAMESPACE" --field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l)
    CRASHING_PODS=$(kubectl get pods -n "$NAMESPACE" -o json 2>/dev/null | jq '[.items[] | select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff")] | length')

    echo "- **Total Pods**: $POD_TOTAL"
    echo "- **Running Pods**: $POD_RUNNING"
    echo "- **CrashLoopBackOff Pods**: $CRASHING_PODS"
    echo ""

    # 4. CrashLoopBackOff Pods
    if [[ "$CRASHING_PODS" -gt 0 ]]; then
    echo "### πŸ”Έ CrashLoopBackOff Pods"
    echo '| Pod Name | Node | Restarts |'
    echo '|----------|------|----------|'
    kubectl get pods -n "$NAMESPACE" -o json 2>/dev/null |
    jq -r '
    .items[] |
    select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff") |
    [.metadata.name, .spec.nodeName, .status.containerStatuses[0].restartCount] |
    @tsv' | while IFS=$'\t' read -r pod node restarts; do
    echo "| $pod | $node | $restarts |"
    done
    echo ""
    fi

    # 5. Deployed Images
    echo "## πŸ”Ή Deployed Images"
    kubectl get pods -n "$NAMESPACE" -o json 2>/dev/null |
    jq -r '.items[].spec.containers[].image' | sort -u |
    sed 's/^/- `/;s/$/`/'
    echo ""

    echo "---"
    echo "βœ… Report generated successfully"
    } | tee "$MD_FILE" | sed 's/`//g' > "$TXT_FILE"

    echo "πŸ“„ Markdown saved to: $MD_FILE"
    echo "πŸ“„ Plain text saved to: $TXT_FILE"