feat(cloudflare): TunnelRoute — per-app tunnel ingress (G1)#157
Merged
Conversation
Add a TunnelRoute kind so "expose one app publicly" is a self-contained
per-app unit instead of hand-editing a shared Tunnel's ingress list.
A Tunnel's ingress is a single ordered list, so managing it from N per-app
resources would clobber (last-writer-wins). TunnelRoute contributes ONE
host-scoped rule ({tunnel, hostname, service, path?}) via a read-modify-
write keyed by hostname: mergeIngressRule upserts this app's rule and keeps
a single trailing catch-all; removeIngressRule (on delete) pulls just its
rule. So many apps share one tunnel, each owning its own resource. Get
probes the live tunnel config for its hostname.
Pair with the app's CNAME DNSRecord ($ref the Tunnel's status.cnameTarget,
#139); examples/expose-app.yaml shows the pair.
Decided model C (a real primitive) per the K5 homelab-PaaS scope over a
documented-pattern or a clobber-prone composite. #TunnelRoute schema;
dispatch wired in Apply/Get/Delete/Handshake.
Concurrency caveat (documented): routes to the SAME tunnel should apply
serially — the shared-config RMW is last-write-wins.
Tests (fake CF API): mergeIngressRule/removeIngressRule (upsert-by-hostname,
catch-all invariant), and end-to-end aggregation (two routes coexist on one
tunnel, delete leaves the other, get Ready then NotFound). Not yet validated
against a real Cloudflare account.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
G1 — expose-app (model C: TunnelRoute)
You asked what G1 was deciding; given the ratified homelab-PaaS scope (K5), I built the real primitive rather than docs. A Cloudflare Tunnel's ingress is one ordered list, so managing it from N per-app resources would clobber (last-writer-wins).
TunnelRoutesolves that: each app contributes ONE host-scoped rule to a named Tunnel via a read-modify-write keyed by hostname.mergeIngressRuleupserts this app's rule (keyed by hostname) and keeps a single trailing catch-all;removeIngressRule(delete) pulls just its rule. So many apps share one tunnel, each owning its own resource — no clobbering. Both are pure/deterministic.#TunnelRouteschema; dispatch wired in Apply/Get/Delete/Handshake.examples/expose-app.yamlshows the per-app pair.Why model C
Model A (docs) is still "two places, shared edits"; model B (one composite owning the tunnel) clobbers on the shared ingress list. C makes "expose an app" a self-contained per-app unit — the right PaaS primitive.
Caveat
Documented: routes to the same tunnel should apply serially (the shared-config RMW is last-write-wins). Not yet validated against a real Cloudflare account (needs a token) — unit-tested against the fake CF API.
Tests
mergeIngressRule/removeIngressRule(upsert-by-hostname, catch-all invariant), and end-to-end aggregation (two routes coexist on one tunnel, deleting one leaves the other, Get Ready→NotFound).Local CI: build,
go test ./...(+-raceon cloudflare), gofmt, vet, staticcheck, golangci-lint (0 issues), modernize — all green. (Stray build binary removed before commit.)