Collection of operational skills for VaultMesh infrastructure including: - backup-sovereign: Backup and recovery operations - btc-anchor: Bitcoin anchoring - cloudflare-tunnel-manager: Cloudflare tunnel management - container-registry: Container registry operations - disaster-recovery: Disaster recovery procedures - dns-sovereign: DNS management - eth-anchor: Ethereum anchoring - gitea-bootstrap: Gitea setup and configuration - hetzner-bootstrap: Hetzner server provisioning - merkle-forest: Merkle tree operations - node-hardening: Node security hardening - operator-bootstrap: Operator initialization - proof-verifier: Cryptographic proof verification - rfc3161-anchor: RFC3161 timestamping - secrets-vault: Secrets management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
90 lines
2.5 KiB
Bash
Executable File
90 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# === METADATA ===
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
|
|
# === CONFIGURATION ===
|
|
: "${NODE_NAME:=node-a}"
|
|
: "${BACKUP_LABEL:=manual}"
|
|
: "${OUTPUT_DIR:=$SKILL_ROOT/outputs}"
|
|
: "${BACKUP_SOURCES:=}"
|
|
: "${BACKUP_EXCLUDES:=.git,node_modules,target,dist,outputs}"
|
|
|
|
# === FUNCTIONS ===
|
|
log_plan() { echo "[PLAN] $(date -Iseconds) $*"; }
|
|
die() { echo "[ERROR] $(date -Iseconds) $*" >&2; exit 1; }
|
|
|
|
estimate_size() {
|
|
local total=0
|
|
IFS=',' read -r -a sources <<< "$BACKUP_SOURCES"
|
|
IFS=',' read -r -a excludes <<< "$BACKUP_EXCLUDES"
|
|
|
|
for src in "${sources[@]}"; do
|
|
src="${src/#\~/$HOME}"
|
|
if [[ -e "$src" ]]; then
|
|
# Build find exclude args
|
|
local find_excludes=()
|
|
for ex in "${excludes[@]}"; do
|
|
find_excludes+=(-name "$ex" -prune -o)
|
|
done
|
|
|
|
local size
|
|
size=$(find "$src" "${find_excludes[@]}" -type f -print0 2>/dev/null | \
|
|
xargs -0 stat -c%s 2>/dev/null | \
|
|
awk '{sum+=$1} END {print sum+0}')
|
|
total=$((total + size))
|
|
fi
|
|
done
|
|
echo "$total"
|
|
}
|
|
|
|
main() {
|
|
[[ -n "$BACKUP_SOURCES" ]] || die "BACKUP_SOURCES is required (comma-separated paths)."
|
|
|
|
local ts run_id run_dir
|
|
ts="$(date -Iseconds | tr ':' '-')"
|
|
run_id="${NODE_NAME}_${BACKUP_LABEL}_${ts}"
|
|
run_dir="$OUTPUT_DIR/runs/$run_id"
|
|
|
|
log_plan "=== Backup Plan ==="
|
|
log_plan "Run ID: $run_id"
|
|
log_plan "Run directory: $run_dir"
|
|
log_plan "Archive: $run_dir/archive.tar.gz"
|
|
log_plan "Manifest: $run_dir/manifest.json"
|
|
echo ""
|
|
|
|
log_plan "=== Sources ==="
|
|
IFS=',' read -r -a sources <<< "$BACKUP_SOURCES"
|
|
for src in "${sources[@]}"; do
|
|
src="${src/#\~/$HOME}"
|
|
if [[ -e "$src" ]]; then
|
|
log_plan " [OK] $src"
|
|
else
|
|
log_plan " [MISSING] $src"
|
|
fi
|
|
done
|
|
echo ""
|
|
|
|
log_plan "=== Excludes ==="
|
|
IFS=',' read -r -a excludes <<< "$BACKUP_EXCLUDES"
|
|
for ex in "${excludes[@]}"; do
|
|
log_plan " - $ex"
|
|
done
|
|
echo ""
|
|
|
|
log_plan "=== Size Estimate ==="
|
|
local est_bytes est_mb
|
|
est_bytes=$(estimate_size)
|
|
est_mb=$((est_bytes / 1024 / 1024))
|
|
log_plan "Estimated uncompressed: ${est_mb} MB ($est_bytes bytes)"
|
|
log_plan "Compressed size will be smaller (typically 30-70% of original)"
|
|
echo ""
|
|
|
|
log_plan "Next: ./scripts/11_backup_apply.sh (requires DRY_RUN=0)"
|
|
}
|
|
|
|
[[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@"
|