Last active
April 9, 2025 17:29
-
-
Save venkata-qa/ac45986cceb15268a1053ec1ecad3dd5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| NAMESPACE=$1 | |
| if [[ -z "$NAMESPACE" ]]; then | |
| echo "❌ Usage: $0 <namespace>" | |
| exit 1 | |
| fi | |
| 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" | |
| } | |
| # Report header | |
| cat <<EOF > "$REPORT_FILE" | |
| # 🚀 Kubernetes Release Report | |
| - **Namespace**: \`$NAMESPACE\` | |
| - **Generated**: \`$TIMESTAMP\` | |
| - **Cluster Context**: \`$(kubectl config current-context 2>/dev/null)\` | |
| --- | |
| EOF | |
| # 1. Namespace Overview | |
| 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 | |
| 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.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" >> "$REPORT_FILE" | |
| echo "- **Running Pods**: $POD_RUNNING" >> "$REPORT_FILE" | |
| echo "- **CrashLoopBackOff Pods**: $CRASHING_PODS" >> "$REPORT_FILE" | |
| # 3.2 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 // 0)] | @tsv' | | |
| while IFS=$'\t' read -r pod node restarts; do | |
| printf "| %s | %s | %s |\n" "$pod" "$node" "$restarts" | |
| done >> "$REPORT_FILE" | |
| # 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 -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 -r image; do | |
| base=$(echo "$image" | cut -d":" -f1) | |
| tag=$(echo "$image" | cut -d":" -f2) | |
| echo "| $base | ${tag:-latest} |" | |
| done >> "$REPORT_FILE" | |
| # 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" | |
| # 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") | |
| | { | |
| 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" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment