Last active
April 9, 2025 13:17
-
-
Save venkata-qa/2626d21e517f80be3fc106660af50d8d 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_namespace_report_${NAMESPACE}_$(date +%Y%m%d).md" | |
| echo "π οΈ Generating Markdown Kubernetes report for namespace: $NAMESPACE" | |
| echo "π Report will be saved to: $REPORT_FILE" | |
| # Markdown Helpers | |
| add_heading() { | |
| echo -e "\n## $1\n" >> "$REPORT_FILE" | |
| } | |
| add_subheading() { | |
| echo -e "\n### $1\n" >> "$REPORT_FILE" | |
| } | |
| add_codeblock() { | |
| echo -e "\n\`\`\`bash\n$1\n\`\`\`\n" >> "$REPORT_FILE" | |
| } | |
| # Report Header | |
| cat <<EOF > "$REPORT_FILE" | |
| # Kubernetes Namespace 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 >> "$REPORT_FILE" | |
| # 2. Deployment Summary | |
| add_heading "2. Deployment Summary" | |
| add_subheading "2.1 Deployment Table" | |
| echo '| Name | Ready Replicas | Image | Version |' >> "$REPORT_FILE" | |
| echo '|------|----------------|-------|---------|' >> "$REPORT_FILE" | |
| kubectl get deployments -n $NAMESPACE -o json --request-timeout=30s | jq -r ' | |
| .items[] | | |
| {name: .metadata.name, replicas: .status.readyReplicas, images: [.spec.template.spec.containers[].image]} | | |
| [.name, .replicas, (.images[] | split(":")[0]), (.images[] | split(":")[1] // "latest")] | @tsv' | \ | |
| awk -F'\t' '{ printf "| %s | %s | %s | %s |\n", $1, $2, $3, $4 }' >> "$REPORT_FILE" | |
| # 3. Pod Status | |
| add_heading "3. Pod Status" | |
| add_subheading "3.1 Pod Summary Table" | |
| echo '| Pod Name | Status | Ready | Restarts | Node | IP | Age |' >> "$REPORT_FILE" | |
| echo '|----------|--------|--------|----------|------|----|-----|' >> "$REPORT_FILE" | |
| kubectl get pods -n $NAMESPACE -o json --request-timeout=30s | jq -r ' | |
| .items[] | | |
| { | |
| name: .metadata.name, | |
| status: .status.phase, | |
| ready: ([.status.containerStatuses[]?.ready] | map(tostring) | join(",")), | |
| restarts: ([.status.containerStatuses[]?.restartCount] | add), | |
| node: .spec.nodeName, | |
| ip: .status.podIP, | |
| age: .metadata.creationTimestamp | |
| } | | |
| [.name, .status, .ready, (.restarts // 0), .node, (.ip // "-"), .age] | @tsv' | | |
| while IFS=$'\t' read -r name status ready restarts node ip age; do | |
| printf "| %s | %s | %s | %s | %s | %s | %s |\n" "$name" "$status" "$ready" "$restarts" "$node" "$ip" "$age" | |
| done >> "$REPORT_FILE" | |
| add_subheading "3.2 CrashLoopBackOff Pods (Grouped by App with Logs + Reason)" | |
| echo "" >> "$REPORT_FILE" | |
| kubectl get pods -n "$NAMESPACE" -o json --request-timeout=30s | | |
| jq -r --arg now "$(date -u +%s)" ' | |
| .items[] | | |
| { | |
| name: .metadata.name, | |
| app: (.metadata.labels.app // "N/A"), | |
| startTime: .metadata.creationTimestamp, | |
| phase: .status.phase, | |
| containerStatus: .status.containerStatuses[0], | |
| node: .spec.nodeName, | |
| ip: .status.podIP, | |
| image: (.spec.containers[0].image // ""), | |
| } | | |
| { | |
| name, | |
| app, | |
| phase, | |
| status: (if .containerStatus.state.waiting.reason then .containerStatus.state.waiting.reason else .phase end), | |
| reason: (.containerStatus.state.waiting.reason // "-"), | |
| ready: (.containerStatus.ready | tostring), | |
| restarts: (.containerStatus.restartCount // 0), | |
| node, | |
| ip, | |
| version: ((.image | split(":"))[1] // "latest"), | |
| baseImage: (.image | split(":")[0]), | |
| age: ( | |
| try ( | |
| ($now | tonumber) - (.startTime | sub("Z$"; "") | sub("T"; " ") | strptime("%Y-%m-%d %H:%M:%S") | mktime) | |
| ) catch (0) | |
| ) | |
| } | | |
| select(.reason == "CrashLoopBackOff") | | |
| [.app, .name, .status, .reason, .ready, .restarts, .node, (.ip // "-"), .baseImage, .version, | |
| (if .age < 60 then (.age|tostring)+"s" | |
| elif .age < 3600 then ((.age/60|floor)|tostring)+"m" | |
| elif .age < 86400 then ((.age/3600|floor)|tostring)+"h" | |
| else ((.age/86400|floor)|tostring)+"d" end) | |
| ] | @tsv' | | |
| sort | while IFS=$'\t' read -r app name status reason ready restarts node ip image version age; do | |
| if [[ "$current_app" != "$app" ]]; then | |
| current_app="$app" | |
| echo -e "\n#### App: \`$app\`\n" >> "$REPORT_FILE" | |
| echo '| Pod Name | Status | Reason | Ready | Restarts | Node | IP | Image | Version | Age |' >> "$REPORT_FILE" | |
| echo '|----------|--------|--------|--------|----------|------|----|-------|---------|-----|' >> "$REPORT_FILE" | |
| fi | |
| printf "| %s | %s | %s | %s | %s | %s | %s | %s | %s | %s |\n" \ | |
| "$name" "$status" "$reason" "$ready" "$restarts" "$node" "$ip" "$image" "$version" "$age" >> "$REPORT_FILE" | |
| echo -e "\n<details>\n<summary>π Logs for \`$name\`</summary>\n" >> "$REPORT_FILE" | |
| echo '```log' >> "$REPORT_FILE" | |
| kubectl logs -n "$NAMESPACE" "$name" -p --tail=20 2>&1 >> "$REPORT_FILE" | |
| echo '```' >> "$REPORT_FILE" | |
| echo "</details>" >> "$REPORT_FILE" | |
| done | |
| add_subheading "3.3 Application Containers" | |
| echo '| Pod Name | Container | Image | Version |' >> "$REPORT_FILE" | |
| echo '|----------|-----------|-------|---------|' >> "$REPORT_FILE" | |
| kubectl get pods -n "$NAMESPACE" -o json --request-timeout=30s | jq -r ' | |
| .items[] | | |
| { | |
| podName: .metadata.name, | |
| containers: .spec.containers | |
| } | | |
| .containers[] as $c | | |
| { | |
| podName: .podName, | |
| container: $c.name, | |
| image: $c.image, | |
| version: ( | |
| if ($c.image | contains(":")) then ($c.image | split(":")[1]) else "latest" end | |
| ), | |
| imageName: ($c.image | split(":")[0]), | |
| isSidecar: ($c.image | test("istio|proxy|envoy|sidecar")) | |
| } | | |
| select(.isSidecar | not) | | |
| [.podName, .container, .imageName, .version] | @tsv' | | |
| while IFS=$'\t' read -r pod container image version; do | |
| printf "| %s | %s | %s | %s |\n" "$pod" "$container" "$image" "$version" | |
| done >> "$REPORT_FILE" | |
| add_subheading "3.4 Sidecar Containers" | |
| echo '| Pod Name | Container | Image | Version |' >> "$REPORT_FILE" | |
| echo '|----------|-----------|-------|---------|' >> "$REPORT_FILE" | |
| kubectl get pods -n "$NAMESPACE" -o json --request-timeout=30s | jq -r ' | |
| .items[] | | |
| { | |
| podName: .metadata.name, | |
| containers: .spec.containers | |
| } | | |
| .containers[] as $c | | |
| { | |
| podName: .podName, | |
| container: $c.name, | |
| image: $c.image, | |
| version: ( | |
| if ($c.image | contains(":")) then ($c.image | split(":")[1]) else "latest" end | |
| ), | |
| imageName: ($c.image | split(":")[0]), | |
| isSidecar: ($c.image | test("istio|proxy|envoy|sidecar")) | |
| } | | |
| select(.isSidecar) | | |
| [.podName, .container, .imageName, .version] | @tsv' | | |
| while IFS=$'\t' read -r pod container image version; do | |
| printf "| %s | %s | %s | %s |\n" "$pod" "$container" "$image" "$version" | |
| done >> "$REPORT_FILE" | |
| # 4. Services | |
| add_heading "4. Services" | |
| echo '```bash' >> "$REPORT_FILE" | |
| kubectl get services -n $NAMESPACE -o wide --request-timeout=30s >> "$REPORT_FILE" | |
| echo '```' >> "$REPORT_FILE" | |
| # 5. Persistent Volume Claims | |
| add_heading "5. Persistent Volume Claims" | |
| echo '```bash' >> "$REPORT_FILE" | |
| kubectl get pvc -n $NAMESPACE -o wide --request-timeout=30s >> "$REPORT_FILE" | |
| echo '```' >> "$REPORT_FILE" | |
| # 6. ConfigMaps & Secrets | |
| add_heading "6. ConfigMaps and Secrets" | |
| add_subheading "6.1 ConfigMaps" | |
| echo '```bash' >> "$REPORT_FILE" | |
| kubectl get configmaps -n $NAMESPACE --request-timeout=30s >> "$REPORT_FILE" | |
| echo '```' >> "$REPORT_FILE" | |
| add_subheading "6.2 Secrets" | |
| echo '```bash' >> "$REPORT_FILE" | |
| kubectl get secrets -n $NAMESPACE --request-timeout=30s >> "$REPORT_FILE" | |
| echo '```' >> "$REPORT_FILE" | |
| # 7. Events | |
| add_heading "7. Recent Events (Last 20)" | |
| echo '```bash' >> "$REPORT_FILE" | |
| kubectl get events -n $NAMESPACE --sort-by='.lastTimestamp' --request-timeout=30s | tail -n 20 >> "$REPORT_FILE" | |
| echo '```' >> "$REPORT_FILE" | |
| # 8. Recommendations | |
| add_heading "8. Recommendations" | |
| cat <<EOF >> "$REPORT_FILE" | |
| **Detected Non-Running Pods:** | |
| \`\`\`bash | |
| $(kubectl get pods -n $NAMESPACE --field-selector=status.phase!=Running -o name --request-timeout=30s) | |
| \`\`\` | |
| **Suggested Actions:** | |
| 1. Check logs of failed pods: | |
| \`kubectl logs -n $NAMESPACE <pod-name> -p\` | |
| 2. Investigate image pull failures (ImagePullBackOff): | |
| Validate image name, tag, and registry access. | |
| 3. For pods with high restart counts, review application logs. | |
| 4. View full event history for a pod: | |
| \`kubectl describe pod -n $NAMESPACE <pod-name>\` | |
| EOF | |
| echo -e "\nβ Markdown report generated successfully!" | |
| echo "π File: $REPORT_FILE" | |
| HTML_FILE="${REPORT_FILE%.md}.html" | |
| echo "π§ͺ Generating HTML version: $HTML_FILE" | |
| { | |
| echo "<!DOCTYPE html>" | |
| echo "<html><head><meta charset='UTF-8'>" | |
| echo "<title>K8s Report: $NAMESPACE</title>" | |
| echo "<style> | |
| body { font-family: sans-serif; padding: 1rem; line-height: 1.6; } | |
| h1, h2, h3, h4 { color: #2c3e50; } | |
| table { width: 100%; border-collapse: collapse; margin: 1em 0; font-size: 14px; } | |
| th, td { border: 1px solid #ccc; padding: 6px 10px; text-align: left; } | |
| th { background-color: #f4f4f4; } | |
| details { margin-bottom: 1em; } | |
| summary { font-weight: bold; cursor: pointer; } | |
| pre, code { background: #f8f8f8; padding: 8px; display: block; overflow-x: auto; } | |
| </style></head><body>" | |
| echo "<h1>Kubernetes Namespace Report</h1>" | |
| echo "<p><strong>Namespace:</strong> <code>$NAMESPACE</code><br>" | |
| echo "<strong>Generated:</strong> $(date)<br>" | |
| echo "<strong>Cluster:</strong> <code>$(kubectl config current-context 2>/dev/null)</code></p>" | |
| awk ' | |
| BEGIN { inside_code=0 } | |
| { | |
| if ($0 ~ /^### /) { gsub(/^### /, "<h3>"); print $0 "</h3>" } | |
| else if ($0 ~ /^## /) { gsub(/^## /, "<h2>"); print $0 "</h2>" } | |
| else if ($0 ~ /^# /) { gsub(/^# /, "<h1>"); print $0 "</h1>" } | |
| else if ($0 ~ /^```/) { | |
| if (inside_code) { print "</pre>"; inside_code=0 } | |
| else { print "<pre>"; inside_code=1 } | |
| } | |
| else if ($0 ~ /^<details>/ || $0 ~ /^<\/details>/ || $0 ~ /^<summary>/) { | |
| print $0 | |
| } | |
| else if ($0 ~ /^\|/) { | |
| gsub(/\|/, "</td><td>") | |
| sub(/^<\/td>/, "<tr><td>") | |
| print $0 "</td></tr>" | |
| } | |
| else if (inside_code) { | |
| print $0 | |
| } | |
| else { | |
| print "<p>" $0 "</p>" | |
| } | |
| }' "$REPORT_FILE" | |
| echo "</body></html>" | |
| } > "$HTML_FILE" | |
| echo "β HTML report saved: $HTML_FILE" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment