Some checks failed
ci/crow/manual/retire-slot Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/auto-apply-patches Pipeline was successful
ci/crow/cron/weekly-audit-missing/1 Pipeline was successful
ci/crow/cron/weekly-audit-missing/2 Pipeline was successful
ci/crow/cron/weekly-audit-missing/4 Pipeline was successful
ci/crow/cron/weekly-audit-missing/5 Pipeline was successful
ci/crow/cron/weekly-audit-missing/9 Pipeline was successful
ci/crow/cron/weekly-audit-missing/10 Pipeline was successful
ci/crow/cron/weekly-audit-missing/6 Pipeline was successful
ci/crow/cron/weekly-audit-missing/7 Pipeline was successful
ci/crow/cron/weekly-audit-missing/8 Pipeline was successful
ci/crow/cron/weekly-audit-missing/3 Pipeline was successful
ci/crow/cron/weekly-audit-missing/11 Pipeline was successful
ci/crow/cron/weekly-audit-missing/12 Pipeline was successful
ci/crow/cron/weekly-audit-missing/13 Pipeline was successful
ci/crow/cron/weekly-audit-missing/14 Pipeline was successful
ci/crow/cron/trial-build-registry/3 Pipeline was successful
ci/crow/cron/trial-build-registry/5 Pipeline was successful
ci/crow/cron/trial-build-registry/2 Pipeline was successful
ci/crow/cron/trial-build-registry/14 Pipeline was successful
ci/crow/cron/trial-build-registry/16 Pipeline was successful
ci/crow/cron/trial-build-registry/12 Pipeline was successful
ci/crow/cron/trial-build-registry/15 Pipeline was successful
ci/crow/cron/trial-build-registry/7 Pipeline was successful
ci/crow/cron/trial-build-registry/9 Pipeline was successful
ci/crow/cron/trial-build-registry/4 Pipeline failed
ci/crow/cron/trial-build-registry/13 Pipeline was successful
ci/crow/cron/trial-build-registry/11 Pipeline was successful
ci/crow/cron/trial-build-registry/6 Pipeline was successful
ci/crow/cron/trial-build-registry/1 Pipeline was successful
ci/crow/cron/trial-build-registry/10 Pipeline was successful
ci/crow/cron/trial-build-registry/8 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/14 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/17 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/15 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/5 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/20 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/21 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/19 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/16 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/7 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/1 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/27 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/25 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/31 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/6 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/9 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/33 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/3 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/26 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/18 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/32 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/11 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/4 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/6 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/38 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/22 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/37 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/23 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/39 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/24 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/29 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/1 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/13 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/5 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/2 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/2 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/8 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/28 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/30 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/10 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/36 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/34 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/35 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/12 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/40 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/41 Pipeline was successful
ci/crow/cron/weekly-rebuild-missing/42 Pipeline was successful
ci/crow/cron/weekly-rebuild-reindex/14 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/1 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
## Why
Retiring a slot means three separate things in three separate places, and nothing tied them together.
Alpine 3.22 is what that costs.
It was removed from `local.rpkgs_slots` in `cdn.tf` at some point, so the edge stopped routing it, but it kept:
- a matrix row in **twelve** pipelines
- **six** cron jobs on the Crow server
- roughly **50000 objects** in the bucket
Nightly builds kept producing binaries nobody could reach.
Worse, an unrouted slot is not inert: every request falls through to the flat index, so R 4.4 and R 4.6 clients got `LOAD_FAILED` at `dyn.load()` rather than simply nothing.
It took a fleet-wide `verify_routing=all` run to notice.
## What changed
**`local/check-slots.R`** (`just check-slots`) fails when any `.crow/*.yaml` still targets a slot missing from `local.rpkgs_slots`.
`cdn.tf` stays the source of truth; the checker reads it rather than restating the list.
**`local/retire-slot.R`** (`just retire-slot <codename>`) does the cleanup:
- strips the slot from every pipeline matrix, dropdown option and `OS_VERSION` tag, and moves a dropdown default that pointed at the retired tag
- deletes `amd64/<codename>/` and `arm64/<codename>/` from the bucket
- prints the cron jobs that are left, with the API call, since they live on the Crow server and cannot be removed from here
Dry run by default.
It refuses any slot still listed in `cdn.tf`, so it cannot be pointed at a live slot however it is invoked.
**`.crow/retire-slot.yaml`** runs the asset half in CI, where the B2 credentials exist.
**README** gains a `## Retiring a slot` section with the ordering.
Step 4 before step 2 is the one ordering that actively breaks things: the next nightly rebuilds everything just deleted.
## Verification
Both scripts were run against the tree as it stood at `523424b`, immediately before #213.
The checker names exactly the twelve files that PR edited by hand:
```
.crow/archive-missed-packages.yaml targets unpublished: alpine322
.crow/backfill-flat-safety.yaml targets unpublished: alpine-322
.crow/process-updates.yaml targets unpublished: alpine-322, alpine322
...
12 file(s) target a slot the edge does not route.
```
`retire-slot.R alpine322 --config-only --apply` reproduces that commit's structural changes byte for byte across all 18 pipeline files, and additionally catches the two `OS_VERSION` dropdowns.
The only differences from the hand-made commit are two prose lines, a usage example and a dropdown `description:`, which the script deliberately leaves alone.
Guards exercised: a live slot (`alpine323`) is refused, an unknown codename is rejected by name, and the asset half refuses to run without `B2_S3_ACCESS_KEY` rather than treating B2's empty unauthenticated listing as an already-clean slot.
`crow lint .crow/` reports all 19 configs valid.
`air` and `jarl` are clean on both new scripts.
## Next
`alpine321` and `alpine322` still hold objects in the bucket (22922 and 25308 records respectively, both architectures).
Once this merges they can be removed with the pipeline this PR adds.
Reviewed-on: #214
97 lines
4.2 KiB
Makefile
97 lines
4.2 KiB
Makefile
# Local helpers for build-cran-binaries.
|
|
#
|
|
# `rebuild` (re)builds specific versions of a single package on a given OS/arch
|
|
# by dispatching to a remote buildx builder (the build runs there, not locally).
|
|
# Sensitivity is auto-detected: risky packages land in the per-minor slot
|
|
# (contrib/<x.y>/), everything else in the generic slot; the touched index is
|
|
# refreshed so the result is immediately servable.
|
|
#
|
|
# Prerequisites:
|
|
# - buildx builders named `artemis` (amd64) and `gaia` (arm64), created with the
|
|
# docker-container driver (runs BuildKit on the remote host's docker daemon over
|
|
# SSH). The default `remote` driver does NOT work with an ssh:// docker host.
|
|
# Pass --config docker/buildkitd.toml so BuildKit's GC keeps a usable cache
|
|
# (the default caps the cache-mount tier at 512 MB, forcing re-downloads).
|
|
# docker buildx create --name artemis --driver docker-container --config docker/buildkitd.toml ssh://<user@host-amd64>
|
|
# docker buildx create --name gaia --driver docker-container --config docker/buildkitd.toml ssh://<user@host-arm64>
|
|
# - exported secrets: B2_S3_ACCESS_KEY, B2_S3_SECRET_KEY, PGPASS (GITHUB_PAT optional)
|
|
#
|
|
# Overridable (env or `just VAR=… rebuild …`):
|
|
# R_VERSION (default 4.5.3) — selects the R minor → the per-minor slot
|
|
# AMD64_BUILDER / ARM64_BUILDER — buildx builder names
|
|
#
|
|
# Examples:
|
|
# just rebuild alpine 3.23 amd64 rlang 1.1.4 1.1.3
|
|
# just rebuild redhat 10 arm64 data.table 1.15.4
|
|
# R_VERSION=4.4.3 just rebuild ubuntu noble amd64 Rcpp 1.0.12
|
|
|
|
r_version := env_var_or_default("R_VERSION", "4.5.3")
|
|
amd64_builder := env_var_or_default("AMD64_BUILDER", "artemis")
|
|
arm64_builder := env_var_or_default("ARM64_BUILDER", "gaia")
|
|
|
|
# (re)build PACKAGE at one or more VERSIONS on OS/TAG/ARCH via a remote builder
|
|
rebuild os tag arch package *versions:
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
if [ -z "{{ versions }}" ]; then
|
|
echo "error: provide at least one version, e.g. just rebuild alpine 3.23 amd64 rlang 1.1.4" >&2
|
|
exit 1
|
|
fi
|
|
case "{{ arch }}" in
|
|
amd64) builder="{{ amd64_builder }}" ;;
|
|
arm64) builder="{{ arm64_builder }}" ;;
|
|
*) echo "error: arch must be 'amd64' or 'arm64'" >&2; exit 1 ;;
|
|
esac
|
|
# Accept TF_VAR_-prefixed names (direnv) or plain names.
|
|
export B2_S3_ACCESS_KEY="${B2_S3_ACCESS_KEY:-${TF_VAR_B2_S3_ACCESS_KEY:-}}"
|
|
export B2_S3_SECRET_KEY="${B2_S3_SECRET_KEY:-${TF_VAR_B2_S3_SECRET_KEY:-}}"
|
|
: "${B2_S3_ACCESS_KEY:?set B2_S3_ACCESS_KEY or TF_VAR_B2_S3_ACCESS_KEY}"
|
|
: "${B2_S3_SECRET_KEY:?set B2_S3_SECRET_KEY or TF_VAR_B2_S3_SECRET_KEY}"
|
|
: "${PGPASS:?set PGPASS}"
|
|
secret_args=(
|
|
--secret id=b2_access,env=B2_S3_ACCESS_KEY
|
|
--secret id=b2_secret,env=B2_S3_SECRET_KEY
|
|
--secret id=pgpass,env=PGPASS
|
|
)
|
|
# GITHUB_PAT is optional (raises the GitHub API rate limit); pass only if set.
|
|
if [ -n "${GITHUB_PAT:-}" ]; then
|
|
secret_args+=(--secret id=github_pat,env=GITHUB_PAT)
|
|
fi
|
|
echo "Dispatching build of {{ package }} ({{ versions }}) on {{ os }}:{{ tag }}/{{ arch }} (R {{ r_version }}) to builder '$builder'"
|
|
docker buildx build \
|
|
--builder "$builder" \
|
|
--platform "linux/{{ arch }}" \
|
|
--no-cache \
|
|
--progress=plain \
|
|
--output type=cacheonly \
|
|
"${secret_args[@]}" \
|
|
--build-arg OS="{{ os }}" \
|
|
--build-arg OS_VERSION="{{ tag }}" \
|
|
--build-arg R_VERSION="{{ r_version }}" \
|
|
--build-arg PACKAGE="{{ package }}" \
|
|
--build-arg VERSIONS="{{ versions }}" \
|
|
--build-arg CACHEBUST="$(date +%s)" \
|
|
-f docker/build-one.Dockerfile \
|
|
local
|
|
|
|
# run the edge middleware routing matrix (uses a local deno, else the deno image)
|
|
edge-test:
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
if command -v deno >/dev/null 2>&1; then
|
|
deno test -A edge/rpkgs-router.test.ts
|
|
else
|
|
docker run --rm \
|
|
-v "$PWD:/w" -w /w \
|
|
-v deno-cache:/deno-dir \
|
|
denoland/deno:latest \
|
|
deno test -A edge/rpkgs-router.test.ts
|
|
fi
|
|
|
|
# fail if any pipeline still targets a slot the edge does not route
|
|
check-slots:
|
|
Rscript local/check-slots.R
|
|
|
|
# strip a retired slot from .crow/*.yaml (dry run; pass --apply to write)
|
|
retire-slot codename *flags:
|
|
Rscript local/retire-slot.R {{ codename }} --config-only {{ flags }}
|