install_offline.sh 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  4. # shellcheck source=wp13-common.sh
  5. source "${SCRIPT_DIR}/wp13-common.sh"
  6. usage() {
  7. cat <<'EOF'
  8. Usage: install_offline.sh [options]
  9. Verify, load, and start a DataOps offline Compose bundle.
  10. Options:
  11. --bundle-root PATH Extracted bundle root (default: parent of operations/).
  12. --env-file PATH Optional environment file.
  13. --environment-profile PATH
  14. Validated JSON profile; selects matching .env and project.
  15. --project-name NAME Compose project (default: dataops-test).
  16. --timeout SECONDS Health timeout (default: 600).
  17. --help Show this help.
  18. EOF
  19. }
  20. BUNDLE_ROOT="$(wp13_default_root)"
  21. ENV_FILE=""
  22. ENVIRONMENT_PROFILE=""
  23. PROJECT_NAME=""
  24. TIMEOUT_SECONDS=600
  25. while [[ $# -gt 0 ]]; do
  26. case "$1" in
  27. --bundle-root) BUNDLE_ROOT="$2"; shift 2 ;;
  28. --env-file) ENV_FILE="$2"; shift 2 ;;
  29. --environment-profile) ENVIRONMENT_PROFILE="$2"; shift 2 ;;
  30. --project-name) PROJECT_NAME="$2"; shift 2 ;;
  31. --timeout) TIMEOUT_SECONDS="$2"; shift 2 ;;
  32. --help|-h) usage; exit 0 ;;
  33. *) wp13_die "unknown argument: $1" ;;
  34. esac
  35. done
  36. BUNDLE_ROOT="$(cd "${BUNDLE_ROOT}" && pwd)"
  37. COMPOSE_FILE="${BUNDLE_ROOT}/deploy/docker/docker-compose.yml"
  38. if [[ -n "${ENVIRONMENT_PROFILE}" ]]; then
  39. if [[ "${ENVIRONMENT_PROFILE}" != /* ]]; then
  40. ENVIRONMENT_PROFILE="${BUNDLE_ROOT}/${ENVIRONMENT_PROFILE}"
  41. fi
  42. [[ -r "${ENVIRONMENT_PROFILE}" ]] \
  43. || wp13_die "environment profile is not readable: ${ENVIRONMENT_PROFILE}"
  44. wp13_require_command python3
  45. PROFILE_PROJECT="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1], encoding="utf-8"))["project_name"])' "${ENVIRONMENT_PROFILE}")"
  46. PROFILE_ENV_FILE="${ENVIRONMENT_PROFILE%.json}.env"
  47. if [[ -n "${PROJECT_NAME}" && "${PROJECT_NAME}" != "${PROFILE_PROJECT}" ]]; then
  48. wp13_die "project name does not match environment profile: ${PROJECT_NAME} != ${PROFILE_PROJECT}"
  49. fi
  50. PROJECT_NAME="${PROFILE_PROJECT}"
  51. ENV_FILE="${PROFILE_ENV_FILE}"
  52. fi
  53. PROJECT_NAME="${PROJECT_NAME:-dataops-test}"
  54. wp13_verify_checksums "${BUNDLE_ROOT}"
  55. wp13_require_command docker
  56. if [[ -f "${BUNDLE_ROOT}/images/dataops-images.tar" ]]; then
  57. wp13_log "loading offline images"
  58. docker load -i "${BUNDLE_ROOT}/images/dataops-images.tar" >/dev/null
  59. else
  60. wp13_log "image archive not present; using preloaded local images"
  61. fi
  62. preflight_args=(
  63. --bundle-root "${BUNDLE_ROOT}"
  64. --compose-file "${COMPOSE_FILE}"
  65. --project-name "${PROJECT_NAME}"
  66. )
  67. [[ -z "${ENV_FILE}" ]] || preflight_args+=(--env-file "${ENV_FILE}")
  68. [[ -z "${ENVIRONMENT_PROFILE}" ]] || preflight_args+=(--environment-profile "${ENVIRONMENT_PROFILE}")
  69. bash "${SCRIPT_DIR}/preflight.sh" "${preflight_args[@]}"
  70. wp13_compose "${COMPOSE_FILE}" "${PROJECT_NAME}" "${ENV_FILE}" \
  71. up -d --no-build
  72. wp13_wait_for_project "${PROJECT_NAME}" "${TIMEOUT_SECONDS}"
  73. current="$(
  74. wp13_compose "${COMPOSE_FILE}" "${PROJECT_NAME}" "${ENV_FILE}" \
  75. exec -T backend alembic -c alembic.ini current \
  76. | awk 'NF {print $1; exit}'
  77. )"
  78. head="$(
  79. wp13_compose "${COMPOSE_FILE}" "${PROJECT_NAME}" "${ENV_FILE}" \
  80. exec -T backend alembic -c alembic.ini heads \
  81. | awk 'NF {print $1; exit}'
  82. )"
  83. [[ -n "${current}" && "${current}" == "${head}" ]] \
  84. || wp13_die "post-install migration mismatch: current=${current:-unknown}, head=${head:-unknown}"
  85. expected_head="$(wp13_expected_migration_head "${BUNDLE_ROOT}")"
  86. [[ -n "${expected_head}" ]] \
  87. || wp13_die "release manifest migration head is missing"
  88. [[ "${head}" == "${expected_head}" ]] \
  89. || wp13_die "installed image migration head does not match release manifest: image=${head}, release=${expected_head}"
  90. cp "${BUNDLE_ROOT}/release-manifest.txt" \
  91. "${BUNDLE_ROOT}/installed-${PROJECT_NAME}.manifest"
  92. cp "${BUNDLE_ROOT}/release-manifest.json" \
  93. "${BUNDLE_ROOT}/installed-${PROJECT_NAME}.manifest.json"
  94. wp13_log "offline install completed at migration ${current}"