yt-dlp-gui/tests/test_deploy_units.py
loop-uh e1c0592b84 Туннели к ai-egress не раскручивают штраф sshd: юниты в deploy/, разнесённый старт, растущая пауза
sshd на ai-egress (OpenSSH 10, PerSourcePenalties) штрафует наш IP за
соединения, не дошедшие до аутентификации, и на время штрафа отказывает всем
SSH-соединениям с хоста. 32 туннеля пула перезапускались одновременно раз в
5 с и копили штраф сами: 27.09.2026 — 296 перезапусков в час, на узле
«drop connection … penalty: connections without attempting authentication».

- юниты пула и основного туннеля перенесены в deploy/ (были только в /etc);
- старт экземпляров пула разнесён на 0–15 с (ExecStartPre);
- пауза между перезапусками растёт 5 с → 180 с (RestartSteps/RestartMaxDelaySec);
- keepalive пула 10 с × 3 вместо 5 с × 2: короткое подвисание не рвёт туннель;
- tests/test_deploy_units.py держит эти свойства, AGENTS.md описывает механизм.
2026-09-27 15:15:57 +03:00

57 lines
2.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Туннели к ai-egress не раскручивают штраф sshd узла.
27.09.2026: 32 туннеля пула перезапускались одновременно каждые 5 с, sshd на
ai-egress (PerSourcePenalties) штрафовал наш IP за соединения без
аутентификации и отказывал всем туннелям — 296 перезапусков в час.
"""
from __future__ import annotations
import configparser
from pathlib import Path
import pytest
DEPLOY = Path(__file__).resolve().parent.parent / "deploy"
TUNNEL_UNITS = ("ytgrab-egress-pool@.service", "ytgrab-egress-tunnel.service")
def _service(name: str) -> configparser.SectionProxy:
parser = configparser.ConfigParser(strict=False, interpolation=None)
parser.optionxform = str
parser.read(DEPLOY / name, encoding="utf-8")
return parser["Service"]
@pytest.mark.parametrize("name", TUNNEL_UNITS)
def test_restarts_back_off(name):
service = _service(name)
assert service["Restart"] == "always"
assert int(service["RestartSteps"]) >= 1
max_delay = int(service["RestartMaxDelaySec"])
assert max_delay > int(service["RestartSec"])
assert max_delay >= 60
def test_pool_starts_are_staggered_per_instance():
pre = _service("ytgrab-egress-pool@.service")["ExecStartPre"]
# systemd раскрывает одиночный $ сам; литеральный — только как $$.
assert "$$((" in pre and "%i" in pre
def test_pool_keepalive_tolerates_a_short_stall():
start = _service("ytgrab-egress-pool@.service")["ExecStart"]
options = dict(
part.split("=", 1)
for part in start.split("-o ")[1:]
if "=" in part
)
interval = int(options["ServerAliveInterval"].split()[0])
count = int(options["ServerAliveCountMax"].split()[0])
assert interval * count >= 30
def test_pool_covers_the_configured_port_range():
target = (DEPLOY / "ytgrab-egress-pool.target").read_text(encoding="utf-8")
ports = [int(p) for p in range(18110, 18142)]
assert all(f"ytgrab-egress-pool@{port}.service" in target for port in ports)