Add release snapshot command
This commit is contained in:
parent
a4aa75c77d
commit
41498150ea
|
|
@ -274,6 +274,7 @@ Run a read-only health snapshot from the Debian server with:
|
||||||
./jeannie recover-plan
|
./jeannie recover-plan
|
||||||
./jeannie gitops-status
|
./jeannie gitops-status
|
||||||
./jeannie cert-check
|
./jeannie cert-check
|
||||||
|
./jeannie release-snapshot
|
||||||
```
|
```
|
||||||
|
|
||||||
It reports host memory/disk, systemd services, Docker Compose stacks,
|
It reports host memory/disk, systemd services, Docker Compose stacks,
|
||||||
|
|
@ -309,6 +310,10 @@ and recent repo-server/application-controller errors.
|
||||||
`cert-check` verifies public DNS, TLS certificate expiry, public website/Gitea
|
`cert-check` verifies public DNS, TLS certificate expiry, public website/Gitea
|
||||||
HTTP status, and DuckDNS-to-OCI edge IP drift from the canonical inventory.
|
HTTP status, and DuckDNS-to-OCI edge IP drift from the canonical inventory.
|
||||||
|
|
||||||
|
`release-snapshot` writes a timestamped pre-change report under the homelab
|
||||||
|
state directory with Git state, Kubernetes/Argo CD/Helm state, workload images,
|
||||||
|
public URL status, and pointers to the latest Gitea/OpenTofu backups.
|
||||||
|
|
||||||
Focused doctor commands run narrower read-only checks and print the most likely
|
Focused doctor commands run narrower read-only checks and print the most likely
|
||||||
next step:
|
next step:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -274,6 +274,7 @@ Run a read-only health snapshot from the Debian server with:
|
||||||
./{{ main_script }} recover-plan
|
./{{ main_script }} recover-plan
|
||||||
./{{ main_script }} gitops-status
|
./{{ main_script }} gitops-status
|
||||||
./{{ main_script }} cert-check
|
./{{ main_script }} cert-check
|
||||||
|
./{{ main_script }} release-snapshot
|
||||||
```
|
```
|
||||||
|
|
||||||
It reports host memory/disk, systemd services, Docker Compose stacks,
|
It reports host memory/disk, systemd services, Docker Compose stacks,
|
||||||
|
|
@ -309,6 +310,10 @@ and recent repo-server/application-controller errors.
|
||||||
`cert-check` verifies public DNS, TLS certificate expiry, public website/Gitea
|
`cert-check` verifies public DNS, TLS certificate expiry, public website/Gitea
|
||||||
HTTP status, and DuckDNS-to-OCI edge IP drift from the canonical inventory.
|
HTTP status, and DuckDNS-to-OCI edge IP drift from the canonical inventory.
|
||||||
|
|
||||||
|
`release-snapshot` writes a timestamped pre-change report under the homelab
|
||||||
|
state directory with Git state, Kubernetes/Argo CD/Helm state, workload images,
|
||||||
|
public URL status, and pointers to the latest Gitea/OpenTofu backups.
|
||||||
|
|
||||||
Focused doctor commands run narrower read-only checks and print the most likely
|
Focused doctor commands run narrower read-only checks and print the most likely
|
||||||
next step:
|
next step:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,11 @@ repo-server/application-controller errors.
|
||||||
: Verify public DNS, TLS certificate expiry, public website/Gitea HTTP status,
|
: Verify public DNS, TLS certificate expiry, public website/Gitea HTTP status,
|
||||||
and DuckDNS-to-OCI edge IP drift from the canonical inventory.
|
and DuckDNS-to-OCI edge IP drift from the canonical inventory.
|
||||||
|
|
||||||
|
`release-snapshot`
|
||||||
|
: Write a timestamped pre-change report with Git state, Kubernetes/Argo CD/Helm
|
||||||
|
state, workload images, public URL status, and latest Gitea/OpenTofu backup
|
||||||
|
pointers.
|
||||||
|
|
||||||
Prometheus alerts
|
Prometheus alerts
|
||||||
: High-signal alert rules are managed as the `apps/homelab-alerts` GitOps app.
|
: High-signal alert rules are managed as the `apps/homelab-alerts` GitOps app.
|
||||||
They cover node readiness, restart storms, unavailable deployments, storage
|
They cover node readiness, restart storms, unavailable deployments, storage
|
||||||
|
|
|
||||||
10
jeannie
10
jeannie
|
|
@ -5981,6 +5981,11 @@ cert_check() {
|
||||||
"${REPO_ROOT}/scripts/cert-check"
|
"${REPO_ROOT}/scripts/cert-check"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
release_snapshot() {
|
||||||
|
require_debian_server "release-snapshot"
|
||||||
|
"${REPO_ROOT}/scripts/release-snapshot"
|
||||||
|
}
|
||||||
|
|
||||||
case "${1:-}" in
|
case "${1:-}" in
|
||||||
up)
|
up)
|
||||||
up
|
up
|
||||||
|
|
@ -6012,6 +6017,9 @@ case "${1:-}" in
|
||||||
cert-check)
|
cert-check)
|
||||||
cert_check
|
cert_check
|
||||||
;;
|
;;
|
||||||
|
release-snapshot)
|
||||||
|
release_snapshot
|
||||||
|
;;
|
||||||
validate)
|
validate)
|
||||||
validate_homelab
|
validate_homelab
|
||||||
;;
|
;;
|
||||||
|
|
@ -6156,7 +6164,7 @@ case "${1:-}" in
|
||||||
echo "Log: ${JEANNIE_LOG_FILE}"
|
echo "Log: ${JEANNIE_LOG_FILE}"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 {up|plan [all|provisioning|cluster|platform|apps|edge]|rebuild-cluster|stop-cluster|start-cluster|status|capacity|recover-plan|gitops-status|cert-check|validate|access-audit|kubeconfig-readonly|apps|website-translation-model|website-ollama-listen|ollama-setup|deploy-gitea|rpi-services|bootstrap-gitea-repo|backup-gitea|drill-restore|drill-gitea-restore|drill-pihole-restore|install-gitea-runner|move-prometheus-stack-workers|doctor-versions|doctor-edge|doctor-gitea|doctor-rpi|doctor-cluster|preflight|doctor-preapply|inventory-check|state-backup|fix-debian-docker-root|secrets-init|secrets-check|tailnet-policy-check|ai-index|ai-check|security-scan|security-prepare|security-zap|security-k8s|security-host|security-trivy|security-secrets|security-nuclei|security-web|security-logs|security-runtime|security-attack-path|openwrt|nuke}"
|
echo "Usage: $0 {up|plan [all|provisioning|cluster|platform|apps|edge]|rebuild-cluster|stop-cluster|start-cluster|status|capacity|recover-plan|gitops-status|cert-check|release-snapshot|validate|access-audit|kubeconfig-readonly|apps|website-translation-model|website-ollama-listen|ollama-setup|deploy-gitea|rpi-services|bootstrap-gitea-repo|backup-gitea|drill-restore|drill-gitea-restore|drill-pihole-restore|install-gitea-runner|move-prometheus-stack-workers|doctor-versions|doctor-edge|doctor-gitea|doctor-rpi|doctor-cluster|preflight|doctor-preapply|inventory-check|state-backup|fix-debian-docker-root|secrets-init|secrets-check|tailnet-policy-check|ai-index|ai-check|security-scan|security-prepare|security-zap|security-k8s|security-host|security-trivy|security-secrets|security-nuclei|security-web|security-logs|security-runtime|security-attack-path|openwrt|nuke}"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
HOMELAB_STATE_DIR="${HOMELAB_STATE_DIR:-${XDG_DATA_HOME:-${HOME}/.local/share}/homelab}"
|
||||||
|
SNAPSHOT_DIR="${HOMELAB_RELEASE_SNAPSHOT_DIR:-${HOMELAB_STATE_DIR}/release-snapshots}"
|
||||||
|
TIMESTAMP="$(date -u +%Y%m%dT%H%M%SZ)"
|
||||||
|
REPORT="${SNAPSHOT_DIR}/release-snapshot-${TIMESTAMP}.txt"
|
||||||
|
|
||||||
|
mkdir -p "$SNAPSHOT_DIR"
|
||||||
|
exec > >(tee "$REPORT") 2>&1
|
||||||
|
|
||||||
|
section() {
|
||||||
|
printf '\n== %s ==\n' "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
have() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
run_optional() {
|
||||||
|
local description="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
section "$description"
|
||||||
|
if "$@"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'warn: %s unavailable or failed\n' "$description"
|
||||||
|
}
|
||||||
|
|
||||||
|
latest_file() {
|
||||||
|
local dir="$1"
|
||||||
|
local pattern="$2"
|
||||||
|
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
find "$dir" -maxdepth 1 -type f -name "$pattern" -print 2>/dev/null | sort | tail -1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
section "Snapshot Metadata"
|
||||||
|
printf 'created_utc=%s\n' "$TIMESTAMP"
|
||||||
|
printf 'report=%s\n' "$REPORT"
|
||||||
|
printf 'repo=%s\n' "$REPO_ROOT"
|
||||||
|
printf 'host=%s\n' "$(hostname 2>/dev/null || echo unknown)"
|
||||||
|
|
||||||
|
section "Git State"
|
||||||
|
git -C "$REPO_ROOT" rev-parse --abbrev-ref HEAD
|
||||||
|
git -C "$REPO_ROOT" rev-parse HEAD
|
||||||
|
git -C "$REPO_ROOT" status --short
|
||||||
|
git -C "$REPO_ROOT" log --oneline -5
|
||||||
|
|
||||||
|
if have kubectl; then
|
||||||
|
run_optional "Kubernetes Nodes" kubectl get nodes -o wide
|
||||||
|
run_optional "Kubernetes Problem Pods" sh -c \
|
||||||
|
'kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded -o wide'
|
||||||
|
run_optional "Argo CD Applications" sh -c \
|
||||||
|
'kubectl -n argocd get applications.argoproj.io -o custom-columns=NAME:.metadata.name,SYNC:.status.sync.status,HEALTH:.status.health.status,REVISION:.status.sync.revision,PATH:.spec.source.path --no-headers'
|
||||||
|
run_optional "Workload Images" sh -c \
|
||||||
|
'kubectl get deploy,statefulset,daemonset -A -o jsonpath="{range .items[*]}{.metadata.namespace}{\"/\"}{.metadata.name}{\"\\t\"}{range .spec.template.spec.containers[*]}{.image}{\" \"}{end}{\"\\n\"}{end}"'
|
||||||
|
else
|
||||||
|
section "Kubernetes"
|
||||||
|
echo "kubectl not installed; skipping Kubernetes snapshot."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if have helm; then
|
||||||
|
run_optional "Helm Releases" helm list -A
|
||||||
|
else
|
||||||
|
section "Helm Releases"
|
||||||
|
echo "helm not installed; skipping Helm release snapshot."
|
||||||
|
fi
|
||||||
|
|
||||||
|
section "Backup Pointers"
|
||||||
|
state_backup="$(latest_file "${HOMELAB_TOFU_STATE_BACKUP_DIR:-${HOMELAB_STATE_DIR}/tofu-state-backups}" 'tofu-state-*.tgz' || true)"
|
||||||
|
gitea_backup="$(latest_file "${LAB_GITEA_BACKUP_DIR:-/home/jv/backups/gitea}" 'gitea-*.zip' || true)"
|
||||||
|
printf 'latest_tofu_state_backup=%s\n' "${state_backup:-missing}"
|
||||||
|
printf 'latest_gitea_backup=%s\n' "${gitea_backup:-missing}"
|
||||||
|
|
||||||
|
section "Public URLs"
|
||||||
|
for url in "${LAB_PUBLIC_URL:-https://lab2025.duckdns.org/}" "${LAB_GITEA_URL:-https://lab2025.duckdns.org/git/jv/my-homelab-configs}"; do
|
||||||
|
if have curl; then
|
||||||
|
status="$(curl -k -sS -o /dev/null -w '%{http_code}' --max-time 10 "$url" 2>/dev/null || true)"
|
||||||
|
printf '%-60s http=%s\n' "$url" "${status:-none}"
|
||||||
|
else
|
||||||
|
printf '%-60s curl not installed\n' "$url"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
section "Next Actions"
|
||||||
|
cat <<EOF
|
||||||
|
Before applying risky changes:
|
||||||
|
1. Review this report for dirty Git state, unhealthy apps, or missing backups.
|
||||||
|
2. Run ./jeannie state-backup if latest_tofu_state_backup is missing or old.
|
||||||
|
3. Run ./jeannie backup-gitea if latest_gitea_backup is missing or old.
|
||||||
|
4. Keep this report path with the change notes: $REPORT
|
||||||
|
EOF
|
||||||
Loading…
Reference in New Issue