fix the manager

This commit is contained in:
2026-07-06 12:34:01 +02:00
parent de468929e1
commit 05070d7d54
6 changed files with 115 additions and 15 deletions

View File

@@ -10,6 +10,7 @@ import asyncio
import json
import os
import socket
import subprocess
import threading
import time
from typing import Any, Dict, Optional
@@ -52,6 +53,77 @@ def format_access_url(host: str, port: int) -> str:
return f"http://{host}:{port}"
def detect_lan_ip() -> str:
configured_ip = os.getenv("MANAGER_PUBLIC_IP") or os.getenv("CONFIGURATOR_PUBLIC_IP")
if configured_ip:
return configured_ip
try:
output = subprocess.check_output(
["ip", "route", "get", "1.1.1.1"],
stderr=subprocess.DEVNULL,
text=True,
).strip()
parts = output.split()
if "src" in parts:
candidate = parts[parts.index("src") + 1]
if is_public_manager_ip(candidate):
return candidate
except (OSError, subprocess.SubprocessError, IndexError):
pass
try:
output = subprocess.check_output(
["ip", "-o", "-4", "addr", "show", "scope", "global"],
stderr=subprocess.DEVNULL,
text=True,
)
for line in output.splitlines():
parts = line.split()
interface = parts[1]
candidate = parts[3].split("/", 1)[0]
if is_ignored_interface(interface):
continue
if is_public_manager_ip(candidate):
return candidate
except (OSError, subprocess.SubprocessError, IndexError):
pass
try:
output = subprocess.check_output(["hostname", "-I"], stderr=subprocess.DEVNULL, text=True).strip()
for candidate in output.split():
if is_public_manager_ip(candidate):
return candidate
except (OSError, subprocess.SubprocessError):
pass
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.connect(("8.8.8.8", 80))
candidate = sock.getsockname()[0]
if is_public_manager_ip(candidate):
return candidate
except OSError:
pass
return "localhost"
def is_ignored_interface(interface: str) -> bool:
ignored_prefixes = ("docker", "br-", "veth", "virbr", "podman", "lo")
return interface.startswith(ignored_prefixes)
def is_public_manager_ip(candidate: str) -> bool:
if not candidate or "." not in candidate:
return False
if candidate.startswith("127.") or candidate.startswith("169.254."):
return False
if candidate.startswith("172.17."):
return False
return True
def get_user_container_lock(user_id: str) -> threading.Lock:
with user_container_locks_guard:
if user_id not in user_container_locks:
@@ -448,12 +520,13 @@ async def main():
log(f"Gateway port: {GATEWAY_PORT if GATEWAY_PORT else 'disabled'}")
log(f"Inactivity timeout: {INACTIVITY_SECONDS}s")
public_host = detect_lan_ip()
servers = []
if GATEWAY_PORT > 0:
gateway_server = await asyncio.start_server(handle_gateway_connection, "0.0.0.0", GATEWAY_PORT)
log(
"Shared gateway ready: "
f"{format_access_url('localhost', GATEWAY_PORT)} "
f"{format_access_url(public_host, GATEWAY_PORT)} "
f"(host-based routing: http://<user>.localhost:{GATEWAY_PORT})"
)
servers.append(gateway_server)
@@ -463,7 +536,7 @@ async def main():
await handle_connection(reader, writer, configured_user)
server = await asyncio.start_server(handler, "0.0.0.0", user["port"])
direct_url = format_access_url("localhost", user["port"])
direct_url = format_access_url(public_host, user["port"])
if GATEWAY_PORT > 0:
gateway_url = format_access_url(f"{user['id']}.localhost", GATEWAY_PORT)
log(