Files
soleprint/rig/docs/notes/ports.md
2026-09-22 05:15:49 -03:00

2.8 KiB

ctrl/ports.sh

Why each environment gets a port block

New versions of a system mean new clusters on ONE machine, not new machines. Cluster name, kubectl context, registry container and image tag already derive from the directory name, so two copies never collide there, but host ports are a single shared namespace and would.

The block is derived from the directory name: stateless, stable, and requiring no coordination between copies that know nothing about each other.

base = 20000 + (hash(slug) % 200) * 10
  +0 HTTP   +1 HTTPS   +2 TILT   +3 REGISTRY   (+4..9 reserved)

20000+ deliberately avoids the ports something is already likely to hold: 80, 443, 3000, 5432, 8000, 8080.

Derivation is a default, not a decision. On first use the resolved block is written into ctrl/.env, so it becomes pinned, visible and editable rather than a number that appears from nowhere. Anything already in ctrl/.env wins.

active

The resolved facts a consumer outside bash needs, machine-readable:

CLUSTER KUBECONTEXT HTTP HTTPS TILT REGISTRY MANIFESTS_DIR OVERLAY_DIR

Identity and ports together, because they are one fact set: both derive from a folder name (the overlay's when one is named) so that copies never collide. A consumer needs all of them or none, and fetching them separately is how two end up disagreeing. MANIFESTS_DIR and OVERLAY_DIR ride along because the one consumer that needs the addressing is the one that needs to know what to deploy and whose Tiltfile to include.

The two paths are absolute, or - when there is none: an empty field would shift every later one. OVERLAY_DIR was appended rather than inserted, so readers that take fields by position kept their indexes.

Space-separated, so the paths must not contain whitespace; active refuses rather than print a line that splits wrong. Everything else in rig already assumes that of paths; kind, docker and kubectl all do.

persist, with an overlay

persist writes into ctrl/.env, which belongs to this rig, not to an overlay. With OVERLAY set, a block pinned there would follow every overlay this rig later runs, and two of them would then share ports — the collision the derivation exists to prevent. So it refuses and says so; an overlay's ports stay derived from its folder name.

derive answers a DIFFERENT question (what the directory name alone implies) and deliberately ignores ctrl/.env. Configuring anything from it would silently contradict the rule that "anything already in ctrl/.env wins". active is what anything downstream should read.

Why this exists at all: the cluster name is not the bare directory name. default_cluster_name() lowercases it and replaces every character outside [a-z0-9-], because it has to be a DNS label. Re-deriving that in another language is how a copy in My_Project/ ends up guarding the wrong context.