| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- #!/usr/bin/env bash
- require_root() {
- if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
- echo "need root"
- exit 1
- fi
- }
- ensure_runtime_user() {
- local user_name="$1"
- id -u "$user_name" >/dev/null 2>&1 || useradd --system --no-create-home --shell /usr/sbin/nologin "$user_name"
- }
- ensure_log_file() {
- local log_file="$1"
- local owner="$2"
- mkdir -p "$(dirname "$log_file")"
- touch "$log_file"
- chown "$owner":"$owner" "$log_file"
- }
- pid_matches_marker() {
- local pid="$1"
- local marker="$2"
- [[ "$pid" =~ ^[0-9]+$ ]] || return 1
- [[ -r "/proc/$pid/cmdline" ]] || return 1
- local cmdline
- cmdline="$(tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null || true)"
- [[ "$cmdline" == *"$marker"* ]]
- }
- find_pids_by_marker() {
- local marker="$1"
- local proc_path
- for proc_path in /proc/[0-9]*; do
- local pid="${proc_path##*/}"
- if pid_matches_marker "$pid" "$marker"; then
- printf '%s\n' "$pid"
- fi
- done
- }
- stop_pid() {
- local pid="$1"
- kill "$pid" 2>/dev/null || true
- for _ in {1..30}; do
- if ! kill -0 "$pid" 2>/dev/null; then
- return 0
- fi
- sleep 0.1
- done
- if kill -0 "$pid" 2>/dev/null; then
- kill -9 "$pid" 2>/dev/null || true
- fi
- }
- stop_pid_file() {
- local pid_file="$1"
- local marker="$2"
- local pid=""
- if [[ -f "$pid_file" ]]; then
- pid="$(cat "$pid_file" 2>/dev/null || true)"
- fi
- if pid_matches_marker "$pid" "$marker"; then
- stop_pid "$pid"
- else
- while IFS= read -r matched_pid; do
- [[ -n "$matched_pid" ]] || continue
- stop_pid "$matched_pid"
- done < <(find_pids_by_marker "$marker")
- fi
- rm -f "$pid_file"
- }
- wait_for_tcp_listen() {
- local host="$1"
- local port="$2"
- local timeout_sec="${3:-15}"
- local deadline=$((SECONDS + timeout_sec))
- local escaped_host="${host//./\\.}"
- local pattern="${escaped_host}:${port}( |$)"
- while (( SECONDS < deadline )); do
- if ss -H -lnt 2>/dev/null | grep -qE "$pattern"; then
- return 0
- fi
- sleep 0.2
- done
- return 1
- }
- start_python_service() {
- local runtime_user="$1"
- local workdir="$2"
- local pythonpath="$3"
- local log_file="$4"
- local pid_file="$5"
- local marker="$6"
- local argv_json="$7"
- local launcher='
- import json
- import os
- import subprocess
- import sys
- runtime_user, workdir, pythonpath, log_file, pid_file, marker, argv_json = sys.argv[1:]
- argv = json.loads(argv_json)
- env = os.environ.copy()
- env["PYTHONUNBUFFERED"] = "1"
- env["PYTHONPATH"] = pythonpath
- with open(log_file, "ab", buffering=0) as handle:
- proc = subprocess.Popen(
- argv,
- cwd=workdir,
- env=env,
- stdin=subprocess.DEVNULL,
- stdout=handle,
- stderr=subprocess.STDOUT,
- start_new_session=True,
- )
- print(proc.pid)
- '
- local pid
- pid="$(
- runuser -u "$runtime_user" -- python3 -c "$launcher" \
- "$runtime_user" "$workdir" "$pythonpath" "$log_file" "$pid_file" "$marker" "$argv_json"
- )"
- printf '%s\n' "$pid" > "$pid_file"
- printf '%s\n' "$pid"
- }
- ensure_nat_jump_absent() {
- local cmd="$1"
- local table="$2"
- local chain="$3"
- shift 3
- while "$cmd" -t "$table" -C "$chain" "$@" >/dev/null 2>&1; do
- "$cmd" -t "$table" -D "$chain" "$@" >/dev/null 2>&1 || break
- done
- }
- ensure_nat_chain_absent() {
- local cmd="$1"
- local chain="$2"
- if ! command -v "$cmd" >/dev/null 2>&1; then
- return 0
- fi
- if ! "$cmd" -t nat -S >/dev/null 2>&1; then
- return 0
- fi
- "$cmd" -t nat -F "$chain" 2>/dev/null || true
- "$cmd" -t nat -X "$chain" 2>/dev/null || true
- }
|