diff --git a/rig/Makefile b/rig/Makefile index d276a96..34389fd 100644 --- a/rig/Makefile +++ b/rig/Makefile @@ -5,7 +5,6 @@ # bash file, and that file holds the variants: # # make cluster up -> ctrl/cluster.sh up -# make newbox destroy -> ctrl/newbox.sh destroy # # Config layers, weakest first: ctrl/versions.env (pinned toolchain) < # ctrl/env.d/.env (cluster shape) < ctrl/.env (local, gitignored) < @@ -52,7 +51,7 @@ $(eval $(ARGS):;@:) endif .PHONY: help setup check selftest mem deps deps-image pins cluster registry addons ports \ - newbox dockerhost docs tilt \ + docs tilt \ kind-up kind-down kind-reset tilt-up tilt-down help: ## list targets @@ -60,7 +59,7 @@ help: ## list targets # ── setup ────────────────────────────────────────────────────────────────── -setup: ## prepare this machine [core] [--share-docker] [--cluster] +setup: ## prepare this machine [core] [--cluster] bash ctrl/setup.sh $(ARGS) check: ## is this machine ready? reports, never fixes @@ -100,14 +99,6 @@ addons: ## profile addons [install|list] (default ports: ## this environment's port block [show|persist] bash ctrl/ports.sh $(or $(ARGS),show) -# ── host ─────────────────────────────────────────────────────────────────── - -newbox: ## throwaway environment [create|status|shell|destroy] - bash ctrl/newbox.sh $(or $(ARGS),status) - -dockerhost: ## share Docker between distros [status|share|unshare] - $(if $(filter share unshare,$(ARGS)),sudo ,)bash ctrl/dockerhost.sh $(or $(ARGS),status) - # ── docs + dev loop ──────────────────────────────────────────────────────── docs: ## documentation [serve|graphs] (default serve) diff --git a/rig/ctrl/dockerhost.sh b/rig/ctrl/dockerhost.sh deleted file mode 100755 index 5550815..0000000 --- a/rig/ctrl/dockerhost.sh +++ /dev/null @@ -1,272 +0,0 @@ -#!/usr/bin/env bash -# Share ONE Docker daemon across WSL distros, instead of running one per distro. -# -# Why this exists -# --------------- -# WSL2 distros share a kernel and a network stack. Two dockerd instances then -# contend over docker0 and iptables, which can disturb the daemon you actually -# depend on. Docker Desktop avoids this by running a single daemon in a -# dedicated distro and sharing its socket — this is the same idea, without -# Docker Desktop. -# -# So a throwaway rig box does NOT install Docker. It borrows the daemon from -# whichever distro is the designated host. That also makes the test more honest: -# rig never installs Docker anyway — Docker is its documented prerequisite. -# -# How -# --- -# /mnt/wsl is a tmpfs with `shared` mount propagation, visible to every distro -# in the WSL VM. The owning distro exposes its socket there; guests point -# DOCKER_HOST at it. Two ways, with different costs: -# -# share bind-mount the existing socket onto the shared tmpfs. -# Instant, and dockerd is NEVER restarted. Lasts until the -# next WSL shutdown. -# share --persist additionally install a systemd drop-in so dockerd listens -# there itself. Survives restarts, but requires one Docker -# restart now — which stops every container that has no -# restart policy, since live-restore is off by default. -# -# The bind mount is the default precisely because the persistent version's cost -# is paid on a machine that is already working. -# -# Reversibility is the whole design -# --------------------------------- -# `unshare` removes the bind mount (no restart) and, if present, the drop-in. -# The original systemd unit is never edited — only an additive drop-in file is -# ever created — so undoing is deletion, not repair. `status` always states -# which of the three roles a distro is in, in those words. -# -# Nothing here runs automatically. It does nothing until invoked. -# -# Usage: -# dockerhost.sh status # which distro owns Docker; what this one uses -# dockerhost.sh share # share it (bind mount, no daemon restart) -# dockerhost.sh share --persist # ...and survive WSL restarts (restarts Docker) -# dockerhost.sh unshare # undo it; this distro owns its Docker again -# dockerhost.sh use [--persist] # point THIS distro at the shared socket -set -euo pipefail - -SHARED_DIR=/mnt/wsl/shared-docker -SHARED_SOCK="$SHARED_DIR/docker.sock" -OWNER_FILE="$SHARED_DIR/OWNER" -DROPIN=/etc/systemd/system/docker.service.d/10-rig-shared-socket.conf -PROFILE_D=/etc/profile.d/rig-docker-host.sh - -distro_name() { echo "${WSL_DISTRO_NAME:-$(hostname)}"; } - -require_wsl() { - grep -qi microsoft /proc/version 2>/dev/null && return 0 - echo "dockerhost is WSL-only: it relies on /mnt/wsl being shared between distros." >&2 - exit 1 -} - -# ── status ───────────────────────────────────────────────────────────────── - -status() { - require_wsl - echo "distro $(distro_name)" - - if [ -f "$DROPIN" ] || mountpoint -q "$SHARED_SOCK" 2>/dev/null; then - echo "role SHARING — this distro's Docker is offered to other distros" - elif [ -n "${DOCKER_HOST:-}" ] && [ "${DOCKER_HOST}" = "unix://$SHARED_SOCK" ]; then - echo "role BORROWING — using another distro's Docker" - else - echo "role standalone — this WSL installation has the main host Docker" - fi - - echo - if [ -S "$SHARED_SOCK" ]; then - echo "shared sock $SHARED_SOCK (present)" - [ -f "$OWNER_FILE" ] && sed 's/^/ /' "$OWNER_FILE" - else - echo "shared sock none — no distro is sharing right now" - fi - - echo - echo "DOCKER_HOST ${DOCKER_HOST:-(unset — using /var/run/docker.sock)}" - if command -v docker >/dev/null 2>&1; then - echo "docker $(docker version --format '{{.Server.Version}}' 2>/dev/null || echo unreachable)" - else - echo "docker cli not installed" - fi -} - -# ── share / unshare (run on the host distro) ─────────────────────────────── - -# Default: expose the EXISTING socket by bind-mounting it onto the shared tmpfs. -# /mnt/wsl has `shared` propagation, so the mount is visible in other distros. -# -# The point of doing it this way is that dockerd is never restarted. Restarting -# it stops every container that has no restart policy (live-restore is off by -# default), which on a working machine means quietly killing whatever you had -# running. Not a trade worth making just to expose a socket. -# -# Cost: a bind mount does not survive a WSL VM shutdown. `--persist` adds the -# systemd drop-in as well, which does survive but needs that one restart. -share_bind() { - mkdir -p "$SHARED_DIR" - chmod 0755 "$SHARED_DIR" - - if mountpoint -q "$SHARED_SOCK" 2>/dev/null; then - echo "already bind-mounted at $SHARED_SOCK" - else - [ -S /var/run/docker.sock ] || { echo "no /var/run/docker.sock here" >&2; exit 1; } - # The target must exist as a file for a bind mount onto it. - [ -e "$SHARED_SOCK" ] || : > "$SHARED_SOCK" - mount --bind /var/run/docker.sock "$SHARED_SOCK" - echo "bind-mounted /var/run/docker.sock -> $SHARED_SOCK (no daemon restart)" - fi - - cat > "$OWNER_FILE" <&2; exit 1; } - - share_bind - - if [ "${1:-}" != "--persist" ]; then - echo - echo "This lasts until the next WSL shutdown. To make it survive, re-run with" - echo "--persist — but note that adds a systemd drop-in and RESTARTS Docker," - echo "which stops any container that has no restart policy." - return 0 - fi - - if [ -f "$DROPIN" ]; then - echo "drop-in already present — sharing persists across restarts." - return 0 - fi - - echo - echo "--persist: installing a systemd drop-in and restarting Docker." - echo "Containers without a restart policy will stop and will NOT come back." - docker ps --format ' {{.Names}} restart={{.HostConfig.RestartPolicy.Name}}' 2>/dev/null \ - || docker ps --format ' {{.Names}}' 2>/dev/null || true - echo - - local exec_line - exec_line=$(systemctl cat docker.service | grep -m1 '^ExecStart=') - if [ -z "$exec_line" ]; then - echo "could not read docker.service ExecStart — refusing to guess" >&2 - exit 1 - fi - - mkdir -p "$(dirname "$DROPIN")" "$SHARED_DIR" - # Additive only: blank the inherited ExecStart, then restate it verbatim - # with one extra -H. Nothing about the original unit is edited. - cat > "$DROPIN" < "$OWNER_FILE" <&2; exit 1; } - - local did=0 - - # The bind mount first: undoing it needs no restart, so a plain `share` - # is fully reversible without disturbing anything. - if mountpoint -q "$SHARED_SOCK" 2>/dev/null; then - umount "$SHARED_SOCK" - rm -f "$SHARED_SOCK" - echo " removed the bind mount (no restart needed)" - did=1 - fi - rm -f "$OWNER_FILE" - rmdir "$SHARED_DIR" 2>/dev/null || true - - if [ -f "$DROPIN" ]; then - rm -f "$DROPIN" - rmdir "$(dirname "$DROPIN")" 2>/dev/null || true - systemctl daemon-reload - systemctl restart docker - echo " removed the systemd drop-in and restarted Docker" - did=1 - fi - - if [ "$did" -eq 0 ]; then - echo "not sharing — this WSL installation already has the main host Docker." - return 0 - fi - - echo "restored: this WSL installation has the main host Docker again." - echo " (nothing else was changed; the original unit was never edited)" -} - -# ── use (run on a guest distro) ──────────────────────────────────────────── - -use() { - require_wsl - if [ ! -S "$SHARED_SOCK" ]; then - echo "no shared socket at $SHARED_SOCK" >&2 - echo "Run 'sudo bash ctrl/dockerhost.sh share' in the distro that owns Docker." >&2 - exit 1 - fi - - # Align the local docker group GID with the owner's, or the socket is - # unreadable here even though it is visible. - if [ -f "$OWNER_FILE" ] && [ "$(id -u)" -eq 0 ]; then - local gid; gid=$(awk '/docker gid:/ {print $3}' "$OWNER_FILE") - if [ -n "$gid" ]; then - if getent group docker >/dev/null; then - [ "$(getent group docker | cut -d: -f3)" = "$gid" ] || groupmod -g "$gid" docker - else - groupadd -g "$gid" docker - fi - fi - fi - - if [ "${1:-}" = "--persist" ]; then - [ "$(id -u)" -eq 0 ] || { echo "--persist needs root" >&2; exit 1; } - echo "export DOCKER_HOST=unix://$SHARED_SOCK" > "$PROFILE_D" - echo "persisted in $PROFILE_D" - fi - - echo "export DOCKER_HOST=unix://$SHARED_SOCK" -} - -case "${1:-status}" in - status) status ;; - share) shift; share "${1:-}" ;; - unshare) unshare_ ;; - use) shift; use "${1:-}" ;; - *) echo "usage: $0 [status|share|unshare|use [--persist]]" >&2; exit 1 ;; -esac diff --git a/rig/ctrl/hosts.tmpl b/rig/ctrl/hosts.tmpl deleted file mode 100644 index 41b44e7..0000000 --- a/rig/ctrl/hosts.tmpl +++ /dev/null @@ -1,15 +0,0 @@ -# /etc/hosts block for this environment. Rendered by newbox.sh; ${CLUSTER} and -# ${HTTP_PORT} are substituted. -# -# Hostnames are a convenience, not a requirement — every service is reachable at -# localhost: without any of this, which is why DNS is not touched by -# default. Add entries here as the model grows. -# -# On Windows the same block has to go in -# C:\Windows\System32\drivers\etc\hosts for a browser to resolve these. That -# file does NOT support wildcards, so every name must be listed explicitly. -# newbox.sh prints the block for you to paste rather than editing it. - -127.0.0.1 ${CLUSTER}.local -127.0.0.1 api.${CLUSTER}.local -127.0.0.1 docs.${CLUSTER}.local diff --git a/rig/ctrl/newbox.sh b/rig/ctrl/newbox.sh deleted file mode 100755 index 64d8ff1..0000000 --- a/rig/ctrl/newbox.sh +++ /dev/null @@ -1,316 +0,0 @@ -#!/usr/bin/env bash -# Create a disposable Linux environment to validate the installer from a -# genuinely clean slate — one that can be thrown away without touching the -# environment you actually work in. -# -# This is the ONLY host-aware file in the tree. Everything else needs just a -# Linux with Docker, which is what keeps other host types a later addition -# rather than a rewrite. -# -# On WSL it creates a second distro. There is no .bat and no PowerShell script: -# wsl.exe is callable from inside WSL, and wslpath converts the paths it wants. -# A machine with no WSL at all needs `wsl --install` run once by hand first — -# scripting a reboot-requiring Windows feature install is not worth it. -# -# Docker: borrowed by default, never installed twice -# -------------------------------------------------- -# WSL2 distros share one kernel and one network stack, so two dockerd instances -# contend over docker0 and iptables and can disturb the daemon you depend on. -# (That is why Docker Desktop runs one daemon in a dedicated distro and shares -# its socket rather than installing one per distro.) -# -# REUSE_DOCKER=1 (default) borrow the host distro's daemon over /mnt/wsl. -# Nothing is installed; nothing can conflict. -# Requires `ctrl/dockerhost.sh share` once on the -# distro that owns Docker. -# REUSE_DOCKER=0 install a second daemon in the new distro. Only -# if you specifically want to test a from-scratch -# Docker install, and not on a machine you need. -# -# Borrowing is also the more honest test: rig never installs Docker anyway — it -# is the documented prerequisite — so a clean box does not need its own to -# exercise everything rig actually does. -# -# Usage: newbox.sh create | destroy [--purge] | status | shell -set -euo pipefail -cd "$(dirname "$0")" - -source ./lib/config.sh -load_config - -REPO="$(cd .. && pwd)" - -# The distro is named after this environment, and that derived name is the ONLY -# thing this script will ever destroy. See guard_name(). -BOX="${BOX:-${CLUSTER}box}" -BOX_USER="${BOX_USER:-dev}" - -# Borrow the host distro's Docker rather than installing a second daemon. -REUSE_DOCKER="${REUSE_DOCKER:-1}" -SHARED_SOCK=/mnt/wsl/shared-docker/docker.sock - -WSL_EXE=/mnt/c/Windows/System32/wsl.exe - -# ── host detection ───────────────────────────────────────────────────────── - -require_wsl() { - if ! grep -qi microsoft /proc/version 2>/dev/null; then - cat >&2 <<'EOF' -newbox is WSL-only for now. - -If WSL is not installed, run `wsl --install` from an elevated Windows prompt -first — see "Starting from plain Windows" in README.md. - -On native Linux you do not need it: rig already isolates environments by -directory (own cluster, context, images and port block), so a second copy in a -second directory is the clean slate. To validate the installer itself against a -bare system, run ctrl/deps.sh against a stock Debian container instead. -EOF - exit 1 - fi - if [ ! -x "$WSL_EXE" ]; then - echo "wsl.exe not found at $WSL_EXE" >&2 - exit 1 - fi -} - -wsl_list() { "$WSL_EXE" -l -q 2>/dev/null | tr -d '\0\r'; } -box_exists() { wsl_list | grep -qx "$BOX"; } - -# `wsl --unregister` permanently deletes a distro's filesystem. The whole safety -# story is this function: only the name derived from this directory can ever be -# a target, so a typo or a stray argument cannot destroy the distro you work in. -guard_name() { - local derived="${CLUSTER}box" - if [ "$BOX" != "$derived" ]; then - echo "refusing: BOX='$BOX' is not the name derived from this directory ('$derived')." >&2 - echo "That guard exists because --unregister is irreversible." >&2 - exit 1 - fi - if [ -z "$CLUSTER" ] || [ "$BOX" = "box" ]; then - echo "refusing: empty environment name" >&2 - exit 1 - fi -} - -# ── create ───────────────────────────────────────────────────────────────── - -rootfs_path() { - local win_home; win_home=$(wslpath "$("$WSL_EXE" -d "$(wsl_list | head -1)" -e printf '%s' "$USERPROFILE" 2>/dev/null || true)" 2>/dev/null || true) - # Simpler and reliable: use the current user's Windows home via /mnt/c. - ls -d /mnt/c/Users/*/ 2>/dev/null | grep -viE '/(All Users|Default|Default User|Public)/$' | head -1 -} - -build_rootfs() { - local tar="$1" - if [ -f "$tar" ]; then - echo " rootfs cached: $(basename "$tar")" - return - fi - echo " exporting a stock Debian rootfs (cached for next time)" - local cid; cid=$(docker create debian:trixie-slim) - docker export "$cid" > "$tar" - docker rm -f "$cid" >/dev/null -} - -provision() { - echo " provisioning (root)" - local hosts_block - hosts_block=$(CLUSTER="$CLUSTER" HTTP_PORT="$HTTP_PORT" \ - envsubst < ./hosts.tmpl 2>/dev/null || sed "s/\${CLUSTER}/$CLUSTER/g" ./hosts.tmpl) - - # Piped as stdin rather than a second script file, the same shape as any - # remote provisioning heredoc. Everything here is idempotent so a failed run - # can simply be repeated. - "$WSL_EXE" -d "$BOX" -u root -- bash -s </dev/null - -if [ "$REUSE_DOCKER" = "1" ]; then - # Borrow the host distro's daemon: CLI only, no dockerd, nothing to - # conflict with. The GID must match the owner's or the shared socket is - # unreadable here even though it is visible. - install -m 0755 -d /etc/apt/keyrings - if [ ! -f /etc/apt/keyrings/docker.asc ]; then - curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc - chmod a+r /etc/apt/keyrings/docker.asc - fi - echo "deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \$(. /etc/os-release && echo \$VERSION_CODENAME) stable" \ - > /etc/apt/sources.list.d/docker.list - apt-get update -qq - apt-get install -y -qq docker-ce-cli >/dev/null - - echo "export DOCKER_HOST=unix://$SHARED_SOCK" > /etc/profile.d/rig-docker-host.sh - - if [ -f /mnt/wsl/shared-docker/OWNER ]; then - gid=\$(awk '/docker gid:/ {print \$3}' /mnt/wsl/shared-docker/OWNER) - if [ -n "\$gid" ]; then - getent group docker >/dev/null && groupmod -g "\$gid" docker || groupadd -g "\$gid" docker - fi - fi -else - # A second daemon. Only when deliberately testing a from-scratch install. - install -m 0755 -d /etc/apt/keyrings - if [ ! -f /etc/apt/keyrings/docker.asc ]; then - curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc - chmod a+r /etc/apt/keyrings/docker.asc - fi - echo "deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \$(. /etc/os-release && echo \$VERSION_CODENAME) stable" \ - > /etc/apt/sources.list.d/docker.list - apt-get update -qq - apt-get install -y -qq docker-ce docker-ce-cli containerd.io >/dev/null -fi - -id -u "$BOX_USER" >/dev/null 2>&1 || useradd -m -s /bin/bash "$BOX_USER" -usermod -aG sudo,docker "$BOX_USER" -echo "$BOX_USER ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/90-$BOX_USER -chmod 0440 /etc/sudoers.d/90-$BOX_USER - -# systemd is off by default in WSL, and Docker needs it. Takes effect on the -# next start of this distro, which is why create() terminates it below. -cat > /etc/wsl.conf < /etc/sysctl.d/99-rig.conf </dev/null; then - { echo ""; echo "# rig environment"; cat <<'HOSTS' -$hosts_block -HOSTS - } >> /etc/hosts -fi - -touch /etc/rig-provisioned -PROVISION -} - -create() { - require_wsl - guard_name - - local winhome; winhome=$(rootfs_path) - [ -n "$winhome" ] || { echo "could not locate the Windows user directory" >&2; exit 1; } - local tar="${winhome}rig-rootfs.tar" - local installdir="${winhome}WSL/${BOX}" - - echo "creating '$BOX'" - if [ "$REUSE_DOCKER" = "1" ]; then - echo " docker: borrowing the host distro's daemon (nothing installed)" - if [ ! -S "$SHARED_SOCK" ]; then - echo - echo " No shared socket yet. In the distro that owns Docker, run once:" - echo " sudo bash ctrl/dockerhost.sh share" - echo " That adds one systemd drop-in and nothing else; undo with 'unshare'." - echo " Continuing — the box will be created, but Docker won't work in it" - echo " until you do that." - fi - else - echo - echo " REUSE_DOCKER=0: installing a SECOND Docker daemon." - echo " WSL distros share a network stack, so this can disturb Docker in" - echo " the distro you work in. Ctrl-C now if that is a bad trade today." - echo - sleep 4 - fi - echo - - if box_exists; then - echo " distro already registered" - else - build_rootfs "$tar" - mkdir -p "$installdir" - "$WSL_EXE" --import "$BOX" "$(wslpath -w "$installdir")" "$(wslpath -w "$tar")" --version 2 - fi - - # Resumable: a partially-created box is finished rather than restarted. - if "$WSL_EXE" -d "$BOX" -u root -- test -f /etc/rig-provisioned 2>/dev/null; then - echo " already provisioned" - else - provision - echo " restarting the distro so systemd and group membership apply" - "$WSL_EXE" --terminate "$BOX" # ONLY this distro; never --shutdown - fi - - echo " copying rig in" - tar c -C "$REPO" --exclude=def --exclude=.git --exclude=ctrl/.env . \ - | "$WSL_EXE" -d "$BOX" -u "$BOX_USER" -- bash -lc "mkdir -p ~/rig && tar x -C ~/rig" - - echo - echo " docker: $("$WSL_EXE" -d "$BOX" -u "$BOX_USER" -- bash -lc 'systemctl is-active docker 2>/dev/null || echo inactive')" - echo - echo "next:" - echo " make newbox shell # a shell inside it" - echo " then: cd ~/rig && make check && make deps && make cluster up" - echo - echo "For a browser on Windows to resolve the hostnames, paste this into" - echo "C:\\Windows\\System32\\drivers\\etc\\hosts (it has no wildcard support):" - CLUSTER="$CLUSTER" envsubst < ./hosts.tmpl 2>/dev/null | grep -v '^#' | grep -v '^$' | sed 's/^/ /' -} - -# ── the rest ─────────────────────────────────────────────────────────────── - -destroy() { - require_wsl - guard_name - - if ! box_exists; then - echo "no distro '$BOX' to remove" - else - echo "about to PERMANENTLY delete the distro '$BOX' and its filesystem." - "$WSL_EXE" --terminate "$BOX" 2>/dev/null || true - "$WSL_EXE" --unregister "$BOX" - echo " unregistered" - fi - - local winhome; winhome=$(rootfs_path) - rm -rf "${winhome}WSL/${BOX}" 2>/dev/null || true - - if [ "${1:-}" = "--purge" ]; then - rm -f "${winhome}rig-rootfs.tar" - echo " cached rootfs removed" - fi -} - -status() { - require_wsl - echo "environment $CLUSTER" - echo "distro $BOX" - if box_exists; then - echo "registered yes" - echo "provisioned $("$WSL_EXE" -d "$BOX" -u root -- test -f /etc/rig-provisioned 2>/dev/null && echo yes || echo no)" - echo "docker $("$WSL_EXE" -d "$BOX" -u root -- bash -lc 'systemctl is-active docker 2>/dev/null' || echo unknown)" - echo "rig copied $("$WSL_EXE" -d "$BOX" -u "$BOX_USER" -- bash -lc 'test -f ~/rig/Makefile && echo yes || echo no' 2>/dev/null)" - else - echo "registered no" - fi - echo - echo "all distros (this one is never touched unless it is '$BOX'):" - wsl_list | sed 's/^/ /' -} - -shell() { - require_wsl - box_exists || { echo "no distro '$BOX' — run 'make newbox' first" >&2; exit 1; } - "$WSL_EXE" -d "$BOX" -u "$BOX_USER" --cd '~' -} - -case "${1:-status}" in - create) create ;; - destroy) shift; destroy "${1:-}" ;; - status) status ;; - shell) shell ;; - *) echo "usage: $0 [create|destroy [--purge]|status|shell]" >&2; exit 1 ;; -esac diff --git a/rig/ctrl/selftest.sh b/rig/ctrl/selftest.sh index f954d32..c4954e0 100755 --- a/rig/ctrl/selftest.sh +++ b/rig/ctrl/selftest.sh @@ -168,6 +168,26 @@ check "guards on the variable" "1" "$(grep -c 'allow_k8s_contexts(CTX)' Tiltfil check "asks ports.sh for facts" "1" "$(grep -c "local('bash ports.sh active'" Tiltfile)" +note "the standalone Makefile only calls real verbs" +# That file exists so nothing wrapping these scripts has to GUESS how to call +# them. A generated Makefile once did guess: `rigmini.sh on`, which is not a +# verb, and a bare `rigdeps.sh` for "check and report", which installs. So each +# target's default verb must be one the script's own dispatch accepts — read +# from the script's `case`, not from a list here that could drift from it. +verbs_of() { + sed -n '/^case "\$cmd" in/,/^esac/p' "$1" | grep -oE '^ [a-z]+\)' | tr -d ' )' +} +for pair in deps:rigdeps.sh mem:rigmini.sh; do + target=${pair%%:*}; script=${pair##*:} + verb="$(make --no-print-directory -s -n -f ../standalone/Makefile "$target" 2>/dev/null \ + | awk -v s="$script" 'index($0, s) { print $NF; exit }')" + check "make $target -> $script ${verb:-?}, a verb it accepts" "yes" \ + "$(verbs_of "../standalone/$script" | grep -qx "$verb" && echo yes || echo "no: '$verb'")" +done +check "no \`mini\` target, which already means minimal footprint" "0" \ + "$(grep -cE '^mini:' ../standalone/Makefile)" + + note "optional — needs tilt and this rig's cluster" # Parsing the Tiltfile for real is the only way to know it still evaluates, but # Tilt snapshots a kubectl context before parsing, so it cannot run without a diff --git a/rig/ctrl/setup.sh b/rig/ctrl/setup.sh index 878e5e0..fd496f4 100755 --- a/rig/ctrl/setup.sh +++ b/rig/ctrl/setup.sh @@ -11,13 +11,9 @@ # an unfamiliar machine, the full picture is the whole point. Failures are # collected and reported together, and the exit code reflects the worst outcome. # -# The same script runs inside a fresh throwaway distro (newbox), so the -# provisioning path and the everyday path cannot drift apart. -# # Usage: # setup.sh # host checks + the dev toolchain # setup.sh core # kubectl and jq only — no cluster tooling -# setup.sh --share-docker # ...and offer this distro's Docker to others # setup.sh --cluster # ...and bring the cluster up set -euo pipefail cd "$(dirname "$0")" @@ -25,7 +21,6 @@ cd "$(dirname "$0")" source ./lib/config.sh load_config -WITH_SHARE=0 WITH_CLUSTER=0 # Cluster tooling is not wanted everywhere: a managed or corporate-issued # machine may legitimately want kubectl and nothing that builds clusters. @@ -33,7 +28,6 @@ TIER=dev for a in "$@"; do case "$a" in core|dev) TIER="$a" ;; - --share-docker) WITH_SHARE=1 ;; --cluster) WITH_CLUSTER=1 ;; *) echo "unknown option: $a" >&2; exit 1 ;; esac @@ -143,33 +137,6 @@ step_docker() { fi } -step_share_docker() { - if [ "$WITH_SHARE" -ne 1 ]; then - record docker-share skip "not requested (--share-docker)" - return - fi - if ! grep -qi microsoft /proc/version 2>/dev/null; then - record docker-share skip "not WSL — sharing only applies between WSL distros" - return - fi - if [ -f /etc/systemd/system/docker.service.d/10-rig-shared-socket.conf ]; then - record docker-share already "this distro is offering its Docker to others" - return - fi - # Needs root, and asking mid-script is worse than telling the user the - # single command to run. - if [ "$(id -u)" -ne 0 ] && ! sudo -n true 2>/dev/null; then - record docker-share manual "run: sudo bash ctrl/dockerhost.sh share" - return - fi - if sudo bash ./dockerhost.sh share >/tmp/rig-share.$$ 2>&1; then - record docker-share done "this distro now owns the shared Docker" - rm -f "/tmp/rig-share.$$" - else - record docker-share fail "see /tmp/rig-share.$$" - fi -} - step_ports() { local busy="" for entry in "HTTP:$HTTP_PORT" "HTTPS:$HTTPS_PORT" "TILT:$TILT_PORT" "REGISTRY:$REGISTRY_PORT"; do @@ -215,7 +182,6 @@ step_host step_toolchain step_path step_docker -step_share_docker step_ports step_cluster diff --git a/rig/docs/index.html b/rig/docs/index.html index 71e890f..dde3a27 100644 --- a/rig/docs/index.html +++ b/rig/docs/index.html @@ -298,7 +298,6 @@ make cluster up # build the cluster for the active profile
make setup                  # host + toolchain
-make setup --share-docker   # ...and offer this machine's Docker to other distros
 

