250 lines
8.3 KiB
Bash
Executable File
250 lines
8.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Prepare a machine to run rig, and say plainly what worked, what was already
|
|
# done, and what is left for a human.
|
|
#
|
|
# This is the grouped entry point: `make setup`. Every step is idempotent and
|
|
# independently checked, so running it twice is safe and running it on a
|
|
# half-configured machine finishes the job rather than starting over.
|
|
#
|
|
# It deliberately does NOT abort on the first failure. A setup script that dies
|
|
# at step 2 hides the fact that steps 4 and 5 were also going to fail — and on
|
|
# 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")"
|
|
|
|
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.
|
|
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
|
|
done
|
|
|
|
if [ "$TIER" = "core" ] && [ "$WITH_CLUSTER" -eq 1 ]; then
|
|
echo "core tier installs no cluster tooling, so --cluster cannot work" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ── step framework ─────────────────────────────────────────────────────────
|
|
# Statuses are deliberately distinct: "already" and "done" both mean success but
|
|
# tell you very different things about the machine you are on.
|
|
STEP_NAMES=()
|
|
STEP_STATUS=()
|
|
STEP_NOTE=()
|
|
WORST=0
|
|
|
|
record() {
|
|
STEP_NAMES+=("$1"); STEP_STATUS+=("$2"); STEP_NOTE+=("${3:-}")
|
|
# Only a genuine failure is a non-zero exit. "manual" means the machine is
|
|
# fine and you have something to do — reporting that as an error makes the
|
|
# whole run look broken and trains people to ignore the output.
|
|
[ "$2" = "fail" ] && WORST=1 || true
|
|
local mark
|
|
case "$2" in
|
|
already) mark=" ok " ;;
|
|
done) mark=" done " ;;
|
|
skip) mark=" skip " ;;
|
|
manual) mark="MANUAL" ;;
|
|
fail) mark=" FAIL " ;;
|
|
esac
|
|
printf "[%s] %-22s %s\n" "$mark" "$1" "${3:-}"
|
|
}
|
|
|
|
# ── steps ──────────────────────────────────────────────────────────────────
|
|
|
|
step_host() {
|
|
local out
|
|
if ! out=$(bash ./deps.sh detect 2>&1); then
|
|
record host fail "detection failed"
|
|
return
|
|
fi
|
|
# Anything flagged with '!' needs a human; surface the count here
|
|
# and the detail below rather than burying it.
|
|
local warns; warns=$(echo "$out" | grep -c '^\s*!' || true)
|
|
HOST_DETAIL="$out"
|
|
if [ "$warns" -gt 0 ]; then
|
|
record host manual "$warns item(s) need attention — see below"
|
|
else
|
|
record host already "no problems detected"
|
|
fi
|
|
}
|
|
|
|
step_toolchain() {
|
|
local want="kubectl jq"
|
|
[ "$TIER" = "dev" ] && want="$want kind tilt"
|
|
|
|
local missing=""
|
|
for b in $want; do
|
|
command -v "$b" >/dev/null 2>&1 || missing="$missing $b"
|
|
done
|
|
|
|
if [ -z "$missing" ]; then
|
|
record toolchain already "$TIER: $want"
|
|
return
|
|
fi
|
|
|
|
if bash ./deps.sh install "$TIER" >/tmp/rig-deps.$$ 2>&1; then
|
|
local still=""
|
|
for b in $want; do
|
|
[ -x "${OUT_BIN:-$HOME/.local/bin}/$b" ] || still="$still $b"
|
|
done
|
|
if [ -n "$still" ]; then
|
|
record toolchain fail "still missing:$still (see /tmp/rig-deps.$$)"
|
|
else
|
|
record toolchain done "$TIER, installed:$missing"
|
|
rm -f "/tmp/rig-deps.$$"
|
|
fi
|
|
else
|
|
record toolchain fail "install failed — see /tmp/rig-deps.$$"
|
|
fi
|
|
}
|
|
|
|
step_path() {
|
|
local bin="${OUT_BIN:-$HOME/.local/bin}"
|
|
case ":$PATH:" in
|
|
*":$bin:"*) ;;
|
|
*) record path manual "add to ~/.bashrc: export PATH=\"$bin:\$PATH\""; return ;;
|
|
esac
|
|
if grep -qs "$bin" "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null; then
|
|
record path already "$bin on PATH and persisted"
|
|
else
|
|
record path manual "on PATH now, but not persisted in ~/.bashrc"
|
|
fi
|
|
}
|
|
|
|
step_docker() {
|
|
if ! command -v docker >/dev/null 2>&1; then
|
|
record docker fail "no docker cli — this is the one prerequisite rig cannot install"
|
|
return
|
|
fi
|
|
if docker info >/dev/null 2>&1; then
|
|
record docker already "$(docker version --format '{{.Server.Version}}' 2>/dev/null)"
|
|
else
|
|
record docker fail "daemon unreachable (in the docker group? logged out and back in?)"
|
|
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
|
|
local p="${entry#*:}"
|
|
if command -v ss >/dev/null 2>&1 && ss -ltn "sport = :$p" 2>/dev/null | grep -q LISTEN; then
|
|
busy="$busy ${entry%%:*}($p)"
|
|
fi
|
|
done
|
|
if [ -n "$busy" ]; then
|
|
record ports fail "in use:$busy — override in ctrl/.env or rename the directory"
|
|
else
|
|
record ports already "$HTTP_PORT-$REGISTRY_PORT free"
|
|
fi
|
|
}
|
|
|
|
step_cluster() {
|
|
if [ "$TIER" = "core" ]; then
|
|
record cluster skip "core tier — no cluster tooling on this machine"
|
|
return
|
|
fi
|
|
if [ "$WITH_CLUSTER" -ne 1 ]; then
|
|
record cluster skip "not requested (--cluster)"
|
|
return
|
|
fi
|
|
if kind get clusters 2>/dev/null | grep -qx "$CLUSTER"; then
|
|
record cluster already "'$CLUSTER' exists"
|
|
return
|
|
fi
|
|
if bash ./cluster.sh up >/tmp/rig-cluster.$$ 2>&1; then
|
|
record cluster done "'$CLUSTER' created"
|
|
rm -f "/tmp/rig-cluster.$$"
|
|
else
|
|
record cluster fail "see /tmp/rig-cluster.$$"
|
|
fi
|
|
}
|
|
|
|
# ── run ────────────────────────────────────────────────────────────────────
|
|
|
|
echo "setting up '$CLUSTER'"
|
|
echo
|
|
HOST_DETAIL=""
|
|
step_host
|
|
step_toolchain
|
|
step_path
|
|
step_docker
|
|
step_share_docker
|
|
step_ports
|
|
step_cluster
|
|
|
|
echo
|
|
if [ -n "$HOST_DETAIL" ]; then
|
|
echo "host detail"
|
|
echo "$HOST_DETAIL" | sed 's/^/ /'
|
|
echo
|
|
fi
|
|
|
|
# Repeat only what still needs action, so the tail of the output is a to-do list
|
|
# rather than a transcript.
|
|
outstanding=0
|
|
for i in "${!STEP_NAMES[@]}"; do
|
|
case "${STEP_STATUS[$i]}" in
|
|
fail|manual)
|
|
[ "$outstanding" -eq 0 ] && echo "outstanding:"
|
|
outstanding=1
|
|
printf " %-8s %-16s %s\n" "${STEP_STATUS[$i]}" "${STEP_NAMES[$i]}" "${STEP_NOTE[$i]}"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ "$outstanding" -eq 0 ]; then
|
|
echo "ready. next: make cluster up && make docs"
|
|
else
|
|
echo
|
|
echo "(nothing was aborted — every step ran so the list above is complete)"
|
|
fi
|
|
|
|
exit "$WORST"
|