#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck disable=SC1090 source "$SCRIPT_DIR/prole_cfg.sh" usage() { cat </dev/null 2>&1; then MODE=$(prole_normalize_mode "$MODE") fi if [[ -n "$MODE" && "$MODE" != "k3d" ]]; then echo "[INFO] nginx ingress host-port mappings are only applied for k3d (mode=$MODE)." exit 0 fi prole_ensure_kubeconfig >/dev/null 2>&1 || true ensure_kube_context || exit 1 PORT_MAPPING_FILE_PATH="${PORT_MAPPING_FILE:-}" if [[ -z "$PORT_MAPPING_FILE_PATH" ]]; then if [[ -n "${PROLE_CONF:-}" && -f "$PROLE_CONF/port-mapping.cfg" ]]; then PORT_MAPPING_FILE_PATH="$PROLE_CONF/port-mapping.cfg" elif [[ -f "$SCRIPT_DIR/../conf/port-mapping.cfg" ]]; then PORT_MAPPING_FILE_PATH="$SCRIPT_DIR/../conf/port-mapping.cfg" fi fi if [[ -n "$CFG_FILE" && -f "$CFG_FILE" ]]; then PORT_MAPPING_FILE_PATH="$CFG_FILE" fi if [[ -z "$PORT_MAPPING_FILE_PATH" || ! -f "$PORT_MAPPING_FILE_PATH" ]]; then echo "ERROR: port-mapping.cfg not found (set PORT_MAPPING_FILE or use --config-file)." >&2 exit 1 fi trim() { _prole_trim "$1" } # Parse legacy conf/port-mapping.cfg style entries. declare -A PORT_MAP PORT_MAP[_dummy_]=1; unset "PORT_MAP[_dummy_]" # keep array "bound" under set -u while IFS= read -r line; do line="$(trim "$line")" [[ -z "$line" ]] && continue case "$line" in \#*|\;*) continue ;; esac id="${line%%:*}" rest="${line#*:}" if [[ "$id" == "$line" ]]; then continue fi id="$(trim "$id")" rest="$(trim "$rest")" hostPort="" servicePort="" ns="" target="" for token in $rest; do key="$(trim "${token%%=*}")" value="$(trim "${token#*=}")" case "$key" in local|host|hostPort|host_port) hostPort="$value" ;; remote|servicePort|service_port) servicePort="$value" ;; ns|namespace) ns="$value" ;; svc|service) target="svc/$value" ;; target) target="$value" ;; desc|description) ;; esac done if [[ -z "$hostPort" || -z "$servicePort" || -z "$ns" || -z "$target" ]]; then echo "[WARN] Skipping mapping '$id': missing required fields." >&2 continue fi if [[ "$target" == svc/* ]]; then svc="${target#svc/}" else echo "[WARN] Skipping mapping '$id': target '$target' is not a service." >&2 continue fi PORT_MAP["$hostPort"]="$ns/$svc:$servicePort" done <"$PORT_MAPPING_FILE_PATH" if [[ "${#PORT_MAP[@]}" -eq 0 ]]; then echo "ERROR: No mappings found in $PORT_MAPPING_FILE_PATH" >&2 exit 1 fi INGRESS_NS="${INGRESS_NGINX_NAMESPACE:-ingress-nginx}" TCP_CONFIGMAP="${INGRESS_NGINX_TCP_CONFIGMAP:-tcp-services}" # Ensure namespace exists kubectl get namespace "$INGRESS_NS" >/dev/null 2>&1 || kubectl create namespace "$INGRESS_NS" >/dev/null # Build ConfigMap for ingress-nginx TCP services TMP_CM=$(mktemp) { echo "apiVersion: v1" echo "kind: ConfigMap" echo "metadata:" echo " name: ${TCP_CONFIGMAP}" echo " namespace: ${INGRESS_NS}" echo "data:" for port in $(printf '%s\n' "${!PORT_MAP[@]}" | sort -n); do echo " \"${port}\": \"${PORT_MAP[$port]}\"" done } >"$TMP_CM" kubectl apply -f "$TMP_CM" rm -f "$TMP_CM" # Patch ingress-nginx controller service to expose TCP ports, if present. if kubectl -n "$INGRESS_NS" get svc ingress-nginx-controller >/dev/null 2>&1; then existing_ports=$(kubectl -n "$INGRESS_NS" get svc ingress-nginx-controller -o jsonpath='{.spec.ports[*].port}') for port in $(printf '%s\n' "${!PORT_MAP[@]}" | sort -n); do if ! echo " $existing_ports " | grep -q " $port "; then kubectl -n "$INGRESS_NS" patch svc ingress-nginx-controller --type json \ -p "[{\"op\":\"add\",\"path\":\"/spec/ports/-\",\"value\":{\"name\":\"tcp-${port}\",\"port\":${port},\"protocol\":\"TCP\",\"targetPort\":${port}}}]" >/dev/null fi done echo "[OK] nginx ingress TCP mappings applied." else echo "[WARN] ingress-nginx-controller service not found in namespace '$INGRESS_NS'." echo " Install ingress-nginx and rerun init_nginx_ingress.sh to expose host ports." fi