#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" COMMON_ENV_FILE="${ROOT_DIR}/environment.server" SERVER_ENV_FILE="${ROOT_DIR}/deploy/server/.env" CONSOLE_ENV_FILE="${ROOT_DIR}/deploy/console/.env" CONSOLE_COMPOSE_FILE="${ROOT_DIR}/deploy/console/docker-compose.yml" MODE="${RPKI_RTR_SERVER_MODE:-tcp}" COMPOSE_PROJECT="${RPKI_RTR_COMPOSE_PROJECT:-rpki-rtr}" CONSOLE_COMPOSE_PROJECT="${RPKI_CONSOLE_COMPOSE_PROJECT:-rpki-console}" WAIT_SECS="${RPKI_START_WAIT_SECS:-20}" usage() { cat <<'EOF' Usage: scripts/01_start.sh [options] Read root ./environment.server, update deploy/server/.env, then start the RTR server and console. Options: --env FILE Common env file. Default: ./environment.server --mode MODE Server mode: tcp|tls|ssh|base. Default: tcp --wait SECS Wait timeout for container running checks. Default: 20 -h, --help Show this help. EOF } log() { printf '[01_start] %s\n' "$*" >&2 } stage() { printf '\n====== %s ======\n' "$*" >&2 } die() { printf '[01_start] ERROR: %s\n' "$*" >&2 exit 1 } set_env_var() { local env_file="$1" local key="$2" local value="$3" local tmp_file tmp_file="${env_file}.tmp.$$" awk -v key="${key}" -v value="${value}" ' BEGIN { done = 0 } $0 ~ "^[[:space:]]*#?[[:space:]]*" key "=" { if (!done) { print key "=" value done = 1 } next } { print } END { if (!done) { print key "=" value } } ' "${env_file}" >"${tmp_file}" mv "${tmp_file}" "${env_file}" } compose_file_for_mode() { case "$1" in tcp) printf '%s\n' "${ROOT_DIR}/deploy/server/docker-compose.tcp.yml" ;; tls) printf '%s\n' "${ROOT_DIR}/deploy/server/docker-compose.tls.yml" ;; ssh) printf '%s\n' "${ROOT_DIR}/deploy/server/docker-compose.ssh.yml" ;; base) printf '%s\n' "${ROOT_DIR}/deploy/server/docker-compose.yml" ;; *) die "unsupported mode '$1', expected tcp|tls|ssh|base" ;; esac } update_env_from_common() { local target_env_file="$1" local updated_count=0 local line key value while IFS= read -r line || [ -n "${line}" ]; do case "${line}" in ''|\#*) continue ;; *=*) key="${line%%=*}" value="${line#*=}" set_env_var "${target_env_file}" "${key}" "${value}" updated_count=$((updated_count + 1)) ;; esac done <"${COMMON_ENV_FILE}" printf '%s\n' "${updated_count}" } server_compose() { "${COMPOSE_BIN[@]}" --env-file "${SERVER_ENV_FILE}" -p "${COMPOSE_PROJECT}" -f "${SERVER_COMPOSE_FILE}" "$@" } console_compose() { "${COMPOSE_BIN[@]}" --env-file "${CONSOLE_ENV_FILE}" -p "${CONSOLE_COMPOSE_PROJECT}" -f "${CONSOLE_COMPOSE_FILE}" "$@" } container_running() { local compose_kind="$1" local service="$2" local cid state if [ "${compose_kind}" = "server" ]; then cid="$(server_compose ps -q "${service}" 2>/dev/null || true)" else cid="$(console_compose ps -q "${service}" 2>/dev/null || true)" fi [ -n "${cid}" ] || return 1 state="$(docker inspect -f '{{.State.Running}}' "${cid}" 2>/dev/null || true)" [ "${state}" = "true" ] } show_service_debug() { local compose_kind="$1" local service="$2" log "${service} is not running, current compose status:" if [ "${compose_kind}" = "server" ]; then server_compose ps "${service}" >&2 || true log "${service} recent logs:" server_compose logs --tail=80 "${service}" >&2 || true else console_compose ps "${service}" >&2 || true log "${service} recent logs:" console_compose logs --tail=80 "${service}" >&2 || true fi } wait_for_running() { local compose_kind="$1" local service="$2" local deadline=$((SECONDS + WAIT_SECS)) while [ "${SECONDS}" -lt "${deadline}" ]; do if container_running "${compose_kind}" "${service}"; then log "${service} is running" return 0 fi sleep 1 done show_service_debug "${compose_kind}" "${service}" die "${service} failed to reach running state after ${WAIT_SECS}s" } while [ "$#" -gt 0 ]; do case "$1" in --env) [ "$#" -ge 2 ] || die "--env requires a value" COMMON_ENV_FILE="$2" shift 2 ;; --mode) [ "$#" -ge 2 ] || die "--mode requires a value" MODE="$2" shift 2 ;; --wait) [ "$#" -ge 2 ] || die "--wait requires a value" WAIT_SECS="$2" shift 2 ;; -h|--help) usage exit 0 ;; *) die "unknown option: $1" ;; esac done SERVER_COMPOSE_FILE="$(compose_file_for_mode "${MODE}")" stage "Checking Docker" command -v docker >/dev/null 2>&1 || die "docker command not found" if docker compose version >/dev/null 2>&1; then COMPOSE_BIN=(docker compose) elif command -v docker-compose >/dev/null 2>&1 && docker-compose version >/dev/null 2>&1; then COMPOSE_BIN=(docker-compose) else die "docker compose is not available" fi [ -f "${SERVER_ENV_FILE}" ] || die "server env file not found: ${SERVER_ENV_FILE}" [ -f "${SERVER_COMPOSE_FILE}" ] || die "server compose file not found: ${SERVER_COMPOSE_FILE}" [ -f "${CONSOLE_ENV_FILE}" ] || die "console env file not found: ${CONSOLE_ENV_FILE}" [ -f "${CONSOLE_COMPOSE_FILE}" ] || die "console compose file not found: ${CONSOLE_COMPOSE_FILE}" if [ -f "${COMMON_ENV_FILE}" ]; then stage "Reading Environment" server_updated_count="$(update_env_from_common "${SERVER_ENV_FILE}")" log "updated ${server_updated_count} server env variable(s)" else stage "Reading Environment" log "environment.server file not found, skip env update" fi stage "Starting RTR Server" log "starting docker compose service: rpki-rtr" server_compose up -d --no-build rpki-rtr log "waiting for rpki-rtr to be running" wait_for_running server rpki-rtr stage "Starting Console" log "starting docker compose service: rpki-console-ui" console_compose up -d --no-build rpki-console-ui log "waiting for rpki-console-ui to be running" wait_for_running console rpki-console-ui stage "Start Finished"