#!/usr/bin/env bash set -euo pipefail if [[ ${EUID} -ne 0 ]]; then printf '%s\n' "activate-release must run as root" >&2 exit 1 fi archive=${1:-} checksum=${2:-} if [[ -z "$archive" || -z "$checksum" || ! -f "$archive" ]]; then printf '%s\n' "usage: activate-release.sh " >&2 exit 1 fi if [[ "$archive" != /opt/harbor/incoming/* ]]; then printf '%s\n' "archive must be under /opt/harbor/incoming" >&2 exit 1 fi actual=$(sha256sum "$archive" | cut -d' ' -f1) if [[ "$actual" != "$checksum" ]]; then printf '%s\n' "release checksum mismatch" >&2 exit 1 fi release_id=$(basename "$archive" .tar.gz) if [[ ! "$release_id" =~ ^harbor-[0-9]{8}T[0-9]{6}Z-[a-zA-Z0-9._-]+$ ]]; then printf '%s\n' "invalid release archive name" >&2 exit 1 fi release_dir=/opt/harbor/releases/$release_id if [[ ! -d "$release_dir" ]]; then install -d -m 0755 "$release_dir" tar -xzf "$archive" -C "$release_dir" fi test -x "$release_dir/bin/gateway" test -x "$release_dir/bin/worker" test -x "$release_dir/bin/migrate" test -f "$release_dir/web/index.html" chown -R root:harbor "$release_dir" find "$release_dir" -type d -exec chmod 0755 {} + find "$release_dir" -type f -exec chmod 0644 {} + chmod 0755 "$release_dir/bin/gateway" "$release_dir/bin/worker" "$release_dir/bin/migrate" active=blue if [[ -f /etc/harbor/active-slot ]]; then active=$(cat /etc/harbor/active-slot) fi if [[ "$active" == blue ]]; then inactive=green inactive_port=8889 else inactive=blue inactive_port=8888 fi if systemctl is-active --quiet "harbor-gateway@$inactive.service"; then connections=$(ss -Htn state established "( sport = :$inactive_port )" | wc -l) if (( connections > 0 )); then printf '%s\n' "inactive slot still has $connections established connection(s); retry later" >&2 exit 1 fi systemctl stop "harbor-gateway@$inactive.service" fi systemctl stop "harbor-worker@$inactive.service" 2>/dev/null || true set -a source /etc/harbor/harbor.env set +a printf '%s\n' "running forward migrations" "$release_dir/bin/migrate" -path "$release_dir/migrations" -database "$MONGO_URL" up || status=$? if [[ ${status:-0} -ne 0 && ${status:-0} -ne 2 ]]; then exit "$status" fi ln -sfn "$release_dir" "/opt/harbor/slots/$inactive" chown -h harbor:harbor "/opt/harbor/slots/$inactive" systemctl start "harbor-gateway@$inactive.service" for _ in $(seq 1 60); do if curl -fsS "http://127.0.0.1:$inactive_port/api/v1/health" >/dev/null; then break fi sleep 1 done if ! curl -fsS "http://127.0.0.1:$inactive_port/api/v1/health" >/dev/null; then journalctl -u "harbor-gateway@$inactive.service" -n 80 --no-pager >&2 systemctl stop "harbor-gateway@$inactive.service" exit 1 fi if [[ -L /opt/harbor/current ]]; then readlink -f /opt/harbor/current > /etc/harbor/previous-release printf '%s\n' "$active" > /etc/harbor/previous-slot fi ln -sfn "$release_dir" /opt/harbor/current.new mv -Tf /opt/harbor/current.new /opt/harbor/current printf 'server 127.0.0.1:%s;\n' "$inactive_port" > /etc/nginx/harbor-active-server.conf.new mv -f /etc/nginx/harbor-active-server.conf.new /etc/nginx/harbor-active-server.conf nginx -t systemctl reload nginx printf '%s\n' "$inactive" > /etc/harbor/active-slot systemctl start "harbor-worker@$inactive.service" sleep 3 if ! systemctl is-active --quiet "harbor-worker@$inactive.service"; then journalctl -u "harbor-worker@$inactive.service" -n 80 --no-pager >&2 /opt/harbor/deploy/remote/rollback.sh || true exit 1 fi systemctl stop --no-block "harbor-worker@$active.service" 2>/dev/null || true curl -fsS http://127.0.0.1/health >/dev/null rm -f "$archive" printf '%s\n' "activated $release_id on $inactive ($inactive_port)"