| #!/usr/bin/env bash |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| ################################################################ |
| # This script will restart all thirdparty containers |
| ################################################################ |
| |
| set -eo pipefail |
| |
| ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" |
| |
| . "${ROOT}/custom_settings.env" |
| . "${ROOT}/juicefs-helpers.sh" |
| . "${ROOT}/docker-health.sh" |
| . "${ROOT}/docker-compose/hive/scripts/bootstrap/bootstrap-groups.sh" |
| |
| usage() { |
| echo " |
| Usage: $0 <options> |
| Optional options: |
| [no option] start all components |
| --help,-h show this usage |
| -c mysql start MySQL |
| -c mysql,hive3 start MySQL and Hive3 |
| --stop stop the specified components |
| --reserve-ports reserve host ports by setting 'net.ipv4.ip_local_reserved_ports' to avoid port already bind error |
| --no-load-data do not load data into the components |
| --load-parallel <num> set the parallel number to load data, default is the 50% of CPU cores |
| --hive-mode <mode> hive startup mode: fast, refresh, rebuild |
| --hive-modules <list> comma separated hive modules to refresh |
| |
| All valid components: |
| mysql,pg,oracle,sqlserver,clickhouse,es,hive2,hive3,iceberg,iceberg-rest,hudi,kafka,mariadb,db2,oceanbase,lakesoul,kerberos,ranger,polaris,minio |
| " |
| exit 1 |
| } |
| DEFAULT_COMPONENTS="mysql,es,hive2,hive3,pg,oracle,sqlserver,clickhouse,mariadb,iceberg,hudi,db2,oceanbase,kerberos,minio" |
| ALL_COMPONENTS="${DEFAULT_COMPONENTS},kafka,lakesoul,ranger,polaris" |
| COMPONENTS=$2 |
| HELP=0 |
| STOP=0 |
| NEED_RESERVE_PORTS=0 |
| export NEED_LOAD_DATA=1 |
| export LOAD_PARALLEL=$(( $(getconf _NPROCESSORS_ONLN) / 2 )) |
| export START_PROGRESS_INTERVAL="${START_PROGRESS_INTERVAL:-60}" |
| export HIVE_HQL_PARALLEL="${HIVE_HQL_PARALLEL:-4}" |
| export START_CLEANUP_ON_FAILURE="${START_CLEANUP_ON_FAILURE:-1}" |
| export HIVE_MODE="${HIVE_MODE:-refresh}" |
| export HIVE_MODULES="${HIVE_MODULES:-all}" |
| HIVE_SHARED_ID="doris-shared" |
| : "${HIVE_BASELINE_VERSION:?HIVE_BASELINE_VERSION must be set in custom_settings.env}" |
| : "${HIVE_BASELINE_TARBALL_CACHE:?HIVE_BASELINE_TARBALL_CACHE must be set in custom_settings.env}" |
| |
| if [[ -z "${IP_HOST:-}" ]]; then |
| if command -v ip >/dev/null 2>&1; then |
| export IP_HOST=$(ip -4 addr show scope global | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1) |
| elif command -v hostname >/dev/null 2>&1; then |
| export IP_HOST=$(hostname -I 2>/dev/null | awk '{print $1}') |
| fi |
| fi |
| |
| if ! OPTS="$(getopt \ |
| -n "$0" \ |
| -o '' \ |
| -l 'help' \ |
| -l 'stop' \ |
| -l 'reserve-ports' \ |
| -l 'no-load-data' \ |
| -l 'load-parallel:' \ |
| -l 'hive-mode:' \ |
| -l 'hive-modules:' \ |
| -o 'hc:' \ |
| -- "$@")"; then |
| usage |
| fi |
| |
| eval set -- "${OPTS}" |
| |
| if [[ "$#" == 1 ]]; then |
| # default |
| COMPONENTS="${DEFAULT_COMPONENTS}" |
| else |
| while true; do |
| case "$1" in |
| -h) |
| HELP=1 |
| shift |
| ;; |
| --help) |
| HELP=1 |
| shift |
| ;; |
| --stop) |
| STOP=1 |
| shift |
| ;; |
| -c) |
| COMPONENTS=$2 |
| shift 2 |
| ;; |
| --reserve-ports) |
| NEED_RESERVE_PORTS=1 |
| shift |
| ;; |
| --no-load-data) |
| export NEED_LOAD_DATA=0 |
| shift |
| ;; |
| --load-parallel) |
| export LOAD_PARALLEL=$2 |
| shift 2 |
| ;; |
| --hive-mode) |
| export HIVE_MODE=$2 |
| shift 2 |
| ;; |
| --hive-modules) |
| export HIVE_MODULES=$2 |
| shift 2 |
| ;; |
| --) |
| shift |
| break |
| ;; |
| *) |
| echo "Internal error" |
| exit 1 |
| ;; |
| esac |
| done |
| if [[ "${COMPONENTS}"x == ""x ]]; then |
| if [[ "${STOP}" -eq 1 ]]; then |
| COMPONENTS="${ALL_COMPONENTS}" |
| fi |
| if [[ "${NEED_RESERVE_PORTS}" -eq 1 ]]; then |
| COMPONENTS="${DEFAULT_COMPONENTS}" |
| fi |
| fi |
| fi |
| |
| if [[ "${HELP}" -eq 1 ]]; then |
| usage |
| fi |
| |
| if [[ "${COMPONENTS}"x == ""x ]]; then |
| echo "Invalid arguments" |
| echo ${COMPONENTS} |
| usage |
| fi |
| |
| if [[ "${CONTAINER_UID}"x == "doris--"x ]]; then |
| echo "Must set CONTAINER_UID to a unique name in custom_settings.env" |
| exit 1 |
| fi |
| |
| if [[ -z "${HIVE_HOST_ALIAS:-}" ]]; then |
| export HIVE_HOST_ALIAS="hadoop-master-${HIVE_SHARED_ID}" |
| fi |
| |
| echo "Components are: ${COMPONENTS}" |
| echo "Container UID: ${CONTAINER_UID}" |
| echo "Stop: ${STOP}" |
| echo "Start progress interval: ${START_PROGRESS_INTERVAL}" |
| echo "Hive mode: ${HIVE_MODE}" |
| echo "Hive modules: ${HIVE_MODULES}" |
| echo "Hive HQL parallel: ${HIVE_HQL_PARALLEL}" |
| echo "Hive host alias: ${HIVE_HOST_ALIAS}" |
| |
| if ! [[ "${START_PROGRESS_INTERVAL}" =~ ^[1-9][0-9]*$ ]]; then |
| echo "Invalid start progress interval: ${START_PROGRESS_INTERVAL}" |
| usage |
| fi |
| |
| if ! [[ "${HIVE_HQL_PARALLEL}" =~ ^[1-9][0-9]*$ ]]; then |
| echo "Invalid hive HQL parallel: ${HIVE_HQL_PARALLEL}" |
| usage |
| fi |
| |
| case "${START_CLEANUP_ON_FAILURE}" in |
| 0|1) |
| ;; |
| *) |
| echo "Invalid start cleanup on failure: ${START_CLEANUP_ON_FAILURE}" |
| usage |
| ;; |
| esac |
| |
| case "${HIVE_MODE}" in |
| fast|refresh|rebuild) |
| ;; |
| *) |
| echo "Invalid hive mode: ${HIVE_MODE}" |
| usage |
| ;; |
| esac |
| |
| OLD_IFS="${IFS}" |
| IFS=',' |
| read -r -a COMPONENTS_ARR <<<"${COMPONENTS}" |
| IFS="${OLD_IFS}" |
| |
| RUN_MYSQL=0 |
| RUN_PG=0 |
| RUN_ORACLE=0 |
| RUN_SQLSERVER=0 |
| RUN_CLICKHOUSE=0 |
| RUN_HIVE2=0 |
| RUN_HIVE3=0 |
| RUN_ES=0 |
| RUN_ICEBERG=0 |
| RUN_ICEBERG_REST=0 |
| RUN_HUDI=0 |
| RUN_KAFKA=0 |
| RUN_MARIADB=0 |
| RUN_DB2=0 |
| RUN_OCEANBASE=0 |
| RUN_LAKESOUL=0 |
| RUN_KERBEROS=0 |
| RUN_MINIO=0 |
| RUN_RANGER=0 |
| RUN_POLARIS=0 |
| |
| RESERVED_PORTS="65535" |
| |
| for element in "${COMPONENTS_ARR[@]}"; do |
| if [[ "${element}"x == "mysql"x ]]; then |
| RUN_MYSQL=1 |
| elif [[ "${element}"x == "pg"x ]]; then |
| RUN_PG=1 |
| elif [[ "${element}"x == "oracle"x ]]; then |
| RUN_ORACLE=1 |
| elif [[ "${element}"x == "sqlserver"x ]]; then |
| RUN_SQLSERVER=1 |
| elif [[ "${element}"x == "clickhouse"x ]]; then |
| RUN_CLICKHOUSE=1 |
| elif [[ "${element}"x == "es"x ]]; then |
| RUN_ES=1 |
| elif [[ "${element}"x == "hive2"x ]]; then |
| RUN_HIVE2=1 |
| RESERVED_PORTS="${RESERVED_PORTS},50070,50075" # namenode and datanode ports |
| elif [[ "${element}"x == "hive3"x ]]; then |
| RUN_HIVE3=1 |
| elif [[ "${element}"x == "kafka"x ]]; then |
| RUN_KAFKA=1 |
| elif [[ "${element}"x == "iceberg"x ]]; then |
| RUN_ICEBERG=1 |
| elif [[ "${element}"x == "iceberg-rest"x ]]; then |
| RUN_ICEBERG_REST=1 |
| elif [[ "${element}"x == "hudi"x ]]; then |
| RUN_HUDI=1 |
| RESERVED_PORTS="${RESERVED_PORTS},19083,19100,19101,18080" |
| elif [[ "${element}"x == "mariadb"x ]]; then |
| RUN_MARIADB=1 |
| elif [[ "${element}"x == "db2"x ]]; then |
| RUN_DB2=1 |
| elif [[ "${element}"x == "oceanbase"x ]];then |
| RUN_OCEANBASE=1 |
| elif [[ "${element}"x == "lakesoul"x ]]; then |
| RUN_LAKESOUL=1 |
| elif [[ "${element}"x == "kerberos"x ]]; then |
| RUN_KERBEROS=1 |
| elif [[ "${element}"x == "minio"x ]]; then |
| RUN_MINIO=1 |
| elif [[ "${element}"x == "ranger"x ]]; then |
| RUN_RANGER=1 |
| elif [[ "${element}"x == "polaris"x ]]; then |
| RUN_POLARIS=1 |
| else |
| echo "Invalid component: ${element}" |
| usage |
| fi |
| done |
| |
| hive_bootstrap_groups_for() { |
| local hive_version="$1" |
| case "${hive_version}" in |
| hive2) |
| echo "common,hive2_only" |
| ;; |
| hive3) |
| echo "common,hive3_only" |
| ;; |
| *) |
| echo "Unsupported hive version: ${hive_version}" >&2 |
| return 1 |
| ;; |
| esac |
| } |
| |
| hive_requires_mysql_component() { |
| local hive_version="$1" |
| local jfs_meta="" |
| local settings_env="${ROOT}/docker-compose/hive/hive-${hive_version#hive}x_settings.env" |
| |
| # shellcheck disable=SC1090 |
| . "${settings_env}" |
| jfs_meta="${JFS_CLUSTER_META:-}" |
| [[ "${jfs_meta}" == mysql://* ]] || return 1 |
| [[ "${jfs_meta}" == *"@(127.0.0.1:3316)/"* || "${jfs_meta}" == *"@(localhost:3316)/"* ]] |
| } |
| |
| if [[ "${RUN_HIVE2}" -eq 1 ]] && hive_requires_mysql_component "hive2"; then |
| RUN_MYSQL=1 |
| fi |
| if [[ "${RUN_HIVE3}" -eq 1 ]] && hive_requires_mysql_component "hive3"; then |
| RUN_MYSQL=1 |
| fi |
| |
| reserve_ports() { |
| if [[ "${NEED_RESERVE_PORTS}" -eq 0 ]]; then |
| return |
| fi |
| |
| if [[ "${RESERVED_PORTS}"x != ""x ]]; then |
| echo "Reserve ports: ${RESERVED_PORTS}" |
| sudo sysctl -w net.ipv4.ip_local_reserved_ports="${RESERVED_PORTS}" |
| fi |
| } |
| |
| JFS_META_FORMATTED=0 |
| DORIS_ROOT="${DORIS_ROOT:-$(cd "${ROOT}/../.." &>/dev/null && pwd)}" |
| JUICEFS_RUNTIME_ROOT="${ROOT}/juicefs" |
| LOG_ROOT="${ROOT}/logs" |
| |
| mkdir -p "${LOG_ROOT}" |
| |
| JUICEFS_LOCAL_BIN="${JUICEFS_RUNTIME_ROOT}/bin/juicefs" |
| |
| find_juicefs_hadoop_jar() { |
| local -a jar_globs=( |
| "${JUICEFS_RUNTIME_ROOT}/lib/juicefs-hadoop-[0-9]*.jar" |
| "${DORIS_ROOT}/thirdparty/installed/juicefs_libs/juicefs-hadoop-[0-9]*.jar" |
| "${DORIS_ROOT}/output/fe/lib/juicefs/juicefs-hadoop-[0-9]*.jar" |
| "${DORIS_ROOT}/output/be/lib/java_extensions/juicefs/juicefs-hadoop-[0-9]*.jar" |
| "${DORIS_ROOT}/../../../clusterEnv/*/Cluster*/fe/lib/juicefs/juicefs-hadoop-[0-9]*.jar" |
| "${DORIS_ROOT}/../../../clusterEnv/*/Cluster*/be/lib/java_extensions/juicefs/juicefs-hadoop-[0-9]*.jar" |
| "/mnt/ssd01/pipline/OpenSourceDoris/clusterEnv/*/Cluster*/fe/lib/juicefs/juicefs-hadoop-[0-9]*.jar" |
| "/mnt/ssd01/pipline/OpenSourceDoris/clusterEnv/*/Cluster*/be/lib/java_extensions/juicefs/juicefs-hadoop-[0-9]*.jar" |
| ) |
| juicefs_find_hadoop_jar_by_globs "${jar_globs[@]}" |
| } |
| |
| detect_juicefs_version() { |
| local juicefs_jar |
| juicefs_jar=$(find_juicefs_hadoop_jar || true) |
| juicefs_detect_hadoop_version "${juicefs_jar}" "${JUICEFS_DEFAULT_VERSION}" |
| } |
| |
| download_juicefs_hadoop_jar() { |
| local juicefs_version="$1" |
| local cache_dir="${JUICEFS_RUNTIME_ROOT}/lib" |
| juicefs_download_hadoop_jar_to_cache "${juicefs_version}" "${cache_dir}" |
| } |
| |
| install_juicefs_cli() { |
| local juicefs_version="$1" |
| local cache_dir="${JUICEFS_RUNTIME_ROOT}/bin" |
| local archive_name |
| local -a download_urls=() |
| local tmp_dir |
| local extracted_bin |
| |
| archive_name=$(juicefs_cli_archive_name "${juicefs_version}") |
| mkdir -p "${cache_dir}" |
| tmp_dir=$(mktemp -d "${cache_dir}/tmp.XXXXXX") |
| mapfile -t download_urls < <(juicefs_cli_archive_download_urls "${juicefs_version}") |
| |
| if ! juicefs_download_file "${tmp_dir}/${archive_name}" "JuiceFS CLI ${juicefs_version}" "${download_urls[@]}"; then |
| rm -rf "${tmp_dir}" |
| echo "ERROR: failed to download JuiceFS CLI ${juicefs_version}" >&2 |
| return 1 |
| fi |
| |
| tar -xzf "${tmp_dir}/${archive_name}" -C "${tmp_dir}" |
| extracted_bin=$(find "${tmp_dir}" -maxdepth 2 -type f -name juicefs | head -n 1) |
| if [[ -z "${extracted_bin}" ]]; then |
| rm -rf "${tmp_dir}" |
| echo "ERROR: failed to locate extracted JuiceFS CLI in ${archive_name}" >&2 |
| return 1 |
| fi |
| |
| install -m 0755 "${extracted_bin}" "${JUICEFS_LOCAL_BIN}" |
| rm -rf "${tmp_dir}" |
| } |
| |
| resolve_juicefs_cli() { |
| local juicefs_version |
| |
| if command -v juicefs >/dev/null 2>&1; then |
| command -v juicefs |
| return 0 |
| fi |
| |
| if [[ -x "${JUICEFS_LOCAL_BIN}" ]]; then |
| echo "${JUICEFS_LOCAL_BIN}" |
| return 0 |
| fi |
| |
| juicefs_version=$(detect_juicefs_version) |
| install_juicefs_cli "${juicefs_version}" || return 1 |
| echo "${JUICEFS_LOCAL_BIN}" |
| } |
| |
| ensure_juicefs_meta_database() { |
| local jfs_meta="$1" |
| local meta_db |
| local mysql_container |
| local pg_container |
| local -a pg_candidates |
| |
| meta_db="${jfs_meta##*/}" |
| meta_db="${meta_db%%\?*}" |
| if [[ ! "${meta_db}" =~ ^[A-Za-z0-9_]+$ ]]; then |
| echo "WARN: skip JuiceFS metadata database creation for unsafe database name '${meta_db}'." >&2 |
| return 0 |
| fi |
| |
| if [[ "${jfs_meta}" == mysql://* ]]; then |
| if [[ "${jfs_meta}" != *"@(127.0.0.1:3316)/"* && "${jfs_meta}" != *"@(localhost:3316)/"* ]]; then |
| return 0 |
| fi |
| |
| mysql_container=$(sudo docker ps --format '{{.Names}}' | grep -E "(^|-)${CONTAINER_UID}mysql_57(-[0-9]+)?$" | head -n 1 || true) |
| if [[ -n "${mysql_container}" ]]; then |
| if sudo docker exec "${mysql_container}" \ |
| mysql -uroot -p123456 -e "CREATE DATABASE IF NOT EXISTS \`${meta_db}\`;" >/dev/null 2>&1; then |
| return 0 |
| fi |
| echo "WARN: docker mysql ${mysql_container} is unavailable for JuiceFS metadata init." >&2 |
| return 0 |
| fi |
| |
| echo "WARN: docker mysql_57 is not running; skip eager JuiceFS metadata database creation for ${meta_db}." >&2 |
| return 0 |
| fi |
| |
| if [[ "${jfs_meta}" == postgres://* || "${jfs_meta}" == postgresql://* ]]; then |
| if [[ "${jfs_meta}" != *"@127.0.0.1:"* && "${jfs_meta}" != *"@localhost:"* ]]; then |
| return 0 |
| fi |
| |
| pg_candidates=( |
| "hive3-metastore-postgresql" |
| "hive2-metastore-postgresql" |
| "${CONTAINER_UID}postgres" |
| "postgres" |
| ) |
| |
| for pg_container in "${pg_candidates[@]}"; do |
| if ! sudo docker ps --format '{{.Names}}' | grep -Fxq "${pg_container}"; then |
| continue |
| fi |
| |
| if sudo docker exec "${pg_container}" \ |
| psql -U postgres -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='${meta_db}'" | grep -q '^1$'; then |
| return 0 |
| fi |
| |
| if sudo docker exec "${pg_container}" \ |
| psql -U postgres -d postgres -c "CREATE DATABASE \"${meta_db}\";" >/dev/null 2>&1; then |
| return 0 |
| fi |
| |
| echo "WARN: docker postgres ${pg_container} is unavailable for JuiceFS metadata init." >&2 |
| return 0 |
| done |
| |
| echo "WARN: no local postgres container for JuiceFS metadata init; skip eager database creation for ${meta_db}." >&2 |
| return 0 |
| fi |
| |
| return 0 |
| } |
| |
| run_juicefs_cli() { |
| local juicefs_cli |
| if ! juicefs_cli=$(resolve_juicefs_cli); then |
| echo "ERROR: JuiceFS CLI is not available (download failed or binary not found)" >&2 |
| return 1 |
| fi |
| "${juicefs_cli}" "$@" |
| } |
| |
| ensure_juicefs_hadoop_jar_for_hive() { |
| local auxlib_dir="${ROOT}/docker-compose/hive/scripts/auxlib" |
| local source_jar |
| local juicefs_version |
| |
| source_jar=$(find_juicefs_hadoop_jar || true) |
| if [[ -z "${source_jar}" ]]; then |
| juicefs_version=$(detect_juicefs_version) |
| source_jar=$(download_juicefs_hadoop_jar "${juicefs_version}" || true) |
| fi |
| |
| if [[ -z "${source_jar}" ]]; then |
| echo "WARN: skip syncing juicefs-hadoop jar for hive, not found and download failed." |
| return 0 |
| fi |
| |
| mkdir -p "${auxlib_dir}" |
| if [[ "${source_jar}" == "${auxlib_dir}/$(basename "${source_jar}")" ]]; then |
| echo "JuiceFS Hadoop jar already exists in hive auxlib: $(basename "${source_jar}")" |
| return 0 |
| fi |
| cp -f "${source_jar}" "${auxlib_dir}/" |
| echo "Synced JuiceFS Hadoop jar to hive auxlib: $(basename "${source_jar}")" |
| } |
| |
| prepare_juicefs_meta_for_hive() { |
| local jfs_meta="$1" |
| local jfs_cluster_name="${2:-cluster}" |
| if [[ -z "${jfs_meta}" ]]; then |
| return 0 |
| fi |
| if [[ "${jfs_meta}" != mysql://* && "${jfs_meta}" != postgres://* && "${jfs_meta}" != postgresql://* ]]; then |
| return 0 |
| fi |
| if [[ "${JFS_META_FORMATTED}" -eq 1 ]]; then |
| return 0 |
| fi |
| |
| # JuiceFS CLI is required; if unavailable (e.g. no network), skip gracefully. |
| if ! resolve_juicefs_cli >/dev/null 2>&1; then |
| echo "WARN: JuiceFS CLI not available; skipping JuiceFS metadata init for ${jfs_meta}." >&2 |
| echo "WARN: JuiceFS-dependent tests will fail. Ensure juicefs binary is on PATH or network access to github.com is available." >&2 |
| return 0 |
| fi |
| |
| local bucket_dir="${JFS_BUCKET_DIR:-/tmp/jfs-bucket}" |
| sudo mkdir -p "${bucket_dir}" |
| sudo chmod 777 "${bucket_dir}" |
| |
| # For local docker metadata DSNs (mysql/postgresql), ensure metadata database exists. |
| ensure_juicefs_meta_database "${jfs_meta}" |
| |
| if run_juicefs_cli status "${jfs_meta}" >/dev/null 2>&1; then |
| echo "JuiceFS metadata is already formatted." |
| JFS_META_FORMATTED=1 |
| return 0 |
| fi |
| |
| # Clean stale bucket data before formatting. When meta is not formatted, |
| # any leftover data in the bucket directory is orphaned from a previous run |
| # and will cause "juicefs format" to fail with "Storage ... is not empty". |
| if [[ -d "${bucket_dir}" ]]; then |
| echo "Cleaning stale JuiceFS bucket directory: ${bucket_dir}" |
| sudo rm -rf "${bucket_dir:?}"/* |
| fi |
| |
| if ! run_juicefs_cli \ |
| format --storage file --bucket "${bucket_dir}" "${jfs_meta}" "${jfs_cluster_name}"; then |
| # If format reports conflict on rerun, verify by status and continue. |
| run_juicefs_cli status "${jfs_meta}" >/dev/null 2>&1 || true |
| fi |
| |
| JFS_META_FORMATTED=1 |
| } |
| |
| render_uid_template() { |
| local template_file="$1" |
| local output_file="$2" |
| local replacement="${CONTAINER_UID//\\/\\\\}" |
| |
| replacement="${replacement//&/\\&}" |
| replacement="${replacement//|/\\|}" |
| |
| sed "s|doris--|${replacement}|g" "${template_file}" >"${output_file}" |
| } |
| |
| compose_cmd() { |
| local compose_file="$1" |
| local env_file="$2" |
| shift 2 |
| |
| if [[ -n "${env_file}" ]]; then |
| sudo docker compose -f "${compose_file}" --env-file "${env_file}" "$@" |
| else |
| sudo docker compose -f "${compose_file}" "$@" |
| fi |
| } |
| |
| compose_down_stack() { |
| local compose_file="$1" |
| local env_file="$2" |
| shift 2 |
| |
| compose_cmd "${compose_file}" "${env_file}" down "$@" |
| } |
| |
| compose_up_stack() { |
| local compose_file="$1" |
| local env_file="$2" |
| shift 2 |
| |
| compose_cmd "${compose_file}" "${env_file}" up "$@" |
| } |
| |
| reset_data_dirs() { |
| local data_dir |
| |
| for data_dir in "$@"; do |
| sudo mkdir -p "${data_dir}" |
| sudo rm -rf "${data_dir:?}"/* |
| done |
| } |
| |
| declare -A START_PIDS=() |
| declare -A START_LOGS=() |
| declare -A START_COMPOSE_FILES=() |
| declare -A START_ENV_FILES=() |
| declare -A START_DONE=() |
| START_ORDER=() |
| |
| register_stack_metadata() { |
| local component="$1" |
| local compose_file="$2" |
| local env_file="${3:-}" |
| |
| START_COMPOSE_FILES["${component}"]="${compose_file}" |
| START_ENV_FILES["${component}"]="${env_file}" |
| } |
| |
| start_rendered_compose_stack() { |
| local component="$1" |
| local template_file="$2" |
| local compose_file="$3" |
| local env_file="$4" |
| shift 4 |
| |
| local stage="up" |
| local -a up_args=() |
| local -a reset_dirs=() |
| |
| while (($#)); do |
| if [[ "$1" == "--" ]]; then |
| stage="reset" |
| shift |
| continue |
| fi |
| |
| if [[ "${stage}" == "up" ]]; then |
| up_args+=("$1") |
| else |
| reset_dirs+=("$1") |
| fi |
| shift |
| done |
| |
| render_uid_template "${template_file}" "${compose_file}" |
| register_stack_metadata "${component}" "${compose_file}" "${env_file}" |
| compose_down_stack "${compose_file}" "${env_file}" --remove-orphans |
| |
| if [[ "${STOP}" -eq 1 ]]; then |
| return 0 |
| fi |
| |
| if (( ${#reset_dirs[@]} > 0 )); then |
| reset_data_dirs "${reset_dirs[@]}" |
| fi |
| |
| if (( ${#up_args[@]} == 0 )); then |
| up_args=(-d --wait) |
| fi |
| |
| compose_up_stack "${compose_file}" "${env_file}" "${up_args[@]}" |
| } |
| |
| register_job() { |
| local component="$1" |
| local pid="$2" |
| local log_file="$3" |
| |
| START_PIDS["${component}"]="${pid}" |
| START_LOGS["${component}"]="${log_file}" |
| START_DONE["${component}"]=0 |
| START_ORDER+=("${component}") |
| } |
| |
| cleanup_started_stacks() { |
| local component |
| local compose_file |
| local env_file |
| local i |
| |
| [[ "${START_CLEANUP_ON_FAILURE}" -eq 1 ]] || return 0 |
| |
| for ((i = ${#START_ORDER[@]} - 1; i >= 0; --i)); do |
| component="${START_ORDER[$i]}" |
| compose_file="${START_COMPOSE_FILES["${component}"]:-}" |
| env_file="${START_ENV_FILES["${component}"]:-}" |
| [[ -n "${compose_file}" ]] || continue |
| echo "Cleaning component '${component}' after startup failure" >&2 |
| compose_down_stack "${compose_file}" "${env_file}" --remove-orphans >/dev/null 2>&1 || true |
| done |
| } |
| |
| wait_remaining_jobs_quietly() { |
| local component |
| local pid |
| |
| for component in "${START_ORDER[@]}"; do |
| [[ "${START_DONE["${component}"]:-0}" -eq 0 ]] || continue |
| pid="${START_PIDS["${component}"]:-}" |
| [[ -n "${pid}" ]] || continue |
| wait "${pid}" >/dev/null 2>&1 || true |
| START_DONE["${component}"]=1 |
| done |
| } |
| |
| handle_start_failure() { |
| local component="$1" |
| local status="$2" |
| |
| dump_start_failure "${component}" "${status}" |
| kill_running_jobs |
| wait_remaining_jobs_quietly |
| cleanup_started_stacks |
| } |
| |
| collect_one_finished_job() { |
| local component |
| local pid |
| local status |
| |
| for component in "${START_ORDER[@]}"; do |
| [[ "${START_DONE["${component}"]:-0}" -eq 0 ]] || continue |
| pid="${START_PIDS["${component}"]:-}" |
| [[ -n "${pid}" ]] || continue |
| if kill -0 "${pid}" >/dev/null 2>&1; then |
| continue |
| fi |
| |
| status=0 |
| wait "${pid}" || status=$? |
| START_DONE["${component}"]=1 |
| if [[ "${status}" -ne 0 ]]; then |
| handle_start_failure "${component}" "${status}" |
| return 1 |
| fi |
| return 0 |
| done |
| |
| return 2 |
| } |
| |
| launch_component() { |
| local component="$1" |
| local log_file="$2" |
| shift 2 |
| |
| echo "Launching ${component}, log => ${log_file}" |
| "$@" >"${log_file}" 2>&1 & |
| register_job "${component}" "$!" "${log_file}" |
| } |
| |
| kill_running_jobs() { |
| local component |
| local pid |
| |
| for component in "${START_ORDER[@]}"; do |
| [[ "${START_DONE["${component}"]:-0}" -eq 0 ]] || continue |
| pid="${START_PIDS["${component}"]:-}" |
| [[ -n "${pid}" ]] || continue |
| kill "${pid}" >/dev/null 2>&1 || true |
| done |
| } |
| |
| print_wait_progress() { |
| local component |
| local pid |
| local log_file |
| |
| echo "Still waiting for docker components:" |
| for component in "${START_ORDER[@]}"; do |
| [[ "${START_DONE["${component}"]:-0}" -eq 0 ]] || continue |
| pid="${START_PIDS["${component}"]:-}" |
| [[ -n "${pid}" ]] || continue |
| if ! kill -0 "${pid}" >/dev/null 2>&1; then |
| continue |
| fi |
| |
| log_file="${START_LOGS["${component}"]:-}" |
| echo " ${component} (pid=${pid}, log=${log_file})" |
| if [[ -n "${log_file}" && -f "${log_file}" ]]; then |
| echo " ----- ${component} log tail -----" |
| tail -n 20 "${log_file}" || true |
| echo " ----- end ${component} log tail -----" |
| fi |
| done |
| } |
| |
| dump_start_failure() { |
| local component="$1" |
| local status="$2" |
| local log_file="${START_LOGS["${component}"]}" |
| local compose_file="${START_COMPOSE_FILES["${component}"]:-}" |
| local env_file="${START_ENV_FILES["${component}"]:-}" |
| |
| echo "ERROR: docker component '${component}' failed with exit code ${status}" >&2 |
| echo "ERROR: start log file: ${log_file}" >&2 |
| echo "===== ${component} start log (tail -200) =====" >&2 |
| tail -n 200 "${log_file}" >&2 || true |
| |
| if [[ -n "${compose_file}" ]]; then |
| echo "===== ${component} docker compose ps =====" >&2 |
| compose_cmd "${compose_file}" "${env_file}" ps >&2 || true |
| echo "===== ${component} docker compose logs (tail -200) =====" >&2 |
| compose_cmd "${compose_file}" "${env_file}" logs --no-color --tail 200 >&2 || true |
| fi |
| |
| echo "===== unhealthy containers =====" >&2 |
| sudo docker ps -a --filter 'health=unhealthy' --format '{{.Names}} | {{.Image}} | {{.Status}}' >&2 || true |
| } |
| |
| print_started_summary() { |
| local component |
| local compose_file |
| local env_file |
| local compose_ids |
| local container_id |
| |
| echo "===== started components summary =====" |
| for component in "${START_ORDER[@]}"; do |
| compose_file="${START_COMPOSE_FILES["${component}"]:-}" |
| env_file="${START_ENV_FILES["${component}"]:-}" |
| |
| echo "component: ${component}" |
| echo " log: ${START_LOGS["${component}"]}" |
| echo " compose: ${compose_file}" |
| if [[ -n "${env_file}" ]]; then |
| echo " env: ${env_file}" |
| fi |
| echo " compose ps:" |
| compose_cmd "${compose_file}" "${env_file}" ps 2>/dev/null || true |
| |
| compose_ids="$(compose_cmd "${compose_file}" "${env_file}" ps -q 2>/dev/null || true)" |
| if [[ -n "${compose_ids}" ]]; then |
| echo " containers:" |
| while read -r container_id; do |
| [[ -n "${container_id}" ]] || continue |
| sudo docker inspect --format '{{.Name}} | {{.Config.Image}} | {{.State.Status}} | health={{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "${container_id}" \ |
| 2>/dev/null || true |
| done <<<"${compose_ids}" |
| fi |
| done |
| } |
| |
| wait_for_started_jobs() { |
| local component |
| local remaining_count |
| local collect_status |
| local last_progress_ts |
| local now_ts |
| |
| last_progress_ts="$(date +%s)" |
| |
| while true; do |
| remaining_count=0 |
| for component in "${START_ORDER[@]}"; do |
| if [[ "${START_DONE["${component}"]:-0}" -eq 0 ]]; then |
| remaining_count=$((remaining_count + 1)) |
| fi |
| done |
| |
| if (( remaining_count == 0 )); then |
| return 0 |
| fi |
| |
| collect_status=0 |
| collect_one_finished_job || collect_status=$? |
| if [[ "${collect_status}" -eq 1 ]]; then |
| return 1 |
| fi |
| if [[ "${collect_status}" -eq 2 ]]; then |
| now_ts="$(date +%s)" |
| if (( now_ts - last_progress_ts >= START_PROGRESS_INTERVAL )); then |
| print_wait_progress |
| last_progress_ts="${now_ts}" |
| fi |
| sleep 1 |
| fi |
| done |
| } |
| |
| start_es() { |
| # elasticsearch |
| render_uid_template "${ROOT}/docker-compose/elasticsearch/es.yaml.tpl" "${ROOT}/docker-compose/elasticsearch/es.yaml" |
| register_stack_metadata "es" "${ROOT}/docker-compose/elasticsearch/es.yaml" "${ROOT}/docker-compose/elasticsearch/es.env" |
| compose_down_stack "${ROOT}/docker-compose/elasticsearch/es.yaml" "${ROOT}/docker-compose/elasticsearch/es.env" --remove-orphans |
| if [[ "${STOP}" -ne 1 ]]; then |
| sudo mkdir -p "${ROOT}"/docker-compose/elasticsearch/data/es6/ |
| sudo rm -rf "${ROOT}"/docker-compose/elasticsearch/data/es6/* |
| sudo mkdir -p "${ROOT}"/docker-compose/elasticsearch/data/es7/ |
| sudo rm -rf "${ROOT}"/docker-compose/elasticsearch/data/es7/* |
| sudo mkdir -p "${ROOT}"/docker-compose/elasticsearch/data/es8/ |
| sudo rm -rf "${ROOT}"/docker-compose/elasticsearch/data/es8/* |
| sudo chmod -R 777 "${ROOT}"/docker-compose/elasticsearch/data |
| sudo mkdir -p "${ROOT}"/docker-compose/elasticsearch/logs/es6/ |
| sudo rm -rf "${ROOT}"/docker-compose/elasticsearch/logs/es6/* |
| sudo mkdir -p "${ROOT}"/docker-compose/elasticsearch/logs/es7/ |
| sudo rm -rf "${ROOT}"/docker-compose/elasticsearch/logs/es7/* |
| sudo mkdir -p "${ROOT}"/docker-compose/elasticsearch/logs/es8/ |
| sudo rm -rf "${ROOT}"/docker-compose/elasticsearch/logs/es8/* |
| sudo chmod -R 777 "${ROOT}"/docker-compose/elasticsearch/logs |
| sudo chmod -R 777 "${ROOT}"/docker-compose/elasticsearch/config |
| compose_cmd "${ROOT}/docker-compose/elasticsearch/es.yaml" "${ROOT}/docker-compose/elasticsearch/es.env" up -d --remove-orphans |
| fi |
| } |
| |
| start_mysql() { |
| # mysql 5.7 |
| start_rendered_compose_stack "mysql" \ |
| "${ROOT}/docker-compose/mysql/mysql-5.7.yaml.tpl" \ |
| "${ROOT}/docker-compose/mysql/mysql-5.7.yaml" \ |
| "${ROOT}/docker-compose/mysql/mysql-5.7.env" \ |
| -d --wait -- \ |
| "${ROOT}/docker-compose/mysql/data" |
| } |
| |
| start_pg() { |
| # pg 14 |
| start_rendered_compose_stack "pg" \ |
| "${ROOT}/docker-compose/postgresql/postgresql-14.yaml.tpl" \ |
| "${ROOT}/docker-compose/postgresql/postgresql-14.yaml" \ |
| "${ROOT}/docker-compose/postgresql/postgresql-14.env" \ |
| -d --wait -- \ |
| "${ROOT}/docker-compose/postgresql/data/data" |
| } |
| |
| start_oracle() { |
| # oracle |
| start_rendered_compose_stack "oracle" \ |
| "${ROOT}/docker-compose/oracle/oracle-11.yaml.tpl" \ |
| "${ROOT}/docker-compose/oracle/oracle-11.yaml" \ |
| "${ROOT}/docker-compose/oracle/oracle-11.env" \ |
| -d --wait -- \ |
| "${ROOT}/docker-compose/oracle/data" |
| } |
| |
| start_db2() { |
| # db2 |
| start_rendered_compose_stack "db2" \ |
| "${ROOT}/docker-compose/db2/db2.yaml.tpl" \ |
| "${ROOT}/docker-compose/db2/db2.yaml" \ |
| "${ROOT}/docker-compose/db2/db2.env" \ |
| -d --wait -- \ |
| "${ROOT}/docker-compose/db2/data" |
| } |
| |
| start_oceanbase() { |
| # oceanbase |
| start_rendered_compose_stack "oceanbase" \ |
| "${ROOT}/docker-compose/oceanbase/oceanbase.yaml.tpl" \ |
| "${ROOT}/docker-compose/oceanbase/oceanbase.yaml" \ |
| "${ROOT}/docker-compose/oceanbase/oceanbase.env" \ |
| -d --wait -- \ |
| "${ROOT}/docker-compose/oceanbase/data" |
| } |
| |
| start_sqlserver() { |
| # sqlserver |
| start_rendered_compose_stack "sqlserver" \ |
| "${ROOT}/docker-compose/sqlserver/sqlserver.yaml.tpl" \ |
| "${ROOT}/docker-compose/sqlserver/sqlserver.yaml" \ |
| "${ROOT}/docker-compose/sqlserver/sqlserver.env" \ |
| -d --wait -- \ |
| "${ROOT}/docker-compose/sqlserver/data" |
| } |
| |
| start_clickhouse() { |
| # clickhouse |
| start_rendered_compose_stack "clickhouse" \ |
| "${ROOT}/docker-compose/clickhouse/clickhouse.yaml.tpl" \ |
| "${ROOT}/docker-compose/clickhouse/clickhouse.yaml" \ |
| "${ROOT}/docker-compose/clickhouse/clickhouse.env" \ |
| -d --wait -- \ |
| "${ROOT}/docker-compose/clickhouse/data" |
| } |
| |
| start_kafka() { |
| # kafka |
| KAFKA_CONTAINER_ID="${CONTAINER_UID}kafka" |
| render_uid_template "${ROOT}/docker-compose/kafka/kafka.yaml.tpl" "${ROOT}/docker-compose/kafka/kafka.yaml" |
| sed -i "s/localhost/${IP_HOST}/g" "${ROOT}/docker-compose/kafka/kafka.yaml" |
| register_stack_metadata "kafka" "${ROOT}/docker-compose/kafka/kafka.yaml" "${ROOT}/docker-compose/kafka/kafka.env" |
| compose_down_stack "${ROOT}/docker-compose/kafka/kafka.yaml" "${ROOT}/docker-compose/kafka/kafka.env" --remove-orphans |
| |
| create_kafka_topics() { |
| local container_id="$1" |
| local ip_host="$2" |
| local -a topics=("basic_data" "basic_array_data" "basic_data_with_errors" "basic_array_data_with_errors" "basic_data_timezone" "basic_array_data_timezone" "trino_kafka_basic_data") |
| local topic |
| |
| for topic in "${topics[@]}"; do |
| echo "Creating kafka topic '${topic}' for ${container_id}" |
| sudo docker exec "${container_id}" bash -c "/opt/bitnami/kafka/bin/kafka-topics.sh --create --bootstrap-server '${ip_host}:19193' --topic '${topic}'" |
| done |
| |
| } |
| |
| wait_for_kafka_ready() { |
| local container_id="$1" |
| local ip_host="$2" |
| local attempt |
| |
| for attempt in {1..30}; do |
| if sudo docker exec "${container_id}" bash -c "/opt/bitnami/kafka/bin/kafka-topics.sh --list --bootstrap-server '${ip_host}:19193'" >/dev/null 2>&1; then |
| return 0 |
| fi |
| sleep 2 |
| done |
| |
| echo "ERROR: kafka container '${container_id}' did not become ready on ${ip_host}:19193" >&2 |
| return 1 |
| } |
| |
| if [[ "${STOP}" -ne 1 ]]; then |
| compose_up_stack "${ROOT}/docker-compose/kafka/kafka.yaml" "${ROOT}/docker-compose/kafka/kafka.env" --build --remove-orphans -d |
| wait_for_kafka_ready "${KAFKA_CONTAINER_ID}" "${IP_HOST}" |
| create_kafka_topics "${KAFKA_CONTAINER_ID}" "${IP_HOST}" |
| fi |
| } |
| |
| start_hive2() { |
| start_hive_stack "hive2" |
| } |
| |
| start_hive3() { |
| start_hive_stack "hive3" |
| } |
| |
| hive_volume_prefix_for() { |
| local hive_version="$1" |
| echo "${HIVE_SHARED_ID}-${hive_version}" |
| } |
| |
| HIVE_VOLUME_SUFFIXES=(namenode datanode pgdata state) |
| |
| log_hive_volumes() { |
| local hive_version="$1" |
| local prefix="$2" |
| echo "[${hive_version}] volume_prefix=${prefix} volumes=$(IFS=,; echo "${HIVE_VOLUME_SUFFIXES[*]}")" |
| } |
| |
| ensure_hive_volumes() { |
| local prefix="$1" |
| local suffix |
| for suffix in "${HIVE_VOLUME_SUFFIXES[@]}"; do |
| if ! sudo docker volume inspect "${prefix}-${suffix}" >/dev/null 2>&1; then |
| sudo docker volume create "${prefix}-${suffix}" >/dev/null |
| fi |
| done |
| } |
| |
| reset_hive_volumes() { |
| local prefix="$1" |
| local suffix |
| for suffix in "${HIVE_VOLUME_SUFFIXES[@]}"; do |
| sudo docker volume rm -f "${prefix}-${suffix}" >/dev/null 2>&1 || true |
| done |
| } |
| |
| hive_volume_is_populated() { |
| local prefix="$1" |
| sudo docker run --rm \ |
| -v "${prefix}-namenode:/vol:ro" \ |
| alpine test -f /vol/current/VERSION 2>/dev/null |
| } |
| |
| maybe_restore_baseline_to_volumes() { |
| local prefix="$1" |
| local hive_version="${2:-hive3}" |
| local baseline_cache="${HIVE_BASELINE_TARBALL_CACHE}" |
| local cache_file="${baseline_cache}/${hive_version}-baseline-${HIVE_BASELINE_VERSION}.tar.gz" |
| local extracted_dir="${baseline_cache}/${hive_version}-baseline-${HIVE_BASELINE_VERSION}" |
| local extracted_ready_file="${extracted_dir}/.extract.ready" |
| local remote_path="hive_baseline/${hive_version}-baseline-${HIVE_BASELINE_VERSION}.tar.gz" |
| local download_url="" |
| local tmp_cache_file="" |
| local tmp_extract_dir="" |
| |
| HIVE_BASELINE_RESTORE_RESULT="missing" |
| |
| if [[ -n "${s3BucketName:-}" && -n "${s3Endpoint:-}" ]]; then |
| download_url="https://${s3BucketName}.${s3Endpoint}/regression/datalake/pipeline_data/${remote_path}" |
| fi |
| |
| # Nothing to do if the named volumes already hold a populated baseline. |
| if hive_volume_is_populated "${prefix}"; then |
| echo "[baseline] volumes already populated, skip restore" |
| HIVE_BASELINE_RESTORE_RESULT="existing" |
| return 0 |
| fi |
| |
| # Ensure a local tarball is available: prefer an intact cache, otherwise |
| # download to a temporary file and atomically replace the cache. This avoids |
| # persisting truncated tarballs when curl is interrupted on CI hosts. |
| if [[ -f "${cache_file}" ]]; then |
| if tar -tzf "${cache_file}" >/dev/null 2>&1; then |
| echo "[baseline] using cached tarball: ${cache_file}" |
| else |
| echo "[baseline] cached tarball is corrupt, removing: ${cache_file}" |
| rm -f "${cache_file}" |
| fi |
| fi |
| |
| if [[ ! -f "${cache_file}" ]]; then |
| if [[ -z "${download_url}" ]]; then |
| echo "[baseline] no baseline tarball available, will do full init" |
| return 0 |
| fi |
| mkdir -p "${baseline_cache}" |
| tmp_cache_file="$(mktemp "${cache_file}.tmp.XXXXXX")" |
| echo "[baseline] downloading baseline from ${download_url}" |
| if ! curl -fSL -o "${tmp_cache_file}" "${download_url}"; then |
| rm -f "${tmp_cache_file}" |
| return 1 |
| fi |
| if ! tar -tzf "${tmp_cache_file}" >/dev/null 2>&1; then |
| echo "[baseline] downloaded tarball is corrupt: ${download_url}" >&2 |
| rm -f "${tmp_cache_file}" |
| return 1 |
| fi |
| mv -f "${tmp_cache_file}" "${cache_file}" |
| fi |
| |
| # Cache the extracted baseline tree on disk so repeated refresh runs can |
| # restore directly from files instead of paying the tar.gz decompression |
| # cost every time. |
| if [[ -f "${extracted_ready_file}" ]] \ |
| && [[ -d "${extracted_dir}/namenode" ]] \ |
| && [[ -d "${extracted_dir}/datanode" ]] \ |
| && [[ -d "${extracted_dir}/pgdata" ]] \ |
| && [[ -d "${extracted_dir}/state" ]]; then |
| echo "[baseline] using cached extracted baseline: ${extracted_dir}" |
| else |
| if [[ -d "${extracted_dir}" ]]; then |
| echo "[baseline] extracted baseline cache is incomplete, removing: ${extracted_dir}" |
| rm -rf "${extracted_dir}" |
| fi |
| mkdir -p "${baseline_cache}" |
| tmp_extract_dir="$(mktemp -d "${extracted_dir}.tmp.XXXXXX")" |
| echo "[baseline] extracting baseline tarball to cache dir: ${extracted_dir}" |
| if ! tar -xzf "${cache_file}" -C "${tmp_extract_dir}"; then |
| rm -rf "${tmp_extract_dir}" |
| return 1 |
| fi |
| if [[ ! -d "${tmp_extract_dir}/namenode" ]] \ |
| || [[ ! -d "${tmp_extract_dir}/datanode" ]] \ |
| || [[ ! -d "${tmp_extract_dir}/pgdata" ]] \ |
| || [[ ! -d "${tmp_extract_dir}/state" ]]; then |
| echo "[baseline] extracted baseline cache is incomplete: ${cache_file}" >&2 |
| rm -rf "${tmp_extract_dir}" |
| return 1 |
| fi |
| touch "${tmp_extract_dir}/.extract.ready" |
| mv "${tmp_extract_dir}" "${extracted_dir}" |
| fi |
| |
| # Restore into all 4 volumes in a single alpine container so data streams |
| # directly from the extracted cache tree into the volume mounts. |
| echo "[baseline] restoring volumes from extracted baseline cache..." |
| local _t0 |
| _t0=$(date +%s) |
| sudo docker run --rm \ |
| -v "${extracted_dir}:/baseline:ro" \ |
| -v "${prefix}-namenode:/restore/namenode" \ |
| -v "${prefix}-datanode:/restore/datanode" \ |
| -v "${prefix}-pgdata:/restore/pgdata" \ |
| -v "${prefix}-state:/restore/state" \ |
| alpine sh -c 'cd /baseline && tar cf - namenode datanode pgdata state | tar xf - -C /restore' |
| HIVE_BASELINE_RESTORE_RESULT="restored" |
| echo "[baseline] restore done took=$(( $(date +%s) - _t0 ))s" |
| } |
| |
| hive_compose_file_for() { |
| local hive_version="$1" |
| echo "${ROOT}/docker-compose/hive/hive-${hive_version#hive}x.yaml" |
| } |
| |
| hive_compose_template_for() { |
| local hive_version="$1" |
| echo "${ROOT}/docker-compose/hive/hive-${hive_version#hive}x.yaml.tpl" |
| } |
| |
| hive_env_file_for() { |
| local hive_version="$1" |
| echo "${ROOT}/docker-compose/hive/hadoop-hive-${hive_version#hive}x.env" |
| } |
| |
| hive_env_template_for() { |
| local hive_version="$1" |
| echo "${ROOT}/docker-compose/hive/hadoop-hive-${hive_version#hive}x.env.tpl" |
| } |
| |
| hive_settings_env_for() { |
| local hive_version="$1" |
| echo "${ROOT}/docker-compose/hive/hive-${hive_version#hive}x_settings.env" |
| } |
| |
| hive_metastore_container_for() { |
| local hive_version="$1" |
| echo "${hive_version}-metastore" |
| } |
| |
| ensure_hosts_alias() { |
| local alias_name="$1" |
| local alias_ip="$2" |
| local tmp_hosts |
| local sudo_cmd=() |
| |
| if [[ "$(id -u)" -ne 0 ]]; then |
| sudo_cmd=(sudo) |
| fi |
| |
| tmp_hosts="$(mktemp)" |
| "${sudo_cmd[@]}" chmod a+w /etc/hosts |
| awk -v alias_name="${alias_name}" ' |
| { |
| keep = 1 |
| for (i = 2; i <= NF; ++i) { |
| if ($i == alias_name) { |
| keep = 0 |
| break |
| } |
| } |
| if (keep) { |
| print |
| } |
| } |
| ' /etc/hosts >"${tmp_hosts}" |
| printf "%s %s\n" "${alias_ip}" "${alias_name}" >>"${tmp_hosts}" |
| "${sudo_cmd[@]}" cp "${tmp_hosts}" /etc/hosts |
| rm -f "${tmp_hosts}" |
| } |
| |
| render_hive_compose() { |
| local hive_version="$1" |
| local compose_tpl |
| local compose_file |
| local env_file |
| local env_tpl |
| |
| compose_tpl="$(hive_compose_template_for "${hive_version}")" |
| compose_file="$(hive_compose_file_for "${hive_version}")" |
| env_file="$(hive_env_file_for "${hive_version}")" |
| env_tpl="$(hive_env_template_for "${hive_version}")" |
| |
| envsubst <"${compose_tpl}" >"${compose_file}" |
| envsubst <"${ROOT}/docker-compose/hive/hadoop-hive.env.tpl" >"${env_file}" |
| envsubst <"${env_tpl}" >>"${env_file}" |
| } |
| |
| hive_compose_cmd() { |
| local hive_version="$1" |
| sudo docker compose -p "${CONTAINER_UID}${hive_version}" -f "$(hive_compose_file_for "${hive_version}")" --env-file "$(hive_env_file_for "${hive_version}")" "${@:2}" |
| } |
| |
| exec_hive_script() { |
| local hive_version="$1" |
| local script_name="$2" |
| local metastore_container |
| |
| metastore_container="$(hive_metastore_container_for "${hive_version}")" |
| # -i: forward SIGINT/SIGTERM into container so Ctrl+C kills the in-container script |
| # instead of leaving an orphan that keeps mutating state. |
| # stdbuf -oL -eL: line-buffer output so progress reaches the host log in real time. |
| sudo docker exec -i \ |
| -e HIVE_BOOTSTRAP_GROUPS="${HIVE_BOOTSTRAP_GROUPS}" \ |
| -e LOAD_PARALLEL="${LOAD_PARALLEL}" \ |
| -e HIVE_HQL_PARALLEL="${HIVE_HQL_PARALLEL}" \ |
| -e HIVE_MODULES="${HIVE_MODULES}" \ |
| -e HIVE_BASELINE_VERSION="${HIVE_BASELINE_VERSION}" \ |
| -e HIVE_STATE_DIR="/mnt/state" \ |
| -e HS_PORT="${HS_PORT}" \ |
| -e DORIS_HS2_URL="jdbc:hive2://localhost:${HS_PORT}/default" \ |
| -e HIVE_DEBUG="${HIVE_DEBUG:-0}" \ |
| "${metastore_container}" \ |
| stdbuf -oL -eL bash --noprofile --norc "/mnt/scripts/${script_name}" |
| } |
| |
| maybe_refresh_hive_data() { |
| local hive_version="$1" |
| local baseline_restore_result="${2:-missing}" |
| |
| if [[ "${NEED_LOAD_DATA}" -eq 0 ]]; then |
| echo "Skip Hive data refresh because --no-load-data is set" |
| return 0 |
| fi |
| |
| if [[ "${HIVE_MODE}" == "rebuild" || "${baseline_restore_result}" == "missing" ]]; then |
| local _t_baseline |
| _t_baseline=$(date +%s) |
| echo "[$(date '+%H:%M:%S')] [${hive_version}] init-hive-baseline begin" |
| exec_hive_script "${hive_version}" init-hive-baseline.sh |
| echo "[$(date '+%H:%M:%S')] [${hive_version}] init-hive-baseline done took=$(( $(date +%s) - _t_baseline ))s" |
| fi |
| |
| if [[ "${HIVE_MODE}" == "refresh" || "${HIVE_MODE}" == "rebuild" ]]; then |
| local _t_modules |
| _t_modules=$(date +%s) |
| echo "[$(date '+%H:%M:%S')] [${hive_version}] refresh-hive-modules begin (mode=${HIVE_MODE} modules=${HIVE_MODULES})" |
| exec_hive_script "${hive_version}" refresh-hive-modules.sh |
| echo "[$(date '+%H:%M:%S')] [${hive_version}] refresh-hive-modules done took=$(( $(date +%s) - _t_modules ))s" |
| fi |
| } |
| |
| start_hive_stack() { |
| local hive_version="$1" |
| local volume_prefix |
| local baseline_restore_result="missing" |
| |
| export HIVE_BOOTSTRAP_GROUPS="$(hive_bootstrap_groups_for "${hive_version}")" |
| echo "${hive_version} selected bootstrap files: ${HIVE_BOOTSTRAP_GROUPS}" |
| |
| . "$(hive_settings_env_for "${hive_version}")" |
| volume_prefix="$(hive_volume_prefix_for "${hive_version}")" |
| export HIVE_VOLUME_PREFIX="${volume_prefix}" |
| log_hive_volumes "${hive_version}" "${volume_prefix}" |
| |
| # Keep a stable hostname in metastore/HDFS metadata while allowing the |
| # backing host IP to change across restarts. |
| ensure_hosts_alias "${HIVE_HOST_ALIAS}" "${IP_HOST}" |
| |
| if [[ "${STOP}" -eq 1 ]]; then |
| render_hive_compose "${hive_version}" |
| hive_compose_cmd "${hive_version}" down |
| return 0 |
| fi |
| |
| # refresh/rebuild: tear down the stack and clear volumes first. |
| # fast: keep existing volumes and only restore the baseline when they are empty. |
| if [[ "${HIVE_MODE}" == "rebuild" || "${HIVE_MODE}" == "refresh" ]]; then |
| render_hive_compose "${hive_version}" |
| hive_compose_cmd "${hive_version}" down || true |
| reset_hive_volumes "${volume_prefix}" |
| fi |
| |
| ensure_hive_volumes "${volume_prefix}" |
| if [[ "${HIVE_MODE}" != "rebuild" ]]; then |
| maybe_restore_baseline_to_volumes "${volume_prefix}" "${hive_version}" |
| baseline_restore_result="${HIVE_BASELINE_RESTORE_RESULT}" |
| fi |
| if [[ "${HIVE_MODE}" == "fast" && "${baseline_restore_result}" == "missing" ]]; then |
| echo "[baseline] ERROR: fast mode requires existing populated volumes or an available baseline tarball" >&2 |
| return 1 |
| fi |
| render_hive_compose "${hive_version}" |
| |
| # fast mode is the only mode that reuses the current stack in place. |
| if [[ "${HIVE_MODE}" == "fast" ]] && docker_hive_stack_healthy "${CONTAINER_UID}" "${hive_version}"; then |
| echo "${hive_version} stack is already healthy, fast mode skips compose up" |
| else |
| local _t_up |
| _t_up=$(date +%s) |
| hive_compose_cmd "${hive_version}" up --build --remove-orphans -d --wait |
| echo "[$(date '+%H:%M:%S')] [${hive_version}] compose up done took=$(( $(date +%s) - _t_up ))s" |
| fi |
| |
| local _t_data |
| _t_data=$(date +%s) |
| maybe_refresh_hive_data "${hive_version}" "${baseline_restore_result}" |
| echo "[$(date '+%H:%M:%S')] [${hive_version}] data refresh done took=$(( $(date +%s) - _t_data ))s" |
| } |
| |
| start_iceberg() { |
| # iceberg |
| ICEBERG_DIR=${ROOT}/docker-compose/iceberg |
| render_uid_template "${ROOT}/docker-compose/iceberg/iceberg.yaml.tpl" "${ROOT}/docker-compose/iceberg/iceberg.yaml" |
| render_uid_template "${ROOT}/docker-compose/iceberg/entrypoint.sh.tpl" "${ROOT}/docker-compose/iceberg/entrypoint.sh" |
| cp "${ROOT}/docker-compose/iceberg/entrypoint.sh" "${ROOT}/docker-compose/iceberg/scripts/entrypoint.sh" |
| register_stack_metadata "iceberg" "${ROOT}/docker-compose/iceberg/iceberg.yaml" "${ROOT}/docker-compose/iceberg/iceberg.env" |
| compose_down_stack "${ROOT}/docker-compose/iceberg/iceberg.yaml" "${ROOT}/docker-compose/iceberg/iceberg.env" --remove-orphans |
| if [[ "${STOP}" -ne 1 ]]; then |
| if [[ ! -d "${ICEBERG_DIR}/data" ]]; then |
| echo "${ICEBERG_DIR}/data does not exist" |
| ( |
| cd "${ICEBERG_DIR}" || exit 1 |
| rm -f iceberg_data*.zip |
| wget -P "${ROOT}/docker-compose/iceberg" "https://${s3BucketName}.${s3Endpoint}/regression/datalake/pipeline_data/iceberg_data_spark40.zip" |
| sudo unzip iceberg_data_spark40.zip |
| sudo mv iceberg_data data |
| sudo rm -rf iceberg_data_spark40.zip |
| ) |
| else |
| echo "${ICEBERG_DIR}/data exist, continue !" |
| fi |
| |
| compose_up_stack "${ROOT}/docker-compose/iceberg/iceberg.yaml" "${ROOT}/docker-compose/iceberg/iceberg.env" -d --wait |
| fi |
| } |
| |
| start_hudi() { |
| HUDI_DIR=${ROOT}/docker-compose/hudi |
| export CONTAINER_UID=${CONTAINER_UID} |
| export HUDI_BUNDLE_URL="${HUDI_BUNDLE_URL:-${MAVEN_REPOSITORY_URL}/org/apache/hudi/hudi-spark3.5-bundle_2.12/1.0.2/hudi-spark3.5-bundle_2.12-1.0.2.jar}" |
| export HADOOP_AWS_URL="${HADOOP_AWS_URL:-${MAVEN_REPOSITORY_URL}/org/apache/hadoop/hadoop-aws/3.3.4/hadoop-aws-3.3.4.jar}" |
| export AWS_SDK_BUNDLE_URL="${AWS_SDK_BUNDLE_URL:-${MAVEN_REPOSITORY_URL}/com/amazonaws/aws-java-sdk-bundle/1.12.262/aws-java-sdk-bundle-1.12.262.jar}" |
| export POSTGRESQL_JDBC_URL="${POSTGRESQL_JDBC_URL:-${MAVEN_REPOSITORY_URL}/org/postgresql/postgresql/42.7.1/postgresql-42.7.1.jar}" |
| envsubst <"${HUDI_DIR}"/hudi.env.tpl >"${HUDI_DIR}"/hudi.env |
| set -a |
| . "${HUDI_DIR}"/hudi.env |
| set +a |
| envsubst <"${HUDI_DIR}"/hudi.yaml.tpl >"${HUDI_DIR}"/hudi.yaml |
| sudo chmod +x "${HUDI_DIR}"/scripts/init.sh |
| register_stack_metadata "hudi" "${HUDI_DIR}/hudi.yaml" "${HUDI_DIR}/hudi.env" |
| compose_down_stack "${HUDI_DIR}/hudi.yaml" "${HUDI_DIR}/hudi.env" --remove-orphans |
| if [[ "${STOP}" -ne 1 ]]; then |
| compose_up_stack "${HUDI_DIR}/hudi.yaml" "${HUDI_DIR}/hudi.env" -d --wait |
| fi |
| } |
| |
| start_mariadb() { |
| # mariadb |
| start_rendered_compose_stack "mariadb" \ |
| "${ROOT}/docker-compose/mariadb/mariadb-10.yaml.tpl" \ |
| "${ROOT}/docker-compose/mariadb/mariadb-10.yaml" \ |
| "${ROOT}/docker-compose/mariadb/mariadb-10.env" \ |
| -d --wait -- \ |
| "${ROOT}/docker-compose/mariadb/data" |
| } |
| |
| start_lakesoul() { |
| echo "RUN_LAKESOUL" |
| cp "${ROOT}"/docker-compose/lakesoul/lakesoul.yaml.tpl "${ROOT}"/docker-compose/lakesoul/lakesoul.yaml |
| sed -i "s/doris--/${CONTAINER_UID}/g" "${ROOT}"/docker-compose/lakesoul/lakesoul.yaml |
| register_stack_metadata "lakesoul" "${ROOT}/docker-compose/lakesoul/lakesoul.yaml" "" |
| compose_cmd "${ROOT}/docker-compose/lakesoul/lakesoul.yaml" "" down --remove-orphans |
| sudo rm -rf "${ROOT}"/docker-compose/lakesoul/data |
| if [[ "${STOP}" -ne 1 ]]; then |
| echo "PREPARE_LAKESOUL_DATA" |
| compose_cmd "${ROOT}/docker-compose/lakesoul/lakesoul.yaml" "" up -d |
| ## import tpch data into lakesoul |
| ## install rustup |
| curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y |
| # shellcheck source=/dev/null |
| . "${HOME}/.cargo/env" |
| ## install rust nightly-2023-05-20 |
| rustup install nightly-2023-05-20 |
| ## download&generate tpch data |
| mkdir -p lakesoul/test_files/tpch/data |
| git clone https://github.com/databricks/tpch-dbgen.git |
| ( |
| cd tpch-dbgen |
| make |
| ./dbgen -f -s 0.1 |
| mv *.tbl ../lakesoul/test_files/tpch/data |
| ) |
| export TPCH_DATA=$(realpath lakesoul/test_files/tpch/data) |
| ## import tpch data |
| git clone https://github.com/lakesoul-io/LakeSoul.git |
| # git checkout doris_dev |
| ( |
| cd LakeSoul/rust |
| cargo test load_tpch_data --package lakesoul-datafusion --features=ci -- --nocapture |
| ) |
| fi |
| } |
| |
| start_kerberos() { |
| echo "RUN_KERBEROS" |
| export CONTAINER_UID=${CONTAINER_UID} |
| envsubst <"${ROOT}"/docker-compose/kerberos/kerberos.yaml.tpl >"${ROOT}"/docker-compose/kerberos/kerberos.yaml |
| sed -i "s/s3Endpoint/${s3Endpoint}/g" "${ROOT}"/docker-compose/kerberos/entrypoint-hive-master.sh |
| sed -i "s/s3BucketName/${s3BucketName}/g" "${ROOT}"/docker-compose/kerberos/entrypoint-hive-master.sh |
| for i in {1..2}; do |
| . "${ROOT}"/docker-compose/kerberos/kerberos${i}_settings.env |
| envsubst <"${ROOT}"/docker-compose/kerberos/hadoop-hive.env.tpl >"${ROOT}"/docker-compose/kerberos/hadoop-hive-${i}.env |
| envsubst <"${ROOT}"/docker-compose/kerberos/conf/my.cnf.tpl > "${ROOT}"/docker-compose/kerberos/conf/kerberos${i}/my.cnf |
| envsubst <"${ROOT}"/docker-compose/kerberos/conf/kerberos${i}/kdc.conf.tpl > "${ROOT}"/docker-compose/kerberos/conf/kerberos${i}/kdc.conf |
| envsubst <"${ROOT}"/docker-compose/kerberos/conf/kerberos${i}/krb5.conf.tpl > "${ROOT}"/docker-compose/kerberos/conf/kerberos${i}/krb5.conf |
| done |
| sudo chmod a+w /etc/hosts |
| if ! awk -v ip="${IP_HOST}" '$1 == ip && $2 == "hadoop-master" { found = 1 } END { exit !found }' /etc/hosts; then |
| sudo sed -i "1i${IP_HOST} hadoop-master" /etc/hosts |
| fi |
| if ! awk -v ip="${IP_HOST}" '$1 == ip && $2 == "hadoop-master-2" { found = 1 } END { exit !found }' /etc/hosts; then |
| sudo sed -i "1i${IP_HOST} hadoop-master-2" /etc/hosts |
| fi |
| register_stack_metadata "kerberos" "${ROOT}/docker-compose/kerberos/kerberos.yaml" "" |
| compose_cmd "${ROOT}/docker-compose/kerberos/kerberos.yaml" "" down --remove-orphans |
| sudo rm -rf "${ROOT}"/docker-compose/kerberos/data |
| if [[ "${STOP}" -ne 1 ]]; then |
| echo "PREPARE KERBEROS DATA" |
| rm -rf "${ROOT}"/docker-compose/kerberos/two-kerberos-hives/*.keytab |
| rm -rf "${ROOT}"/docker-compose/kerberos/two-kerberos-hives/*.jks |
| rm -rf "${ROOT}"/docker-compose/kerberos/two-kerberos-hives/*.conf |
| compose_cmd "${ROOT}/docker-compose/kerberos/kerberos.yaml" "" up --remove-orphans --wait -d |
| sudo ln -sfn "${ROOT}/docker-compose/kerberos/two-kerberos-hives" /keytabs |
| sudo cp "${ROOT}"/docker-compose/kerberos/common/conf/doris-krb5.conf /keytabs/krb5.conf |
| sudo cp "${ROOT}"/docker-compose/kerberos/common/conf/doris-krb5.conf /etc/krb5.conf |
| sleep 2 |
| fi |
| } |
| |
| start_minio() { |
| echo "RUN_MINIO" |
| start_rendered_compose_stack "minio" \ |
| "${ROOT}/docker-compose/minio/minio-RELEASE.2024-11-07.yaml.tpl" \ |
| "${ROOT}/docker-compose/minio/minio-RELEASE.2024-11-07.yaml" \ |
| "${ROOT}/docker-compose/minio/minio-RELEASE.2024-11-07.env" \ |
| -d --wait |
| } |
| |
| start_polaris() { |
| echo "RUN_POLARIS" |
| local POLARIS_DIR="${ROOT}/docker-compose/polaris" |
| # Render compose with envsubst since settings is a bash export file |
| export CONTAINER_UID=${CONTAINER_UID} |
| . "${POLARIS_DIR}/polaris_settings.env" |
| if command -v envsubst >/dev/null 2>&1; then |
| envsubst <"${POLARIS_DIR}/docker-compose.yaml.tpl" >"${POLARIS_DIR}/docker-compose.yaml" |
| else |
| # Fallback: let docker compose handle variable substitution from current shell env |
| cp "${POLARIS_DIR}/docker-compose.yaml.tpl" "${POLARIS_DIR}/docker-compose.yaml" |
| fi |
| register_stack_metadata "polaris" "${POLARIS_DIR}/docker-compose.yaml" "" |
| compose_cmd "${POLARIS_DIR}/docker-compose.yaml" "" down --remove-orphans |
| if [[ "${STOP}" -ne 1 ]]; then |
| compose_cmd "${POLARIS_DIR}/docker-compose.yaml" "" up -d --wait --remove-orphans |
| fi |
| } |
| |
| start_ranger() { |
| echo "RUN_RANGER" |
| export CONTAINER_UID=${CONTAINER_UID} |
| find "${ROOT}/docker-compose/ranger/script" -type f -exec sed -i "s/s3Endpoint/${s3Endpoint}/g" {} \; |
| find "${ROOT}/docker-compose/ranger/script" -type f -exec sed -i "s/s3BucketName/${s3BucketName}/g" {} \; |
| . "${ROOT}/docker-compose/ranger/ranger_settings.env" |
| envsubst <"${ROOT}"/docker-compose/ranger/ranger.yaml.tpl >"${ROOT}"/docker-compose/ranger/ranger.yaml |
| register_stack_metadata "ranger" "${ROOT}/docker-compose/ranger/ranger.yaml" "${ROOT}/docker-compose/ranger/ranger_settings.env" |
| compose_down_stack "${ROOT}/docker-compose/ranger/ranger.yaml" "${ROOT}/docker-compose/ranger/ranger_settings.env" --remove-orphans |
| if [[ "${STOP}" -ne 1 ]]; then |
| compose_up_stack "${ROOT}/docker-compose/ranger/ranger.yaml" "${ROOT}/docker-compose/ranger/ranger_settings.env" -d --wait --remove-orphans |
| fi |
| } |
| |
| start_iceberg_rest() { |
| echo "RUN_ICEBERG_REST" |
| # iceberg-rest with multiple cloud storage backends |
| ICEBERG_REST_DIR=${ROOT}/docker-compose/iceberg-rest |
| |
| # generate iceberg-rest.yaml |
| export CONTAINER_UID=${CONTAINER_UID} |
| . "${ROOT}"/docker-compose/iceberg-rest/iceberg-rest_settings.env |
| envsubst <"${ICEBERG_REST_DIR}/docker-compose.yaml.tpl" >"${ICEBERG_REST_DIR}/docker-compose.yaml" |
| register_stack_metadata "iceberg-rest" "${ICEBERG_REST_DIR}/docker-compose.yaml" "" |
| compose_cmd "${ICEBERG_REST_DIR}/docker-compose.yaml" "" down --remove-orphans |
| if [[ "${STOP}" -ne 1 ]]; then |
| # Start all three REST catalogs (S3, OSS, COS) |
| compose_cmd "${ICEBERG_REST_DIR}/docker-compose.yaml" "" up -d --remove-orphans --wait |
| fi |
| } |
| |
| echo "starting dockers in parallel" |
| |
| reserve_ports |
| |
| # Ensure hive data is downloaded before starting hive2/hive3, but only once |
| need_prepare_hive_data=0 |
| if [[ "$NEED_LOAD_DATA" -eq 1 ]]; then |
| if [[ "${RUN_HIVE2}" -eq 1 ]] || [[ "${RUN_HIVE3}" -eq 1 ]]; then |
| if [[ "${HIVE_MODE}" == "refresh" || "${HIVE_MODE}" == "rebuild" ]]; then |
| need_prepare_hive_data=1 |
| fi |
| fi |
| fi |
| |
| if [[ $need_prepare_hive_data -eq 1 ]]; then |
| prepare_hive_bootstrap_groups=() |
| if [[ "${RUN_HIVE2}" -eq 1 ]]; then |
| prepare_hive_bootstrap_groups+=("$(hive_bootstrap_groups_for "hive2")") |
| fi |
| if [[ "${RUN_HIVE3}" -eq 1 ]]; then |
| prepare_hive_bootstrap_groups+=("$(hive_bootstrap_groups_for "hive3")") |
| fi |
| export HIVE_BOOTSTRAP_GROUPS="$(bootstrap_merge_groups "${prepare_hive_bootstrap_groups[@]}")" |
| echo "prepare hive2/hive3 data" |
| echo "Prepare hive selected bootstrap files: ${HIVE_BOOTSTRAP_GROUPS}" |
| bash "${ROOT}/docker-compose/hive/scripts/prepare-hive-data.sh" |
| fi |
| |
| if [[ "${STOP}" -ne 1 ]]; then |
| if [[ "${RUN_HIVE2}" -eq 1 ]] || [[ "${RUN_HIVE3}" -eq 1 ]]; then |
| ensure_juicefs_hadoop_jar_for_hive |
| fi |
| fi |
| |
| if [[ "${RUN_ES}" -eq 1 ]]; then |
| launch_component "es" "${LOG_ROOT}/start_es.log" start_es |
| fi |
| |
| if [[ "${RUN_MYSQL}" -eq 1 ]]; then |
| launch_component "mysql" "${LOG_ROOT}/start_mysql.log" start_mysql |
| fi |
| |
| if [[ "${RUN_PG}" -eq 1 ]]; then |
| launch_component "pg" "${LOG_ROOT}/start_pg.log" start_pg |
| fi |
| |
| if [[ "${RUN_ORACLE}" -eq 1 ]]; then |
| launch_component "oracle" "${LOG_ROOT}/start_oracle.log" start_oracle |
| fi |
| |
| if [[ "${RUN_DB2}" -eq 1 ]]; then |
| launch_component "db2" "${LOG_ROOT}/start_db2.log" start_db2 |
| fi |
| |
| if [[ "${RUN_OCEANBASE}" -eq 1 ]]; then |
| launch_component "oceanbase" "${LOG_ROOT}/start_oceanbase.log" start_oceanbase |
| fi |
| |
| if [[ "${RUN_SQLSERVER}" -eq 1 ]]; then |
| launch_component "sqlserver" "${LOG_ROOT}/start_sqlserver.log" start_sqlserver |
| fi |
| |
| if [[ "${RUN_CLICKHOUSE}" -eq 1 ]]; then |
| launch_component "clickhouse" "${LOG_ROOT}/start_clickhouse.log" start_clickhouse |
| fi |
| |
| if [[ "${RUN_KAFKA}" -eq 1 ]]; then |
| launch_component "kafka" "${LOG_ROOT}/start_kafka.log" start_kafka |
| fi |
| |
| if [[ "${RUN_HIVE2}" -eq 1 ]]; then |
| launch_component "hive2" "${LOG_ROOT}/start_hive2.log" start_hive2 |
| fi |
| |
| if [[ "${RUN_HIVE3}" -eq 1 ]]; then |
| launch_component "hive3" "${LOG_ROOT}/start_hive3.log" start_hive3 |
| fi |
| |
| if [[ "${RUN_ICEBERG}" -eq 1 ]]; then |
| launch_component "iceberg" "${LOG_ROOT}/start_iceberg.log" start_iceberg |
| fi |
| |
| if [[ "${RUN_ICEBERG_REST}" -eq 1 ]]; then |
| launch_component "iceberg-rest" "${LOG_ROOT}/start_iceberg_rest.log" start_iceberg_rest |
| fi |
| |
| if [[ "${RUN_HUDI}" -eq 1 ]]; then |
| launch_component "hudi" "${LOG_ROOT}/start_hudi.log" start_hudi |
| fi |
| |
| if [[ "${RUN_MARIADB}" -eq 1 ]]; then |
| launch_component "mariadb" "${LOG_ROOT}/start_mariadb.log" start_mariadb |
| fi |
| |
| if [[ "${RUN_LAKESOUL}" -eq 1 ]]; then |
| launch_component "lakesoul" "${LOG_ROOT}/start_lakesoul.log" start_lakesoul |
| fi |
| |
| if [[ "${RUN_MINIO}" -eq 1 ]]; then |
| launch_component "minio" "${LOG_ROOT}/start_minio.log" start_minio |
| fi |
| |
| if [[ "${RUN_POLARIS}" -eq 1 ]]; then |
| launch_component "polaris" "${LOG_ROOT}/start_polaris.log" start_polaris |
| fi |
| |
| if [[ "${RUN_KERBEROS}" -eq 1 ]]; then |
| launch_component "kerberos" "${LOG_ROOT}/start_kerberos.log" start_kerberos |
| fi |
| |
| if [[ "${RUN_RANGER}" -eq 1 ]]; then |
| launch_component "ranger" "${LOG_ROOT}/start_ranger.log" start_ranger |
| fi |
| echo "waiting all dockers starting done" |
| |
| if ! wait_for_started_jobs; then |
| exit 1 |
| fi |
| |
| if [[ "${STOP}" -ne 1 ]]; then |
| if [[ "${RUN_HIVE2}" -eq 1 ]]; then |
| . "${ROOT}"/docker-compose/hive/hive-2x_settings.env |
| prepare_juicefs_meta_for_hive "${JFS_CLUSTER_META}" "cluster" |
| fi |
| if [[ "${RUN_HIVE3}" -eq 1 ]]; then |
| . "${ROOT}"/docker-compose/hive/hive-3x_settings.env |
| prepare_juicefs_meta_for_hive "${JFS_CLUSTER_META}" "cluster" |
| fi |
| fi |
| |
| if [[ "${STOP}" -ne 1 ]]; then |
| echo "docker started" |
| print_started_summary |
| echo "all requested dockers started successfully" |
| fi |