3 · make cluster up

@@ -325,7 +324,6 @@ make cluster reset # destroy and rebuild — the on
make cluster list
Every cluster on the machine, its memory cost and its port block. The usual reason a new one will not start is an old one you forgot about; make cluster free frees them without deleting.
make ports
This environment's port block, and whether each is derived or overridden.
make registry
Which of the four registry modes is active, and where it points.
-
make dockerhost
Which WSL distro owns Docker and what this one is using.

Running more than one

diff --git a/rig/standalone/Makefile b/rig/standalone/Makefile new file mode 100644 index 0000000..15e7fc3 --- /dev/null +++ b/rig/standalone/Makefile @@ -0,0 +1,43 @@ +# Optional shorthand for the two standalone scripts. They run without it: +# `bash rigdeps.sh detect` and `bash rigmini.sh status` are the whole interface, +# and this file only spells those out so nobody has to guess them. +# +# Guessing is what went wrong before. A Makefile generated around these scripts +# invented `make mini` -> `rigmini.sh on`, a verb that does not exist, and a bare +# `rigdeps.sh` for "check and report", which actually installs. So every target +# here calls only a verb the script accepts, and ctrl/selftest.sh checks that. +# +# Works wherever the three files sit together — the scripts are found beside +# this Makefile, not in the current directory, so `make -f path/Makefile` works. +# +# Usage: +# make deps report the host and toolchain; changes nothing +# make deps install [dev] download, verify and install into ~/.local/bin +# make mem advertised memory and what caps it; safe +# make mem push allocates until it stops — not on a box you need + +HERE := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) + +# Words after the target become the script's verb and arguments. +ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)) +ifneq ($(ARGS),) +$(eval $(ARGS):;@:) +.PHONY: $(ARGS) +endif + +.DEFAULT_GOAL := help +.PHONY: help deps mem + +help: ## list targets + @grep -hE '^[a-z][a-z-]*:.*?##' $(MAKEFILE_LIST) | sed 's/:.*##/\t/' | expand -t16 + +# Defaults to `detect`, not `install`: on a machine you are still evaluating, +# the bare command should report. Installing is a word you type. +deps: ## toolchain [detect|list|verify|install|fetch] (default detect) + bash $(HERE)rigdeps.sh $(or $(ARGS),detect) + +# `mem`, matching the full rig's `make mem`, and deliberately NOT `mini`: that +# word already means "minimal footprint" in the projects that use this, and one +# name pointing at two jobs is how the invented target happened. +mem: ## memory and its caps [status|push|all] (default status) + bash $(HERE)rigmini.sh $(or $(ARGS),status) diff --git a/rig/standalone/README.md b/rig/standalone/README.md index d24abe5..a5aa7a5 100644 --- a/rig/standalone/README.md +++ b/rig/standalone/README.md @@ -39,6 +39,20 @@ bash rigmini.sh status # advertised memory and caps; safe bash rigmini.sh push # allocates until it stops — not on a machine you need ``` +The `Makefile` beside them is **optional shorthand** for exactly those calls — +copy it along or don't; the scripts do not need it: + +```bash +make deps # = rigdeps.sh detect (reports; installing is `make deps install`) +make mem # = rigmini.sh status +``` + +If you wrap these scripts in a Makefile of your own, copy the calls from that +file rather than guessing them. `rigmini.sh` measures memory; it has no `on` or +`off`, and toggling a heavy service off for a smaller footprint is a job for the +project's own manifests, not for this script. `make selftest` in the full rig +fails if this Makefile ever calls a verb its script does not accept. + If an earlier setup already put these tools in some other directory on PATH, remove that directory and the line that added it — do not rely on `install` to notice. It only reports shadowing once `~/.local/bin` is itself on PATH, which on