feat(shared): expose shared services on stable localhost ports for GUI clients - #110
Merged
Conversation
…I clients `devstack shared expose [services...]` publishes the shared engines on stable 127.0.0.1 host ports so a developer's GUI clients — DataGrip/TablePlus, a Redis or S3 browser, the RabbitMQ management UI — can connect, without a duplicate stack per repo. `devstack shared ports` is the read-only projection (ports + connection strings); `shared expose --off` returns the stack to DNS-only. Design (spec 03 host-reachability): - Opt-in and loopback-only; the default is still "no host ports" (DNS over devstack_shared). Exposure is an UP-TIME compose overlay (compose.expose.yaml), so the deterministic, golden-asserted generated compose is untouched — same posture as the provisioning overlay. - Ports are ledger-allocated (FreeHostPort), stable across runs, and sit in a distinct 5xxxx range so the expose overlay and the 4xxxx provisioning overlay never publish the same host port (a duplicate binding). Kafka is the one deliberate exception: host clients must reach the fixed advertised 127.0.0.1:49092. - Persistent: the up saga re-applies the expose overlay so host ports survive up/down. Refused on a remote backend (a remote bridge is not host-routable). - Per engine it publishes the primary protocol port plus the useful secondary UI ports (MinIO console, RabbitMQ management, NATS monitor) and prints a client-ready connection string for each (the postgres admin DSN + a reminder that per-project DBs use the documented per-project dev creds). Tests: overlay write/read round-trip, instance resolution (all/named/rejects non-engines), per-engine connection URLs, the expose-vs-provision no-collision invariant, CLI table/JSON/quiet rendering, and command registration. Verified live on WSL2: `shared ports` projection, the overlay merges cleanly with the running shared compose (`docker compose config`), and a host psql client reaches shared-postgres on the published loopback port. Determinism/golden unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Requested from live testing: reach the shared engines (Postgres/MinIO/Redis/…) from host GUI clients like DataGrip, TablePlus, an S3 browser, or the RabbitMQ management UI — without a duplicate stack per repo.
Commands
devstack shared expose [services...]— publish the shared engines on stable127.0.0.1host ports. No args = every exposable engine; name services to scope it.devstack shared ports— read-only projection: ports + copy-paste connection strings (lock-free).devstack shared expose --off— back to DNS-only.Design (spec 03 host-reachability)
devstack_shared). Exposure is an up-time compose overlay (compose.expose.yaml) — the deterministic, golden-asserted generated compose is untouched (same posture as the provisioning overlay).FreeHostPort), stable across runs, in a distinct5xxxxrange so the expose overlay and the4xxxxprovisioning overlay never publish the same host port. Kafka is the one deliberate exception (host clients must use the fixed advertised127.0.0.1:49092). A unit test enforces the invariant.up/down. Refused on a remote backend (a remote bridge isn't host-routable).Example
Tests
shared portsprojection; the overlay merges cleanly with the running shared compose (docker compose config); a hostpsqlclient reaches shared-postgres on the published loopback port (HOST-CONNECT-OK PostgreSQL 18.4).orchestrate+clisuites green.🤖 Generated with Claude Code