Skip to content

refactor(BA-8675): add TraefikRoutingConfigFactory for ingresses - #16018

Merged
jopemachine merged 13 commits into
mainfrom
refactor/BA-8675-traefik-routing-config-factory
Oct 26, 2026
Merged

jopemachine merged 13 commits into
mainfrom
refactor/BA-8675-traefik-routing-config-factory

Conversation

@jopemachine

@jopemachine jopemachine commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Add TraefikRoutingConfigFactory (appproxy/coordinator/clients/worker/traefik/routing_config.py), which builds the Traefik routing configs of an ingress from the ingress types and exposes only two methods:
    • all_routing_config_etcd_keys(ingress_key): every router, service and middleware key an ingress can own, for clearing the ones it no longer has
    • routing_configs_by_etcd_key(ingress, *, hostname, wildcard_domain, tls_listen): the router, service and middleware configs of the ingress by the etcd key Traefik reads (worker_{authority}/{http|tcp}/{routers|services|middlewares}/{name})
  • The router rule is ClientIP for TCP, joined with || for several allowed client IPs as Traefik v3 matchers take one value each, and Host for HTTP; the HTTP router middleware order is CORSHeaders, then ipAllowList when there are allowed client IPs, then the appproxy-traefik-plugin auth plugin.
  • The configs are typed as TypedDicts with the keys Traefik reads in appproxy/coordinator/clients/worker/traefik/types.py (HttpRouterConfig, TcpRouterConfig, HttpServiceConfig, TcpServiceConfig, and the CORSHeaders, ipAllowList and auth plugin middleware configs); routing_configs_by_etcd_key returns dict[str, RoutingConfig].
  • The factory takes TraefikRoutingConfigFactoryArgs (the Traefik, secret and permit hash config sections) and reads the client IP strategy and the auth plugin secrets from them.
  • Add TraefikWildcardDomainMissingError.
  • Split out of feat(BA-8444): add the coordinator client that writes ingresses to Traefik etcd #15893, which writes these configs to Traefik etcd through TraefikWorkerClient and carries this module until this PR merges.

Test plan

  • test_traefik_routing_config.py: ipAllowList with no client IP strategy, a depth and excluded IPs; the TCP ClientIP rule with and without allowed client IPs
  • Traefik v3.7.9 accepts the joined ClientIP rule and rejects the comma form

Resolves #15989 (BA-8675)

🤖 Generated with Claude Code

The Traefik ingress export needs the router, service and middleware
configs of an ingress and the etcd keys Traefik reads them from. The
factory builds them from the ingress types in one place so the client
that writes them to etcd holds no Traefik naming or layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The factory keeps the `TraefikConfig` it is given and reads
`client_ip_strategy` from it when building an ipAllowList middleware,
instead of keeping only the `ClientIPStrategyConfig`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jopemachine
jopemachine marked this pull request as ready for review October 23, 2026 07:25
@jopemachine
jopemachine requested a review from a team as a code owner October 23, 2026 07:25
Copilot AI balanced review requested due to automatic review settings October 23, 2026 07:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

jopemachine and others added 5 commits October 23, 2026 16:30
`TraefikWorker` is the value the Traefik worker client builds from
service discovery and the routing config factory reads, so it lives in
its own module next to both instead of in the factory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It holds the worker's frontend settings a Traefik router needs (hostname,
wildcard domain, tls_listen), not a worker, so the type and the arguments
carrying it say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…listen separately

`WorkerFrontendSettings` grouped two worker API settings with the Traefik
wildcard domain under a made-up name. The factory now takes the three
values as keyword arguments and hands each private builder only the ones
it uses, and `clients/worker/types.py` is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tingConfigFactory

The factory receives the Traefik, secret and permit hash config sections
as one `TraefikRoutingConfigFactoryArgs` and reads the auth plugin
secrets from them, instead of taking the two secret strings separately.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fig_etcd_keys

It returns every routing config key an ingress can own, whether or not the
ingress uses it now, for clearing the ones it no longer has.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jopemachine
jopemachine marked this pull request as draft October 23, 2026 08:37
The router, service and middleware configs the factory returns are
`TypedDict`s (`TraefikHttpRouterConfig`, `TraefikTcpServiceConfig`,
`TraefikIpAllowListMiddlewareConfig`, ...) instead of `dict[str, Any]`,
with the keys Traefik reads. The written etcd keys and values are
unchanged. The tests compare each config as a whole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added size:XL 500~ LoC and removed size:L 100~500 LoC labels Oct 23, 2026
jopemachine and others added 2 commits October 23, 2026 17:46
Every TypedDict in traefik_routing_config describes a Traefik config, so
the module name already carries the prefix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ackage

Move the routing config module to clients/worker/traefik/routing_config.py and
its TypedDicts to clients/worker/traefik/types.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jopemachine
jopemachine marked this pull request as ready for review October 26, 2026 00:47
jopemachine added a commit that referenced this pull request Oct 26, 2026
… into a traefik package

Move clients/worker/traefik.py to clients/worker/traefik/client.py and the routing
config module to clients/worker/traefik/routing_config.py with its TypedDicts in
clients/worker/traefik/types.py, matching #16018.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread tests/unit/appproxy/coordinator/clients/worker/traefik/test_routing_config.py Outdated
jopemachine and others added 2 commits October 26, 2026 12:10
…ances

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jopemachine
jopemachine requested a review from wngh4628 October 26, 2026 04:01
@jopemachine
jopemachine requested a review from a team October 26, 2026 04:01
@jopemachine
jopemachine merged commit 7f8b8a8 into main Oct 26, 2026
34 checks passed
@jopemachine
jopemachine deleted the refactor/BA-8675-traefik-routing-config-factory branch October 26, 2026 05:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:app-proxy Related to App Proxy component size:XL 500~ LoC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build the Traefik routing configs of an ingress through TraefikRoutingConfigFactory

3 participants