Add homelab change journal

This commit is contained in:
juvdiaz 2026-06-29 17:42:41 -06:00
parent 759b087b5e
commit 4f90fd8904
5 changed files with 109 additions and 1 deletions

View File

@ -277,6 +277,7 @@ Run a read-only health snapshot from the Debian server with:
./jeannie release-snapshot ./jeannie release-snapshot
./jeannie backup-status ./jeannie backup-status
./jeannie workers list ./jeannie workers list
./jeannie change-journal list
./jeannie map ./jeannie map
``` ```
@ -326,6 +327,12 @@ restore drill reports, and repo-managed Pi-hole restore inputs. The main
Use `recreate-plan <index>` before replacing one broken Pimox worker so the Use `recreate-plan <index>` before replacing one broken Pimox worker so the
cluster drain, VM stop, and `./jeannie up` path stay ordered. cluster drain, VM stop, and `./jeannie up` path stay ordered.
`change-journal` lists local journal entries written before risky commands such
as `up`, `apps`, `deploy-gitea`, `rpi-services`, `stop-cluster`,
`start-cluster`, `rebuild-cluster`, `release-snapshot`, and `nuke`. Entries live
under `${HOMELAB_STATE_DIR}/change-journal` and record Git revision, branch,
dirty file count, and command details.
`map` prints a dependency map from the canonical inventory, covering public `map` prints a dependency map from the canonical inventory, covering public
entry, GitOps automation, cluster foundation, DNS, observability, and security entry, GitOps automation, cluster foundation, DNS, observability, and security
learning paths. `./jeannie map --dot` emits Graphviz DOT. learning paths. `./jeannie map --dot` emits Graphviz DOT.

View File

@ -277,6 +277,7 @@ Run a read-only health snapshot from the Debian server with:
./{{ main_script }} release-snapshot ./{{ main_script }} release-snapshot
./{{ main_script }} backup-status ./{{ main_script }} backup-status
./{{ main_script }} workers list ./{{ main_script }} workers list
./{{ main_script }} change-journal list
./{{ main_script }} map ./{{ main_script }} map
``` ```
@ -326,6 +327,12 @@ restore drill reports, and repo-managed Pi-hole restore inputs. The main
Use `recreate-plan <index>` before replacing one broken Pimox worker so the Use `recreate-plan <index>` before replacing one broken Pimox worker so the
cluster drain, VM stop, and `./{{ main_script }} up` path stay ordered. cluster drain, VM stop, and `./{{ main_script }} up` path stay ordered.
`change-journal` lists local journal entries written before risky commands such
as `up`, `apps`, `deploy-gitea`, `rpi-services`, `stop-cluster`,
`start-cluster`, `rebuild-cluster`, `release-snapshot`, and `nuke`. Entries live
under `${HOMELAB_STATE_DIR}/change-journal` and record Git revision, branch,
dirty file count, and command details.
`map` prints a dependency map from the canonical inventory, covering public `map` prints a dependency map from the canonical inventory, covering public
entry, GitOps automation, cluster foundation, DNS, observability, and security entry, GitOps automation, cluster foundation, DNS, observability, and security
learning paths. `./{{ main_script }} map --dot` emits Graphviz DOT. learning paths. `./{{ main_script }} map --dot` emits Graphviz DOT.

View File

@ -85,6 +85,10 @@ includes this as a warning signal.
: Manage Kubernetes/Pimox worker lifecycle operations. Commands include `list`, : Manage Kubernetes/Pimox worker lifecycle operations. Commands include `list`,
`start`, `stop`, `drain`, `uncordon`, `recreate-plan`, and `rebalance`. `start`, `stop`, `drain`, `uncordon`, `recreate-plan`, and `rebalance`.
`change-journal {list|path}`
: List local journal entries written before risky commands, or print the journal
directory path.
`map` `map`
: Print a dependency map from the canonical inventory. Use `map --dot` for a : Print a dependency map from the canonical inventory. Use `map --dot` for a
Graphviz DOT graph. Graphviz DOT graph.

25
jeannie
View File

