Template
Fix mita RPC socket path and rate-limit heal recovery.
This commit is contained in:
@@ -103,7 +103,7 @@ else:
|
|||||||
application_path = os.path.dirname(__file__)
|
application_path = os.path.dirname(__file__)
|
||||||
|
|
||||||
DATA_FILE = os.path.join(application_path, 'data.json') # legacy JSON; used only for one-shot import / export
|
DATA_FILE = os.path.join(application_path, 'data.json') # legacy JSON; used only for one-shot import / export
|
||||||
CURRENT_VERSION = "v2.6.8"
|
CURRENT_VERSION = "v2.6.9"
|
||||||
RELEASES_REPO_URL = repo_url()
|
RELEASES_REPO_URL = repo_url()
|
||||||
RELEASES_API_LATEST = api_latest_url()
|
RELEASES_API_LATEST = api_latest_url()
|
||||||
BIN_DIR = os.environ.get('TUNNEL_BIN_DIR', os.path.join(application_path, 'bin'))
|
BIN_DIR = os.environ.get('TUNNEL_BIN_DIR', os.path.join(application_path, 'bin'))
|
||||||
|
|||||||
+32
-23
@@ -21,7 +21,9 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
MIERU_RELEASE = '3.28.0'
|
MIERU_RELEASE = '3.28.0'
|
||||||
GITHUB_RELEASE = f'https://github.com/enfein/mieru/releases/download/v{MIERU_RELEASE}'
|
GITHUB_RELEASE = f'https://github.com/enfein/mieru/releases/download/v{MIERU_RELEASE}'
|
||||||
MITA_SOCK = '/var/run/mita.sock'
|
# Official mita UDS (v3.x). Older docs sometimes mention /var/run/mita.sock.
|
||||||
|
MITA_SOCK = '/var/run/mita/mita.sock'
|
||||||
|
MITA_SOCK_LEGACY = '/var/run/mita.sock'
|
||||||
# Official package persists applied config here. If this file has portBindings
|
# Official package persists applied config here. If this file has portBindings
|
||||||
# but no users, `mita run` (systemd) auto-starts the proxy and FATAL-exits
|
# but no users, `mita run` (systemd) auto-starts the proxy and FATAL-exits
|
||||||
# with "socks5 server listening failed: no user found", crashing the daemon.
|
# with "socks5 server listening failed: no user found", crashing the daemon.
|
||||||
@@ -246,10 +248,14 @@ class MieruManager:
|
|||||||
self.ssh.run_sudo_command(
|
self.ssh.run_sudo_command(
|
||||||
f"systemctl stop {self.SERVICE_NAME} 2>/dev/null || true; "
|
f"systemctl stop {self.SERVICE_NAME} 2>/dev/null || true; "
|
||||||
f"systemctl reset-failed {self.SERVICE_NAME} 2>/dev/null || true; "
|
f"systemctl reset-failed {self.SERVICE_NAME} 2>/dev/null || true; "
|
||||||
f"rm -f {_q(MITA_SOCK)} /var/run/mita/*.sock "
|
f"rm -f {_q(MITA_SOCK)} {_q(MITA_SOCK_LEGACY)} /var/run/mita/*.sock "
|
||||||
f"{_q(MITA_CONFIG_PB)} {_q(MITA_CONFIG_JSON)} 2>/dev/null || true",
|
f"{_q(MITA_CONFIG_PB)} {_q(MITA_CONFIG_JSON)} 2>/dev/null || true; "
|
||||||
|
f"mkdir -p /var/run/mita /etc/mita 2>/dev/null || true",
|
||||||
timeout=60,
|
timeout=60,
|
||||||
)
|
)
|
||||||
|
# systemd StartLimitBurst: wait out "Start request repeated too quickly".
|
||||||
|
time.sleep(6)
|
||||||
|
|
||||||
clients = self._ensure_bootstrap_clients(self._read_clients())
|
clients = self._ensure_bootstrap_clients(self._read_clients())
|
||||||
self._write_clients(clients)
|
self._write_clients(clients)
|
||||||
meta = self._read_metadata()
|
meta = self._read_metadata()
|
||||||
@@ -258,17 +264,26 @@ class MieruManager:
|
|||||||
self._write_file(self.config_path, json.dumps(config, indent=2))
|
self._write_file(self.config_path, json.dumps(config, indent=2))
|
||||||
|
|
||||||
self.ssh.run_sudo_command(
|
self.ssh.run_sudo_command(
|
||||||
|
f"systemctl reset-failed {self.SERVICE_NAME} 2>/dev/null || true; "
|
||||||
f"systemctl start {self.SERVICE_NAME}",
|
f"systemctl start {self.SERVICE_NAME}",
|
||||||
timeout=60,
|
timeout=60,
|
||||||
)
|
)
|
||||||
|
if not self._wait_for_rpc(timeout=60):
|
||||||
|
# Second attempt after another rate-limit window.
|
||||||
|
self.ssh.run_sudo_command(
|
||||||
|
f"systemctl reset-failed {self.SERVICE_NAME} 2>/dev/null || true; "
|
||||||
|
f"systemctl restart {self.SERVICE_NAME}",
|
||||||
|
timeout=60,
|
||||||
|
)
|
||||||
|
time.sleep(3)
|
||||||
if not self._wait_for_rpc(timeout=45):
|
if not self._wait_for_rpc(timeout=45):
|
||||||
journal, _, _ = self.ssh.run_sudo_command(
|
journal, _, _ = self.ssh.run_sudo_command(
|
||||||
f"journalctl -u {self.SERVICE_NAME} -n 40 --no-pager 2>&1",
|
f"journalctl -u {self.SERVICE_NAME} -n 50 --no-pager 2>&1",
|
||||||
timeout=30,
|
timeout=30,
|
||||||
)
|
)
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
'mita daemon still not ready after heal. '
|
'mita daemon still not ready after heal. '
|
||||||
f'journal: {(journal or "").strip()[-500:]}'
|
f'journal: {(journal or "").strip()[-600:]}'
|
||||||
)
|
)
|
||||||
out, err, code = self._mita_cli(
|
out, err, code = self._mita_cli(
|
||||||
['apply', 'config', _q(self.config_path)],
|
['apply', 'config', _q(self.config_path)],
|
||||||
@@ -284,7 +299,8 @@ class MieruManager:
|
|||||||
def _ensure_daemon(self, log=None):
|
def _ensure_daemon(self, log=None):
|
||||||
"""Ensure mita systemd unit is up and RPC socket answers."""
|
"""Ensure mita systemd unit is up and RPC socket answers."""
|
||||||
self.ssh.run_sudo_command(
|
self.ssh.run_sudo_command(
|
||||||
f"systemctl enable {self.SERVICE_NAME} 2>/dev/null || true",
|
f"systemctl enable {self.SERVICE_NAME} 2>/dev/null || true; "
|
||||||
|
f"mkdir -p /var/run/mita /etc/mita 2>/dev/null || true",
|
||||||
timeout=30,
|
timeout=30,
|
||||||
)
|
)
|
||||||
# Official package expects the operating user in group `mita`.
|
# Official package expects the operating user in group `mita`.
|
||||||
@@ -308,29 +324,19 @@ class MieruManager:
|
|||||||
timeout=60,
|
timeout=60,
|
||||||
)
|
)
|
||||||
if not self._wait_for_rpc(timeout=45):
|
if not self._wait_for_rpc(timeout=45):
|
||||||
# Crash loop / stale socket — wipe broken store and recover.
|
# Crash loop / wrong socket / rate-limit — wipe store and recover.
|
||||||
if self._daemon_needs_heal():
|
|
||||||
self._heal_mita_store(log)
|
|
||||||
else:
|
|
||||||
self.ssh.run_sudo_command(
|
|
||||||
f"systemctl stop {self.SERVICE_NAME} 2>/dev/null || true; "
|
|
||||||
f"rm -f {_q(MITA_SOCK)} /var/run/mita/*.sock 2>/dev/null || true; "
|
|
||||||
f"systemctl start {self.SERVICE_NAME}",
|
|
||||||
timeout=60,
|
|
||||||
)
|
|
||||||
if not self._wait_for_rpc(timeout=45):
|
|
||||||
# Last resort: heal even if journal didn't match yet.
|
|
||||||
self._heal_mita_store(log)
|
self._heal_mita_store(log)
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.append('mita daemon is active')
|
log.append('mita daemon is active')
|
||||||
|
|
||||||
def _wait_for_rpc(self, timeout=30):
|
def _wait_for_rpc(self, timeout=30):
|
||||||
deadline = time.time() + timeout
|
deadline = time.time() + timeout
|
||||||
while time.time() < deadline:
|
sock_check = (
|
||||||
sock_out, _, sock_code = self.ssh.run_sudo_command(
|
f"(test -S {_q(MITA_SOCK)} || test -S {_q(MITA_SOCK_LEGACY)}) && echo ok"
|
||||||
f"test -S {_q(MITA_SOCK)} && echo ok"
|
|
||||||
)
|
)
|
||||||
if sock_code == 0 and 'ok' in (sock_out or ''):
|
while time.time() < deadline:
|
||||||
|
# Prefer CLI status: if it answers IDLE/RUNNING, RPC is up
|
||||||
|
# regardless of which sock path we expected.
|
||||||
status_out, _, status_code = self.ssh.run_sudo_command(
|
status_out, _, status_code = self.ssh.run_sudo_command(
|
||||||
'mita status 2>&1',
|
'mita status 2>&1',
|
||||||
timeout=20,
|
timeout=20,
|
||||||
@@ -338,7 +344,10 @@ class MieruManager:
|
|||||||
text = (status_out or '').upper()
|
text = (status_out or '').upper()
|
||||||
if status_code == 0 and ('IDLE' in text or 'RUNNING' in text):
|
if status_code == 0 and ('IDLE' in text or 'RUNNING' in text):
|
||||||
return True
|
return True
|
||||||
# Socket exists but CLI still races — brief pause.
|
sock_out, _, sock_code = self.ssh.run_sudo_command(sock_check)
|
||||||
|
if sock_code == 0 and 'ok' in (sock_out or ''):
|
||||||
|
time.sleep(1)
|
||||||
|
continue
|
||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user