134 lines
4.0 KiB
Bash
Executable File
134 lines
4.0 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Usage:
|
|
# 1) Edit the PORT_FORWARDS list below with entries of:
|
|
# <namespace> <service_name> <local_port> <service_port>
|
|
# 2) Run: ./init_port_forward.sh
|
|
#
|
|
# The script will start all port-forwards in the background and keep running
|
|
# until interrupted (Ctrl+C). On exit, it will clean up started port-forward processes.
|
|
|
|
set -euo pipefail
|
|
|
|
# Define your namespace/service/port combinations here
|
|
# Example entries:
|
|
# "default my-service 8080 80"
|
|
# "observability grafana 3000 3000"
|
|
PORT_FORWARDS=(
|
|
"mongodb my-release-mongodb 27017 27017"
|
|
"paradedb paradedb-rw 5432 5432"
|
|
"redis redis-master 6379 6379"
|
|
"temporal temporal-frontend 7233 7233"
|
|
)
|
|
|
|
if [ ${#PORT_FORWARDS[@]} -eq 0 ]; then
|
|
echo "No port-forward entries defined. Edit PORT_FORWARDS in $(basename "$0")."
|
|
exit 1
|
|
fi
|
|
|
|
PIDS=()
|
|
|
|
cleanup() {
|
|
echo "\nStopping port-forward processes..."
|
|
for pid in "${PIDS[@]}"; do
|
|
if kill -0 "$pid" >/dev/null 2>&1; then
|
|
kill "$pid" >/dev/null 2>&1 || true
|
|
fi
|
|
done
|
|
}
|
|
|
|
trap cleanup EXIT INT TERM
|
|
|
|
timestamp() { date '+%Y-%m-%d %H:%M:%S'; }
|
|
|
|
# Allow overriding kubectl binary if needed
|
|
KUBECTL=${KUBECTL:-kubectl}
|
|
|
|
is_port_free() {
|
|
local port="$1"
|
|
# Consider port free if nothing is listening locally on it
|
|
if command -v ss >/dev/null 2>&1; then
|
|
! ss -ltn | awk '{print $4}' | grep -E "(^|:|\\])${port}$" >/dev/null 2>&1
|
|
else
|
|
if command -v lsof >/dev/null 2>&1; then
|
|
! lsof -tiTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1
|
|
else
|
|
# Fallback: attempt to open a TCP connection; expect failure when nothing is listening
|
|
! (exec 3<>"/dev/tcp/127.0.0.1/${port}") 2>/dev/null
|
|
fi
|
|
fi
|
|
}
|
|
|
|
free_port_if_stuck() {
|
|
local port="$1"
|
|
# Try multiple tools to free a stuck listener (often old kubectl PF)
|
|
if command -v lsof >/dev/null 2>&1; then
|
|
local pids
|
|
pids=$(lsof -tiTCP:"${port}" -sTCP:LISTEN 2>/dev/null || true)
|
|
if [ -n "${pids}" ]; then
|
|
echo "[$(timestamp)] Found listeners on ${port}: ${pids}; terminating"
|
|
kill ${pids} 2>/dev/null || true
|
|
sleep 0.5
|
|
fi
|
|
fi
|
|
if ! is_port_free "${port}"; then
|
|
if command -v fuser >/dev/null 2>&1; then
|
|
echo "[$(timestamp)] Forcing free of ${port} via fuser"
|
|
fuser -k "${port}/tcp" 2>/dev/null || true
|
|
sleep 0.5
|
|
fi
|
|
fi
|
|
}
|
|
|
|
run_port_forward() {
|
|
local namespace="$1"
|
|
local service_name="$2"
|
|
local local_port="$3"
|
|
local service_port="$4"
|
|
|
|
# simple and robust supervisor loop with gentle backoff on failures
|
|
local delay=2
|
|
local max_delay=20
|
|
while true; do
|
|
free_port_if_stuck "${local_port}"
|
|
if ! is_port_free "${local_port}"; then
|
|
echo "[$(timestamp)] ns=${namespace} svc=${service_name} ${local_port}:${service_port} -> local port busy, retrying in 3s"
|
|
sleep 3
|
|
continue
|
|
fi
|
|
|
|
echo "[$(timestamp)] Starting port-forward: ns=${namespace} svc=${service_name} ${local_port}:${service_port}"
|
|
${KUBECTL} -n "${namespace}" port-forward "svc/${service_name}" "${local_port}:${service_port}" \
|
|
--address=127.0.0.1 --pod-running-timeout=2m --request-timeout=0
|
|
rc=$?
|
|
|
|
# If kubectl exits (e.g., connection reset by peer), wait a bit and retry
|
|
echo "[$(timestamp)] Port-forward exited (rc=${rc}): ns=${namespace} svc=${service_name} ${local_port}:${service_port}"
|
|
sleep "${delay}"
|
|
# Exponential backoff up to max_delay
|
|
if [ ${delay} -lt ${max_delay} ]; then
|
|
delay=$(( delay * 2 ))
|
|
if [ ${delay} -gt ${max_delay} ]; then
|
|
delay=${max_delay}
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
ONLY_SERVICE_NAME="${ONLY_SERVICE_NAME:-}"
|
|
|
|
for entry in "${PORT_FORWARDS[@]}"; do
|
|
read -r NAMESPACE SERVICE_NAME LOCAL_PORT SERVICE_PORT <<< "$entry"
|
|
if [ -n "${ONLY_SERVICE_NAME}" ] && [ "${SERVICE_NAME}" != "${ONLY_SERVICE_NAME}" ]; then
|
|
continue
|
|
fi
|
|
run_port_forward "${NAMESPACE}" "${SERVICE_NAME}" "${LOCAL_PORT}" "${SERVICE_PORT}" &
|
|
PIDS+=("$!")
|
|
done
|
|
|
|
echo "All port-forwards started: ${#PIDS[@]} process(es). Press Ctrl+C to stop."
|
|
|
|
# Do not exit the script if one port-forward fails; they self-restart
|
|
set +e
|
|
wait
|