PSA/ee/appliance/scripts/collect-support-bundle.sh
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

196 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
KUBECONFIG_PATH="${KUBECONFIG:-}"
TALOSCONFIG_PATH="${TALOSCONFIG:-}"
NODE_IP=""
SITE_ID="appliance-single-node"
OUTPUT_DIR="${PWD}"
REPO_ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../../.." && pwd)"
TEMP_DIR=""
usage() {
cat <<'EOF'
Usage:
collect-support-bundle.sh --kubeconfig <path> [options]
Options:
--kubeconfig <path> Kubeconfig path
--talosconfig <path> Optional legacy Talos config path for Talos-only diagnostics
--node-ip <ip> Optional legacy Talos node IP for node-level collection
--site-id <id> Bundle identifier (default: appliance-single-node)
--output-dir <path> Directory for the .tar.gz bundle (default: current directory)
--help Show this help
EOF
}
require_command() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "Required command not found: $1" >&2
exit 1
fi
}
cleanup() {
if [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ]; then
rm -rf "$TEMP_DIR"
fi
}
capture_cmd() {
local output_file="$1"
shift
{
printf '$'
for arg in "$@"; do
printf ' %q' "$arg"
done
printf '\n'
"$@"
} >"$output_file" 2>&1 || true
}
kubectl_capture() {
local output_file="$1"
shift
capture_cmd "$output_file" kubectl --kubeconfig "$KUBECONFIG_PATH" "$@"
}
talos_capture() {
local output_file="$1"
shift
if [ -z "$TALOSCONFIG_PATH" ] || [ -z "$NODE_IP" ]; then
return 0
fi
capture_cmd "$output_file" talosctl --talosconfig "$TALOSCONFIG_PATH" -n "$NODE_IP" -e "$NODE_IP" "$@"
}
collect_namespace_logs() {
local namespace="$1"
local pod_list
local pod_name
local container_list
local container_name
local safe_namespace
safe_namespace="$(printf '%s' "$namespace" | tr '/' '_')"
pod_list="$(kubectl --kubeconfig "$KUBECONFIG_PATH" -n "$namespace" get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null || true)"
printf '%s\n' "$pod_list" | while IFS= read -r pod_name; do
[ -n "$pod_name" ] || continue
container_list="$(kubectl --kubeconfig "$KUBECONFIG_PATH" -n "$namespace" get pod "$pod_name" -o jsonpath='{range .spec.initContainers[*]}{.name}{"\n"}{end}{range .spec.containers[*]}{.name}{"\n"}{end}' 2>/dev/null || true)"
printf '%s\n' "$container_list" | while IFS= read -r container_name; do
[ -n "$container_name" ] || continue
kubectl_capture "$TEMP_DIR/logs/${safe_namespace}-${pod_name}-${container_name}.log" -n "$namespace" logs "$pod_name" -c "$container_name" --tail=500
kubectl_capture "$TEMP_DIR/logs/${safe_namespace}-${pod_name}-${container_name}-previous.log" -n "$namespace" logs "$pod_name" -c "$container_name" --previous --tail=500
done
done
}
while [ "$#" -gt 0 ]; do
case "$1" in
--kubeconfig)
KUBECONFIG_PATH="$2"
shift 2
;;
--talosconfig)
TALOSCONFIG_PATH="$2"
shift 2
;;
--node-ip)
NODE_IP="$2"
shift 2
;;
--site-id)
SITE_ID="$2"
shift 2
;;
--output-dir)
OUTPUT_DIR="$2"
shift 2
;;
--help|-h)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
require_command kubectl
require_command tar
require_command date
if [ -z "$KUBECONFIG_PATH" ]; then
echo "Kubeconfig path is required via --kubeconfig or KUBECONFIG." >&2
exit 1
fi
if [ ! -f "$KUBECONFIG_PATH" ]; then
echo "Kubeconfig file not found: $KUBECONFIG_PATH" >&2
exit 1
fi
if [ -n "$TALOSCONFIG_PATH" ] && [ ! -f "$TALOSCONFIG_PATH" ]; then
echo "Talosconfig file not found: $TALOSCONFIG_PATH" >&2
exit 1
fi
TEMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/alga-support-bundle.XXXXXX")"
trap cleanup EXIT
mkdir -p "$TEMP_DIR"/{cluster,logs,talos,meta}
cat >"$TEMP_DIR/meta/summary.txt" <<EOF
siteId: $SITE_ID
generatedAt: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
repoRoot: $REPO_ROOT
hasTalosContext: $( [ -n "$TALOSCONFIG_PATH" ] && [ -n "$NODE_IP" ] && printf yes || printf no )
EOF
kubectl_capture "$TEMP_DIR/cluster/version.txt" version
kubectl_capture "$TEMP_DIR/cluster/nodes.txt" get nodes -o wide
kubectl_capture "$TEMP_DIR/cluster/node-describe.txt" describe nodes
kubectl_capture "$TEMP_DIR/cluster/storage-classes.txt" get storageclass
kubectl_capture "$TEMP_DIR/cluster/persistent-volumes.txt" get pv
kubectl_capture "$TEMP_DIR/cluster/persistent-volume-claims.txt" get pvc -A
kubectl_capture "$TEMP_DIR/cluster/events.txt" get events -A --sort-by=.lastTimestamp
kubectl_capture "$TEMP_DIR/cluster/flux-sources.txt" -n flux-system get gitrepositories.source.toolkit.fluxcd.io -o yaml
kubectl_capture "$TEMP_DIR/cluster/flux-kustomizations.txt" -n flux-system get kustomizations.kustomize.toolkit.fluxcd.io -o yaml
kubectl_capture "$TEMP_DIR/cluster/flux-helm-releases.txt" -n alga-system get helmreleases.helm.toolkit.fluxcd.io -o yaml
kubectl_capture "$TEMP_DIR/cluster/alga-pods.txt" -n msp get pods -o wide
kubectl_capture "$TEMP_DIR/cluster/alga-jobs.txt" -n msp get jobs -o yaml
kubectl_capture "$TEMP_DIR/cluster/alga-configmaps.txt" -n alga-system get configmaps -o yaml
kubectl_capture "$TEMP_DIR/cluster/alga-secrets.txt" -n msp get secrets -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'
kubectl_capture "$TEMP_DIR/cluster/describe-db.txt" -n msp describe statefulset db
kubectl_capture "$TEMP_DIR/cluster/describe-redis.txt" -n msp describe statefulset redis
kubectl_capture "$TEMP_DIR/cluster/describe-alga-core.txt" -n msp describe deployment alga-core-sebastian
collect_namespace_logs "flux-system"
collect_namespace_logs "alga-system"
collect_namespace_logs "msp"
talos_capture "$TEMP_DIR/talos/version.txt" version
talos_capture "$TEMP_DIR/talos/health.txt" health --wait-timeout 30s
talos_capture "$TEMP_DIR/talos/services.txt" service
talos_capture "$TEMP_DIR/talos/links.txt" get links
talos_capture "$TEMP_DIR/talos/addresses.txt" get addresses
talos_capture "$TEMP_DIR/talos/routes.txt" get routes
talos_capture "$TEMP_DIR/talos/hostname.txt" get hostname
talos_capture "$TEMP_DIR/talos/resolvers.txt" get resolvers
BUNDLE_PATH="$OUTPUT_DIR/${SITE_ID}-support-bundle-$(date -u +"%Y%m%dT%H%M%SZ").tar.gz"
mkdir -p "$OUTPUT_DIR"
tar -C "$TEMP_DIR" -czf "$BUNDLE_PATH" .
echo "Support bundle written to $BUNDLE_PATH"