#!/usr/bin/env bash set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" cd "$ROOT" if [ -f .env ]; then set -a # shellcheck disable=SC1091 . ./.env set +a fi if [ -n "${DEPLOY_GEOINTEL_INSTALL_AI:-}" ]; then GEOINTEL_INSTALL_AI="$DEPLOY_GEOINTEL_INSTALL_AI" fi GEOINTEL_INSTALL_AI="${GEOINTEL_INSTALL_AI:-false}" GEOINTEL_BUILD_SHA="$(git rev-parse HEAD)" GEOINTEL_BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" GEOINTEL_IMAGE_REPOSITORY="${GEOINTEL_IMAGE_REPOSITORY:-geointel-all-in-one}" if [ "$GEOINTEL_INSTALL_AI" = "true" ]; then GEOINTEL_RELEASE_VARIANT="ai" else GEOINTEL_RELEASE_VARIANT="gis" fi GEOINTEL_RELEASE_IMAGE="${GEOINTEL_IMAGE_REPOSITORY}:${GEOINTEL_BUILD_SHA}-${GEOINTEL_RELEASE_VARIANT}" GEOINTEL_PREVIOUS_IMAGE="${GEOINTEL_IMAGE_REPOSITORY}:previous" FRONTEND_URL="${FRONTEND_URL:-http://127.0.0.1:${GEOINTEL_FRONTEND_PORT:-1202}}" wait_for_geointel_health() { local status="" for attempt in $(seq 1 90); do status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' geointel 2>/dev/null || true)" if [ "$status" = "healthy" ]; then echo "GeoIntel container is healthy after attempt ${attempt}." return 0 fi if [ "$status" = "unhealthy" ] || [ "$status" = "exited" ] || [ "$status" = "dead" ]; then echo "GeoIntel container entered terminal state: ${status}" >&2 docker logs --tail 120 geointel >&2 || true return 1 fi sleep 2 done echo "GeoIntel container did not become healthy (last state: ${status:-missing})." >&2 docker logs --tail 120 geointel >&2 || true return 1 } start_image() { local image="$1" GEOINTEL_IMAGE="$image" bash deploy/unraid/run-dockerman-container.sh wait_for_geointel_health } rollback_previous() { if ! docker image inspect "$GEOINTEL_PREVIOUS_IMAGE" >/dev/null 2>&1; then echo "Automatic rollback unavailable: ${GEOINTEL_PREVIOUS_IMAGE} does not exist." >&2 return 1 fi echo "Rolling back to ${GEOINTEL_PREVIOUS_IMAGE}..." start_image "$GEOINTEL_PREVIOUS_IMAGE" } docker compose -f docker-compose.unraid.yml config >/dev/null current_image_id="$(docker inspect --format '{{.Image}}' geointel 2>/dev/null || true)" release_image_id="$( docker image inspect --format '{{.Id}}' "$GEOINTEL_RELEASE_IMAGE" 2>/dev/null || true )" if ( [ -n "$current_image_id" ] && [ "$current_image_id" != "$release_image_id" ] && docker image inspect "$current_image_id" >/dev/null 2>&1 ); then docker tag "$current_image_id" "$GEOINTEL_PREVIOUS_IMAGE" elif [ -n "$current_image_id" ] && [ "$current_image_id" = "$release_image_id" ]; then echo "Current container already uses ${GEOINTEL_RELEASE_IMAGE}; preserving the existing previous image." fi if docker image inspect "$GEOINTEL_RELEASE_IMAGE" >/dev/null 2>&1; then stored_revision="$( docker image inspect \ --format '{{index .Config.Labels "org.opencontainers.image.revision"}}' \ "$GEOINTEL_RELEASE_IMAGE" )" stored_ai="$( docker image inspect \ --format '{{index .Config.Labels "io.geointel.ai.enabled"}}' \ "$GEOINTEL_RELEASE_IMAGE" )" if [ "$stored_revision" != "$GEOINTEL_BUILD_SHA" ] || [ "$stored_ai" != "$GEOINTEL_INSTALL_AI" ]; then echo "Immutable release tag has conflicting metadata: ${GEOINTEL_RELEASE_IMAGE}" >&2 exit 2 fi echo "Reusing existing immutable image ${GEOINTEL_RELEASE_IMAGE}." docker tag "$GEOINTEL_RELEASE_IMAGE" "${GEOINTEL_IMAGE_REPOSITORY}:latest" else docker build \ --build-arg GEOINTEL_INSTALL_AI="$GEOINTEL_INSTALL_AI" \ --build-arg GEOINTEL_BUILD_SHA="$GEOINTEL_BUILD_SHA" \ --build-arg GEOINTEL_BUILD_TIME="$GEOINTEL_BUILD_TIME" \ -f deploy/unraid/Dockerfile.all-in-one \ -t "$GEOINTEL_RELEASE_IMAGE" \ -t "${GEOINTEL_IMAGE_REPOSITORY}:latest" \ . fi if ! start_image "$GEOINTEL_RELEASE_IMAGE"; then rollback_previous || true exit 1 fi if [ -x scripts/live_migration_smoke.sh ]; then if ! LIVE_SMOKE_CONTAINER=geointel bash scripts/live_migration_smoke.sh; then rollback_previous || true exit 1 fi fi if [ -x scripts/verify_browser_runtime.sh ]; then if ! bash scripts/verify_browser_runtime.sh "$FRONTEND_URL"; then rollback_previous || true exit 1 fi fi echo "Deployed immutable image ${GEOINTEL_RELEASE_IMAGE}." docker image inspect \ --format 'revision={{index .Config.Labels "org.opencontainers.image.revision"}} created={{index .Config.Labels "org.opencontainers.image.created"}}' \ "$GEOINTEL_RELEASE_IMAGE"