@ -5997,24 +5997,39 @@ workers_manage() {
"${REPO_ROOT}/scripts/workers" "${@:2}" "${REPO_ROOT}/scripts/workers" "${@:2}"
} }
record_change_journal() {
local command_name="$1"
shift || true
"${REPO_ROOT}/scripts/change-journal" append "${command_name}" "$*" || true
}
change_journal() {
"${REPO_ROOT}/scripts/change-journal" "${@:2}"
}
homelab_map() { homelab_map() {
"${REPO_ROOT}/scripts/homelab-map" "${@:2}" "${REPO_ROOT}/scripts/homelab-map" "${@:2}"
} }
case "${1:-}" in case "${1:-}" in
up) up)
record_change_journal "up" "$@"
up up
;; ;;
plan) plan)
plan_homelab "${2:-all}" plan_homelab "${2:-all}"
;; ;;
rebuild-cluster) rebuild-cluster)
record_change_journal "rebuild-cluster" "$@"
rebuild_cluster rebuild_cluster
;; ;;
stop-cluster) stop-cluster)
record_change_journal "stop-cluster" "$@"
stop_cluster stop_cluster
;; ;;
start-cluster) start-cluster)
record_change_journal "start-cluster" "$@"
start_cluster start_cluster
;; ;;
status) status)
@ -6033,6 +6048,7 @@ case "${1:-}" in
cert_check cert_check
;; ;;
release-snapshot) release-snapshot)
record_change_journal "release-snapshot" "$@"
release_snapshot release_snapshot
;; ;;
backup-status) backup-status)
@ -6041,6 +6057,9 @@ case "${1:-}" in
workers) workers)
workers_manage "$@" workers_manage "$@"
;; ;;
change-journal)
change_journal "$@"
;;
map) map)
homelab_map "$@" homelab_map "$@"
;; ;;
@ -6054,6 +6073,7 @@ case "${1:-}" in
kubeconfig_readonly kubeconfig_readonly
;; ;;
apps) apps)
record_change_journal "apps" "$@"
require_debian_server "apps" require_debian_server "apps"
jeannie_log_start "apps" jeannie_log_start "apps"
jeannie_step_plan 1 jeannie_step_plan 1
@ -6070,9 +6090,11 @@ case "${1:-}" in
ollama_setup ollama_setup
;; ;;
deploy-gitea) deploy-gitea)
record_change_journal "deploy-gitea" "$@"
deploy_gitea deploy_gitea
;; ;;
rpi-services) rpi-services)
record_change_journal "rpi-services" "$@"
deploy_rpi_services deploy_rpi_services
;; ;;
bootstrap-gitea-repo) bootstrap-gitea-repo)
@ -6181,6 +6203,7 @@ case "${1:-}" in
openwrt openwrt
;; ;;
nuke) nuke)
record_change_journal "nuke" "$@"
require_debian_server "nuke" require_debian_server "nuke"
jeannie_log_start "nuke" jeannie_log_start "nuke"
jeannie_step_plan 1 jeannie_step_plan 1
@ -6188,7 +6211,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|release-snapshot|backup-status|workers <list|start|stop|drain|uncordon|recreate-plan|rebalance>|map [--dot]|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|backup-status|workers <list|start|stop|drain|uncordon|recreate-plan|rebalance>|change-journal {list|path}|map [--dot]|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

67
scripts/change-journal Executable file
View File

@ -0,0 +1,67 @@
#!/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}"
JOURNAL_DIR="${HOMELAB_CHANGE_JOURNAL_DIR:-${HOMELAB_STATE_DIR}/change-journal}"
ACTION="${1:-list}"
mkdir -p "$JOURNAL_DIR"
timestamp() {
date -u +%Y%m%dT%H%M%SZ
}
latest_entries() {
local count="${1:-20}"
find "$JOURNAL_DIR" -maxdepth 1 -type f -name '*.log' -print 2>/dev/null |
sort |
tail -n "$count" |
while IFS= read -r file; do
printf '\n== %s ==\n' "$(basename "$file")"
sed -n '1,80p' "$file"
done
}
append_entry() {
local command_name="${2:-unknown}"
local detail="${3:-}"
local now
local file
now="$(timestamp)"
file="${JOURNAL_DIR}/${now}-${command_name//[^A-Za-z0-9_.-]/_}.log"
{
printf 'created_utc=%s\n' "$now"
printf 'command=%s\n' "$command_name"
printf 'detail=%s\n' "$detail"
printf 'host=%s\n' "$(hostname 2>/dev/null || echo unknown)"
printf 'repo=%s\n' "$REPO_ROOT"
printf 'branch=%s\n' "$(git -C "$REPO_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)"
printf 'revision=%s\n' "$(git -C "$REPO_ROOT" rev-parse HEAD 2>/dev/null || echo unknown)"
printf 'dirty_files=%s\n' "$(git -C "$REPO_ROOT" status --short 2>/dev/null | wc -l | tr -d ' ')"
printf '\n-- git status --short --\n'
git -C "$REPO_ROOT" status --short 2>/dev/null || true
} >"$file"
printf 'Recorded change journal entry: %s\n' "$file"
}
case "$ACTION" in
append)
append_entry "$@"
;;
list)
latest_entries "${2:-20}"
;;
path)
printf '%s\n' "$JOURNAL_DIR"
;;
*)
echo "Usage: ./jeannie change-journal {list [count]|path}" >&2
echo "Internal: scripts/change-journal append <command> [detail]" >&2
exit 1
;;
esac