Files
Andrey Lutsenko c0f5828d0b Add safe upgrade workflow script.
Made-with: Cursor
2026-04-20 23:07:23 +10:00

148 lines
3.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Safe upgrade workflow:
# 1) backup
# 2) upgrade dependencies/components
# 3) run healthcheck
# 4) optional rollback (config restore) on failure
#
# Usage:
# ./upgrade.sh
# ./upgrade.sh --model qwen2.5-coder:7b
# ./upgrade.sh --skip-model-pull
WORKDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MODEL="${MODEL:-qwen2.5-coder:7b}"
SKIP_MODEL_PULL=0
BACKUP_DIR="${BACKUP_DIR:-$HOME/openclaude-backups}"
LAST_BACKUP=""
while [[ $# -gt 0 ]]; do
case "$1" in
--model)
MODEL="$2"
shift 2
;;
--skip-model-pull)
SKIP_MODEL_PULL=1
shift
;;
*)
echo "Unknown argument: $1"
exit 2
;;
esac
done
step() { echo; echo "==> $*"; }
fail() { echo "ERROR: $*" >&2; exit 1; }
run_backup() {
step "Creating backup before upgrade"
pushd "$WORKDIR" >/dev/null
./backup.sh --output-dir "$BACKUP_DIR"
popd >/dev/null
LAST_BACKUP="$(ls -dt "$BACKUP_DIR"/backup_* 2>/dev/null | head -n 1 || true)"
[[ -n "$LAST_BACKUP" ]] || fail "Could not find created backup directory"
echo "Backup: $LAST_BACKUP"
}
rollback_configs() {
if [[ -z "${LAST_BACKUP:-}" ]]; then
echo "No backup found, cannot rollback."
return
fi
step "Rolling back configs from backup"
pushd "$WORKDIR" >/dev/null
./restore.sh --from "$LAST_BACKUP"
popd >/dev/null
}
upgrade_system() {
step "Updating apt packages"
sudo apt update
sudo apt install -y curl git docker.io docker-compose-plugin python3 python3-venv python3-pip
}
upgrade_openclaude() {
step "Updating OpenClaude CLI"
if command -v npm >/dev/null 2>&1; then
npm install -g @gitlawb/openclaude
else
echo "npm not found, skipping OpenClaude update"
fi
}
upgrade_ollama() {
step "Ensuring Ollama is installed and running"
if ! command -v ollama >/dev/null 2>&1; then
curl -fsSL https://ollama.com/install.sh | sh
fi
sudo systemctl enable ollama
sudo systemctl restart ollama
}
upgrade_models() {
if [[ "$SKIP_MODEL_PULL" -eq 1 ]]; then
step "Skipping model pull (--skip-model-pull)"
return
fi
step "Refreshing model: $MODEL"
ollama pull "$MODEL"
ollama pull nomic-embed-text || true
}
upgrade_qdrant() {
step "Refreshing Qdrant container"
pushd "$WORKDIR" >/dev/null
docker compose pull
docker compose up -d
popd >/dev/null
}
upgrade_python_deps() {
step "Refreshing Python virtual environment dependencies"
pushd "$WORKDIR" >/dev/null
if [[ ! -d ".venv" ]]; then
python3 -m venv .venv
fi
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
deactivate || true
popd >/dev/null
}
run_checks() {
step "Running healthcheck (full)"
pushd "$WORKDIR" >/dev/null
./healthcheck.sh --mode full --model "$MODEL"
popd >/dev/null
}
main() {
run_backup
if ! {
upgrade_system
upgrade_openclaude
upgrade_ollama
upgrade_models
upgrade_qdrant
upgrade_python_deps
run_checks
}; then
echo
echo "Upgrade failed. Starting config rollback..."
rollback_configs
fail "Upgrade aborted. Config rollback executed from: $LAST_BACKUP"
fi
step "Upgrade completed successfully"
echo "Backup kept at: $LAST_BACKUP"
echo "Tip: run ./status.sh for quick post-upgrade overview."
}
main "$@"