feat(traefik): each router problem says what it means, whether it's real, and what to do (#5712)
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m22s
CI / unit (push) Failing after 1m33s
CI / publish (push) Skipped

#5712 "Each router problem says what it means, whether it's real, and what
to do". A problem card now names its kind and reads its codes:
- Server errors: 500 means the app is failing; 502/503/504 means Traefik
  couldn't reach it or it timed out.
- Client errors: 404 scanners, a 401/403 login wall, 429 rate limiting, or
  499 clients giving up on a slow app.
- Slow: p95 against p50.
Each card says whether the problem is likely real, and ends with one next
step. A fault links to the swarm service behind the router, matched by
name, and traffic links to Settings → Thresholds. The wording lives in
plugins/traefik/meaning.py.

The plugin manager now hands out a loaded plugin's submodule
(loaded_plugin_submodule), so Traefik and host_agent reach Docker's
models the same way (#5775).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 21:04:39 -04:00
co-authored by Claude Opus 5.5
parent 31a6cf09a9
commit 685850e681
7 changed files with 307 additions and 13 deletions
+15
View File
@@ -77,6 +77,21 @@ def get_loaded_plugin_modules() -> dict[str, object]:
return dict(_PLUGIN_MODULES)
def loaded_plugin_submodule(name: str, sub: str):
"""A loaded plugin's submodule (e.g. ("docker", "models")), or None when
the plugin isn't loaded. Another plugin reaches its models this way:
importing plugins.<name>.models by path would define its tables a second
time, because the plugin was loaded as _steward_plugin_<name> (#5775)."""
import importlib
loaded = _PLUGIN_MODULES.get(name)
if loaded is None:
return None
try:
return importlib.import_module(f"{loaded.__name__}.{sub}")
except ImportError:
return None
def _collect_plugin_module(app: "Quart", name: str, module) -> None:
"""Remember a loaded plugin module; hand it to a live MCP server if mounted.