#!/usr/bin/env bash set -euo pipefail # init_kong.sh # Purpose: # - Deploy Kong API Gateway (DB-less) into the service namespace # - Replaces the prole nginx deployment as the API endpoint # - Routes /backup/* to prole-db-manager # - Creates the kong declarative config as a ConfigMap # - Applies the kong deployment and service manifests # - Provides start/stop/status/restart actions SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # Shared option parsing for common core scripts # shellcheck disable=SC1090 source "$SCRIPT_DIR/common_core_lib.sh" # Inject default config if not provided _has_config=0 for _arg in "$@"; do [[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1 done if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@" fi unset _has_config _arg common_core_preparse_config "$@" # shellcheck disable=SC1090 source "$SCRIPT_DIR/prole_cfg.sh" set -- "${COMMON_CORE_ARGS[@]}" common_core_parse_args "$@" if [[ -z "${PROLE_MODE:-}" ]]; then export PROLE_MODE="k3s" fi if [[ "${COMMON_CORE_HELP:-0}" == 1 ]]; then common_core_usage "$0" exit 0 fi if [[ -n "${COMMON_CORE_PARSE_ERROR:-}" ]]; then echo "ERROR: ${COMMON_CORE_PARSE_ERROR}" >&2 common_core_usage "$0" exit 2 fi ACTION="$COMMON_CORE_ACTION" NAMESPACE="$(common_core_resolve_namespace "default")" common_core_apply_namespace "$NAMESPACE" PROLE_HOME=${PROLE_HOME:-$(cd "$SCRIPT_DIR/.." && pwd)} KONG_IMAGE="${KONG_IMAGE:-kong:3.9}" KONG_NAME="${KONG_NAME:-prole-svc-kong}" KONG_PROXY_PORT="${KONG_PROXY_PORT:-8000}" KONG_ADMIN_PORT="${KONG_ADMIN_PORT:-8001}" KONG_CONFIG_NAME="${KONG_CONFIG_NAME:-prole-svc-kong-config}" # Public service entrypoint (single source of truth from prole.cfg via prole_cfg.sh) SERVICE_HOSTNAME="${SERVICE_HOSTNAME:-svc.prole.org}" SERVICE_TLS_SECRET_NAME="${SERVICE_TLS_SECRET_NAME:-${SERVICE_HOSTNAME//./-}-tls}" SERVICE_TLS_CLUSTER_ISSUER="${SERVICE_TLS_CLUSTER_ISSUER:-letsencrypt-prod}" # Legacy: svc-check used to own svc.prole.org. We now route the service hostname # to Grafana, so remove any leftover svc-check resources to avoid conflicts. SVC_CHECK_NAMESPACE="${SVC_CHECK_NAMESPACE:-svc-check}" # kubectl robustness knobs (timeouts/retries for transient apiserver slowness) KUBECTL_REQUEST_TIMEOUT="${KUBECTL_REQUEST_TIMEOUT:-30s}" KUBECTL_APPLY_RETRIES="${KUBECTL_APPLY_RETRIES:-5}" KUBECTL_APPLY_RETRY_DELAY="${KUBECTL_APPLY_RETRY_DELAY:-2}" # Upstream service defaults DB_MANAGER_SERVICE="${DB_MANAGER_SERVICE:-prole-db-manager}" DB_MANAGER_PORT="${DB_MANAGER_PORT:-80}" PROLE_SERVICE_UPSTREAM_URL="${PROLE_SERVICE_UPSTREAM_URL:-http://prole-svc.prole-db.svc.cluster.local:8080}" GRAFANA_UPSTREAM_URL="${GRAFANA_UPSTREAM_URL:-http://kps-grafana.monitoring.svc.cluster.local:80}" usage() { cat </dev/null || { echo "Missing required tool: $t" >&2; exit 1; } done } ensure_namespace() { if ! kubectl get namespace "$NAMESPACE" >/dev/null 2>&1; then echo "Creating namespace '$NAMESPACE' ..." kubectl create namespace "$NAMESPACE" >/dev/null 2>&1 || true fi } kubectl_rt() { kubectl --request-timeout="$KUBECTL_REQUEST_TIMEOUT" "$@" } kubectl_apply_retry() { local attempt=1 local delay="$KUBECTL_APPLY_RETRY_DELAY" while true; do if kubectl_rt apply "$@"; then return 0 fi local rc=$? if [[ "$attempt" -ge "$KUBECTL_APPLY_RETRIES" ]]; then return "$rc" fi echo "WARN: kubectl apply failed (attempt ${attempt}/${KUBECTL_APPLY_RETRIES}); retrying in ${delay}s ..." >&2 sleep "$delay" attempt=$((attempt + 1)) delay=$((delay * 2)) done } create_kong_config() { echo "Creating/updating Kong declarative config '$KONG_CONFIG_NAME' in namespace '$NAMESPACE' ..." local kong_yml kong_yml=$(cat <"$tmp" kubectl_apply_retry -f "$tmp" ) echo "ConfigMap '$KONG_CONFIG_NAME' ready." } cleanup_legacy_svc_check() { # Best-effort cleanup: older installs applied a static check page (svc-check) # that owned the service hostname via its own Ingress and injected routes into # the shared Kong declarative config ConfigMap. kubectl -n "$NAMESPACE" delete ingress svc-check-ingress --ignore-not-found >/dev/null 2>&1 || true kubectl delete namespace "$SVC_CHECK_NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true } apply_service_ingress() { local host="${SERVICE_HOSTNAME:-}" if [[ -z "$host" ]]; then echo "WARN: SERVICE_HOSTNAME is empty; skipping service Ingress." >&2 return 0 fi echo "Applying service Ingress for host '${host}' -> ${KONG_NAME}:${KONG_PROXY_PORT} (namespace=${NAMESPACE}) ..." ( tmp="$(mktemp)" trap 'rm -f "${tmp:-}"' EXIT cat >"$tmp" </dev/null 2>&1 || true kubectl rollout status deployment/"$KONG_NAME" -n "$NAMESPACE" --timeout=120s >/dev/null 2>&1 || true echo "$KONG_NAME deployed successfully." } stop() { echo "Removing $KONG_NAME from namespace '$NAMESPACE' ..." kubectl delete deployment "$KONG_NAME" -n "$NAMESPACE" --ignore-not-found=true kubectl delete service "$KONG_NAME" -n "$NAMESPACE" --ignore-not-found=true kubectl delete configmap "$KONG_CONFIG_NAME" -n "$NAMESPACE" --ignore-not-found=true echo "$KONG_NAME removed." } status() { echo "=== $KONG_NAME pods ===" kubectl get pods -n "$NAMESPACE" -l app="$KONG_NAME" 2>/dev/null || echo "No pods found" echo "" echo "=== $KONG_NAME service ===" kubectl get svc "$KONG_NAME" -n "$NAMESPACE" 2>/dev/null || echo "No service found" } restart() { echo "Restarting $KONG_NAME ..." kubectl rollout restart deployment/"$KONG_NAME" -n "$NAMESPACE" kubectl rollout status deployment/"$KONG_NAME" -n "$NAMESPACE" --timeout=120s echo "$KONG_NAME restarted." } action_update() { ensure_tools ensure_namespace cleanup_legacy_svc_check create_kong_config apply_service_ingress deploy } case "$ACTION" in start|initialize|update|reload) action_update ;; stop) ensure_tools stop ;; status) ensure_tools status ;; restart) ensure_tools restart ;; *) usage ;; esac