Files
Claude-Code-Monitor/deployments/scripts/rollback.sh
T
nntrivi2001 57dc91585d feat: Claude Code Monitor — lanes, pipelines and a merged workspace
Internal SmartGift build of a Claude Code monitoring dashboard.

Lanes: a durable unit of parallel agent work, one per working directory,
tracked across session restarts. Managed lanes are git worktrees the
dashboard provisions and can reset or remove behind a three-check destroy
guard and a counted preflight; adopted lanes are directories you already
own and are never destroyable.

Pipelines: a lane moves through pipeline stages. A stage the agent declares
with evidence renders green; a stage inferred from the tool-event stream
renders dashed amber and never counts as done. Detection is forward-only
within a 30-minute window, and never writes the declared stage.

Workspace: one page at /run with a lane grid, the selected lane's pipeline,
and a full Claude console behind a disclosure.
2026-07-30 14:39:03 +07:00

222 lines
8.8 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# rollback.sh Rollback deployments for Claude Code Agent Monitor
#
# Usage:
# ./rollback.sh --env production --method helm --revision 5
# ./rollback.sh --env staging --method kustomize
# ./rollback.sh --help
# ─────────────────────────────────────────────────────────────────────────────
# @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
set -euo pipefail
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly APP_NAME="agent-monitor"
readonly APP_PORT=4820
# ── Colors & logging ───────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
log() { echo -e "${CYAN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $*"; }
info() { echo -e "${CYAN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${BLUE}${NC} $*"; }
ok() { echo -e "${CYAN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${GREEN}${NC} $*"; }
warn() { echo -e "${CYAN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${YELLOW}${NC} $*" >&2; }
err() { echo -e "${CYAN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${RED}${NC} $*" >&2; }
fatal() { err "$@"; exit 1; }
# ── Defaults ────────────────────────────────────────────────────────────────
ENVIRONMENT=""
METHOD=""
REVISION=""
NAMESPACE=""
HELM_RELEASE="${APP_NAME}"
SKIP_HEALTH_CHECK=false
# ── Usage ───────────────────────────────────────────────────────────────────
usage() {
cat <<EOF
${BOLD}Usage:${NC}
$(basename "$0") --env <environment> --method <method> [options]
${BOLD}Required:${NC}
--env, -e Environment: dev, staging, production
--method, -m Method: helm, kustomize
${BOLD}Options:${NC}
--revision, -r Helm revision or rollout history number to roll back to
--namespace, -n Kubernetes namespace (default: agent-monitor-<env>)
--release Helm release name (default: ${APP_NAME})
--skip-health Skip post-rollback health check
--help, -h Show this help message
${BOLD}Examples:${NC}
$(basename "$0") --env production --method helm --revision 5
$(basename "$0") --env staging --method kustomize
$(basename "$0") --env production --method helm # rolls back to previous
EOF
exit 0
}
# ── Argument parsing ────────────────────────────────────────────────────────
parse_args() {
[[ $# -eq 0 ]] && usage
while [[ $# -gt 0 ]]; do
case "$1" in
--env|-e) ENVIRONMENT="$2"; shift 2 ;;
--method|-m) METHOD="$2"; shift 2 ;;
--revision|-r) REVISION="$2"; shift 2 ;;
--namespace|-n) NAMESPACE="$2"; shift 2 ;;
--release) HELM_RELEASE="$2"; shift 2 ;;
--skip-health) SKIP_HEALTH_CHECK=true; shift ;;
--help|-h) usage ;;
*) fatal "Unknown option: $1" ;;
esac
done
[[ -z "$ENVIRONMENT" ]] && fatal "Missing required argument: --env"
[[ -z "$METHOD" ]] && fatal "Missing required argument: --method"
[[ -z "$NAMESPACE" ]] && NAMESPACE="agent-monitor-${ENVIRONMENT}"
}
# ── Show release history ───────────────────────────────────────────────────
show_history() {
info "Release history:"
case "$METHOD" in
helm)
helm history "${HELM_RELEASE}" -n "${NAMESPACE}" --max 10 2>/dev/null || warn "No history found"
;;
kustomize)
kubectl rollout history "deployment/${APP_NAME}" -n "${NAMESPACE}" 2>/dev/null || warn "No history found"
;;
esac
echo ""
}
# ── Confirm rollback ───────────────────────────────────────────────────────
confirm_rollback() {
if [[ "$ENVIRONMENT" == "production" ]]; then
local target_msg="previous revision"
[[ -n "$REVISION" ]] && target_msg="revision ${REVISION}"
warn "Rolling back ${BOLD}PRODUCTION${NC} to ${target_msg}"
read -r -p "$(echo -e "${YELLOW}Type 'yes' to confirm:${NC} ")" confirm
[[ "$confirm" == "yes" ]] || fatal "Rollback cancelled."
fi
}
# ── Helm rollback ───────────────────────────────────────────────────────────
rollback_helm() {
info "Rolling back Helm release '${HELM_RELEASE}' in namespace '${NAMESPACE}'..."
local rollback_args=(rollback "${HELM_RELEASE}")
[[ -n "$REVISION" ]] && rollback_args+=("${REVISION}")
rollback_args+=(-n "${NAMESPACE}" --wait --timeout 300s)
if ! helm "${rollback_args[@]}"; then
fatal "Helm rollback failed! Manual intervention required."
fi
ok "Helm rollback completed"
# Show current status
info "Current release status:"
helm status "${HELM_RELEASE}" -n "${NAMESPACE}" 2>/dev/null || true
}
# ── Kustomize rollback ─────────────────────────────────────────────────────
rollback_kustomize() {
info "Rolling back deployment '${APP_NAME}' in namespace '${NAMESPACE}'..."
local undo_args=(rollout undo "deployment/${APP_NAME}" -n "${NAMESPACE}")
if [[ -n "$REVISION" ]]; then
undo_args+=(--to-revision="${REVISION}")
fi
if ! kubectl "${undo_args[@]}"; then
fatal "Kubectl rollback failed! Manual intervention required."
fi
# Wait for rollout
info "Waiting for rollout to complete..."
if ! kubectl rollout status "deployment/${APP_NAME}" -n "${NAMESPACE}" --timeout=300s; then
fatal "Rollout did not complete in time!"
fi
ok "Kustomize rollback completed"
}
# ── Post-rollback health check ─────────────────────────────────────────────
run_health_check() {
if [[ "$SKIP_HEALTH_CHECK" == true ]]; then
info "Skipping health check"
return
fi
info "Running post-rollback health check..."
# Wait for pods to be ready
if ! kubectl wait --for=condition=ready pod \
-l "app.kubernetes.io/name=${APP_NAME}" \
-n "${NAMESPACE}" --timeout=120s 2>/dev/null; then
fatal "Pods did not become ready after rollback!"
fi
# Use health-check.sh if available
if [[ -x "${SCRIPT_DIR}/health-check.sh" ]]; then
# Port forward for check
local local_port=14820
kubectl port-forward "svc/${APP_NAME}" "${local_port}:${APP_PORT}" -n "${NAMESPACE}" &
local pf_pid=$!
sleep 3
if "${SCRIPT_DIR}/health-check.sh" --url "http://localhost:${local_port}" --retries 10 --interval 3; then
ok "Health check passed after rollback"
else
err "Health check failed after rollback!"
fi
kill "$pf_pid" 2>/dev/null || true
else
ok "Pods are ready"
fi
}
# ── Main ────────────────────────────────────────────────────────────────────
main() {
echo ""
echo -e "${BOLD}${YELLOW}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}${YELLOW}║ Claude Code Agent Monitor Rollback ║${NC}"
echo -e "${BOLD}${YELLOW}╚══════════════════════════════════════════════════╝${NC}"
echo ""
parse_args "$@"
show_history
confirm_rollback
case "$METHOD" in
helm) rollback_helm ;;
kustomize) rollback_kustomize ;;
*) fatal "Rollback not supported for method: ${METHOD}" ;;
esac
run_health_check
echo ""
ok "${BOLD}Rollback complete!${NC}"
echo -e " ${BOLD}Environment:${NC} ${ENVIRONMENT}"
echo -e " ${BOLD}Method:${NC} ${METHOD}"
echo -e " ${BOLD}Revision:${NC} ${REVISION:-previous}"
echo -e " ${BOLD}Timestamp:${NC} $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo ""
}
main "$@"