simpler check and deps messages
This commit is contained in:
158
rig/docs/notes/deps.md
Normal file
158
rig/docs/notes/deps.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# ctrl/deps.sh
|
||||
|
||||
## Purpose and safety
|
||||
|
||||
Toolchain installer: detect the host, install a pinned toolchain onto it, then report what it could not do.
|
||||
|
||||
It never runs the cluster, never uses sudo or apt, and writes only into `$OUT_BIN` (default `~/.local/bin`). Everything that would touch the host proper — systemd, inotify limits, `.wslconfig`, docker group — is REPORTED for a human to decide on, never performed. That is what makes it safe to run on a machine that already has a working setup.
|
||||
|
||||
## Usage
|
||||
|
||||
Normally via `make deps`, or directly:
|
||||
|
||||
```
|
||||
deps.sh detect # report host facts only, change nothing
|
||||
deps.sh list # the pinned versions
|
||||
deps.sh verify [core|dev] # run what is installed and see if it works
|
||||
deps.sh fetch [core|dev] [--to DIR] # download + verify into DIR
|
||||
deps.sh install [core|dev] # detect, fetch, install, report
|
||||
```
|
||||
|
||||
Tiers: `core` is kubectl + jq (talk to a cluster); `dev` adds kind and tilt. Default is dev.
|
||||
|
||||
## Container vs bare host
|
||||
|
||||
Runs both inside the installer container and bare on a host. Inside the container, host files are read through `$HOST_ROOT` (mount `/` as `:ro`); bare, it falls back to `/`.
|
||||
|
||||
Host FILES (`/etc/...`, `/mnt/c/...`) must be read through the mount. Kernel-level facts (kernel version, meminfo, inotify) are shared with the container, so the container's own view is already the host's.
|
||||
|
||||
## INVOKED_FROM
|
||||
|
||||
Keep the caller's cwd so a relative `--to` resolves where the user expects, not against `ctrl/` once we've moved.
|
||||
|
||||
## load_config
|
||||
|
||||
Pins arrive through `load_config` like every other setting, not by sourcing `versions.env` here. That is what lets `make standalone` freeze them into a one-file installer: configuration has exactly one way in.
|
||||
|
||||
## mb_of
|
||||
|
||||
A `/proc/meminfo` field in MB, 0 if the field is absent. `MEMINFO` exists so the tight and does-not-fit branches can be exercised against a real machine's numbers from somewhere else; in normal use it is always `/proc/meminfo`.
|
||||
|
||||
## require_amd64
|
||||
|
||||
The pins are amd64. Rather than download something that cannot execute and let it fail as "cannot execute binary file: Exec format error", say so here and hand over the commands that produce the right checksums.
|
||||
|
||||
## pkg_install_cmd
|
||||
|
||||
This never runs a package manager. It names one so the reported action is something you can paste, on the distro you are actually on — an apt line on Amazon Linux 2 is a wrong answer dressed up as help.
|
||||
|
||||
## require_linux
|
||||
|
||||
Windows outside WSL — Git Bash, MSYS, Cygwin — looks close enough to work and then fails in a pile of confusing ways: no /proc, no docker socket, none of the tooling. Detectable, so name it instead.
|
||||
|
||||
## detect: memory
|
||||
|
||||
In MB. Whole gigabytes lose nearly half a GB on exactly the machines where it matters: 1874 MB available used to print as "1 GB". Facts only — whether that is enough depends on the profile, which `check.sh` knows and this does not.
|
||||
|
||||
## detect: overcommit
|
||||
|
||||
How the kernel answers an allocation it cannot really satisfy. With 1 it always says yes and settles up later with the OOM killer, so a cluster that starts cleanly can still lose processes afterwards.
|
||||
|
||||
## detect_wsl: systemd
|
||||
|
||||
systemd is off by default in WSL, and the ingress/DNS paths that use a host service need it. Enabling it requires a Windows-side restart, which cannot be issued from inside the distro.
|
||||
|
||||
## watch_hostile_fs
|
||||
|
||||
Not a path check: `/mnt` is an ordinary mount point and an ext4 disk mounted there is perfectly fine. What matters is the filesystem. The Windows drives arrive as 9p (WSL2) or drvfs (WSL1); network and fuse mounts behave the same way. None of them deliver inotify events, so anything watching files goes quiet without saying why.
|
||||
|
||||
## detect_libc
|
||||
|
||||
tilt is the one binary here that needs a recent glibc. MEASURED, not guessed: tilt 0.37.6 on Amazon Linux 2 (glibc 2.26) fails with
|
||||
|
||||
```
|
||||
/lib64/libc.so.6: version `GLIBC_2.34' not found (required by .../tilt)
|
||||
```
|
||||
|
||||
which names a symbol rather than the problem. Amazon Linux 2 is a stock WorkSpaces bundle, so this is the likely case, not an exotic one. Report the version now; `verify` catches the actual failure after installing.
|
||||
|
||||
## detect_prereqs
|
||||
|
||||
What this script needs to do its own job. Reported here so `detect` answers "will install work?" instead of leaving you to find out one download in. Amazon Linux 2 ships without tar, which is exactly the surprise this catches.
|
||||
|
||||
## detect_docker
|
||||
|
||||
Reachability of the daemon is the real question, and the CLI is only how we ask it. When this runs inside the installer container, Docker necessarily exists on the host — otherwise nothing would be executing — so a missing CLI in there is an installer packaging bug, not a host problem.
|
||||
|
||||
The kind-node count check must be an `if`, not `[ ] && echo`: as the last statement in the function the latter returns 1 when the count is zero, and `set -e` then kills the caller. That is the fresh-machine case — no clusters yet — so the bug only ever shows up where it does most harm.
|
||||
|
||||
## fetch_tgz: --no-same-owner
|
||||
|
||||
Extracting as root would otherwise restore the uid/gid baked into the archive (some ship as uid 1001), leaving a binary the host user does not own.
|
||||
|
||||
## fix_ownership
|
||||
|
||||
The installer runs as root so it can reach the docker socket, which means everything it writes into a mounted volume lands root-owned and unusable from the host. Hand it back to whoever owns the mount point (the host user created that directory before mounting it).
|
||||
|
||||
kind writes the kubeconfig as root too; `fetch` hands that back as well when it's a mounted host directory rather than container-local state.
|
||||
|
||||
## Tiers (CORE_TOOLS, DEV_TOOLS)
|
||||
|
||||
Two tiers, because not every machine should get cluster tooling.
|
||||
|
||||
- `core` — kubectl, jq: talk to a cluster someone else runs. Nothing that creates one. Appropriate on a managed or corporate-issued machine where development tools are not wanted by default.
|
||||
- `dev` — core plus kind and tilt: build clusters and hot-reload into them.
|
||||
|
||||
The split exists because "install the toolchain" is not one decision: on a managed workspace the right answer is kubectl and nothing else.
|
||||
|
||||
No helm: every addon installs with `kubectl apply -f <url>`, so nothing here has ever invoked it. Add it back the day something actually needs a chart.
|
||||
|
||||
ctlptl is `dev` rather than `core` for the same reason kind is: core is "talk to a cluster someone else runs", and ctlptl builds them. It earns its place because it is what wires a cluster to a local registry — without one, an unqualified image name resolves to `docker.io/library/<name>` and there is nothing structural stopping a push there.
|
||||
|
||||
docker-compose is `dev` for the same reason, and is here because the distro docker packages ship the daemon and CLI but frequently not the compose plugin — so `docker compose up` fails with "unknown command" on an otherwise working Docker, and nothing about that message names the missing piece.
|
||||
|
||||
## What is already on this machine (pin_of)
|
||||
|
||||
A tool already on PATH at its pinned version is left where it is. Without this, install downloads a second copy into `OUT_BIN` and then reports the first one as shadowed — noise, and wrong, when both are the same version. That is the normal state of any machine someone set up by hand, whatever directory they happened to choose.
|
||||
|
||||
## reported_version
|
||||
|
||||
Each tool spells the version question differently, and kubectl has to be told `--client` or it goes looking for a server to ask.
|
||||
|
||||
## version_matches
|
||||
|
||||
Matched as a whole version token, so 0.37.6 never matches 10.37.60, with the leading v optional either side: kind says v0.32.0, jq says jq-1.8.2, and tilt says v0.37.6 against a pin of 0.37.6.
|
||||
|
||||
Bash's own regex rather than grep, deliberately. grep is not the same program on every machine — some builds reject patterns that others accept — and a failed grep inside a count reads exactly like a zero.
|
||||
|
||||
## want / DEPS_ONLY
|
||||
|
||||
`DEPS_ONLY` narrows a fetch to the tools it names. Unset means the whole tier, which is what an explicit `deps.sh fetch` always gets: "download these into DIR" must not quietly skip something because this machine happens to have it. Only `install()` sets it, to what `detect_toolchain` found missing or mismatched.
|
||||
|
||||
## detect_toolchain: compose
|
||||
|
||||
compose is the one tool that is normally NOT a binary on PATH. It is a docker CLI plugin, so a machine where `docker compose` works perfectly has no `docker-compose` to find — and probing only PATH would report it missing and re-download a copy that is already there. That is the exact noise the version-aware skip exists to prevent, so ask docker instead.
|
||||
|
||||
## verify_tools
|
||||
|
||||
Installing into a directory that sits early in PATH silently replaces whatever the machine was already using — which on a shared or client machine can break unrelated work (kubectl more than one minor away from a cluster is the common one). Say so; never decide it for them.
|
||||
|
||||
Downloading a verified binary proves it is the right file, not that this machine can run it. On an old distro tilt fails here, with a linker error about a missing symbol, and finding that out now beats finding out during a first cluster build.
|
||||
|
||||
Output is not piped into `head`. With `pipefail` set, a tool that prints more than one line gets SIGPIPE when head closes the pipe, and the pipeline reports 141 — so a working kubectl was announced as "does not run here", with its own correct version string as the evidence. The first line is taken afterwards, from the string.
|
||||
|
||||
## install_compose_plugin
|
||||
|
||||
A copy in `OUT_BIN` only gives you `docker-compose`. That hyphenated form is the retired v1 spelling; every compose file written in the last few years assumes `docker compose`, which resolves plugins BY NAME out of a plugin directory. So the binary is fetched like any other and then linked, in your own home — no root, and nothing outside it.
|
||||
|
||||
If something else already owns that name — docker-desktop and some distro packages install a real file there — overwriting it would take the plugin away from whatever put it there, so say so and let the user decide.
|
||||
|
||||
## install
|
||||
|
||||
The plugin is linked only when compose was one of the things fetched: linking a binary that is already satisfied elsewhere on PATH would point the plugin at a copy rig did not install.
|
||||
|
||||
The "put OUT_BIN on PATH" advice is only worth giving when something actually landed in `OUT_BIN`. When every tool was satisfied elsewhere, `OUT_BIN` may reasonably be off PATH, and telling the user to add it would be advice to fix nothing.
|
||||
|
||||
## main: argument shift
|
||||
|
||||
Read the command, THEN shift — and shift only if there is something there. A bare `shift` with no positional parameters returns 1, and under `set -e` that ended the script before a single line was printed: running this with no arguments at all, the documented default, did nothing and said nothing.
|
||||
Reference in New Issue
Block a user