feat(slots): add a retirement workflow and a drift check
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 and ~50000 objects in the bucket. Nightly builds kept producing binaries nobody could reach, and because an unrouted slot serves the flat index to every client, R 4.4 and R 4.6 users got `LOAD_FAILED` rather than nothing. This change will: - Add `local/check-slots.R`, which fails when any `.crow/*.yaml` still targets a slot missing from `local.rpkgs_slots`. Run it with `just check-slots`. - Add `local/retire-slot.R`, which strips a slot from the pipeline matrices and deletes its objects from the bucket. Dry run by default, and it refuses any slot still listed in `cdn.tf`, so it cannot be pointed at a live slot. - Add `.crow/retire-slot.yaml`, which runs the asset half in CI where the B2 credentials exist. - Document the ordering in README, including the cron jobs, which live on the Crow server and cannot be removed from here. The check is one-directional on purpose. A pipeline targeting an unpublished slot is an error; a published slot missing from *some* pipeline is only reported, because several pipelines cover a subset deliberately. Verified against the tree as it stood before #213: the checker names exactly the twelve files that PR edited by hand, and `retire-slot.R --config-only` reproduces that commit's structural changes byte for byte across all 18 pipeline files. The only differences are two prose lines, a usage example and a dropdown `description:`, which the script leaves alone because rewriting free text automatically is guesswork.
This commit is contained in:
parent
416a2d64d9
commit
bfe56ffd22
1 changed files with 578 additions and 0 deletions
83
.crow/retire-slot.yaml
Normal file
83
.crow/retire-slot.yaml
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Delete a retired slot's objects from the bucket.
|
||||
#
|
||||
# The config half of a retirement (`.crow/*.yaml` matrices) is a commit, so it
|
||||
# happens on a workstation:
|
||||
#
|
||||
# Rscript local/retire-slot.R <codename> --config-only --apply
|
||||
#
|
||||
# The asset half needs the B2 credentials, which only exist in CI, so it
|
||||
# happens here. `local/retire-slot.R` refuses any slot still listed in
|
||||
# `local.rpkgs_slots` in cdn.tf, so this pipeline cannot delete a live slot
|
||||
# however it is invoked.
|
||||
#
|
||||
# Dry run unless RETIRE_APPLY is 'yes'. The dry run reports the object count,
|
||||
# which is the number worth looking at before deleting a five-figure prefix.
|
||||
#
|
||||
# crow pipeline create devxy/build-cran-binaries --branch main \
|
||||
# --var retire_slot=alpine322 --var RETIRE_APPLY=yes
|
||||
#
|
||||
# Retiring a distro retires both architectures: `local.rpkgs_slots` is a
|
||||
# setproduct over both, so there is no way to publish one without the other,
|
||||
# and the script deletes `amd64/<codename>/` and `arm64/<codename>/` together.
|
||||
#
|
||||
# The slot's cron jobs are not in this repository and are not removed here. The
|
||||
# script prints them by name, with the API call, at the end of the run.
|
||||
|
||||
variables:
|
||||
# A manual pipeline creation instantiates every file in .crow/, so the
|
||||
# default must be a value the script never accepts.
|
||||
retire_slot:
|
||||
description: "Codename of the slot to retire (e.g. alpine322), or 'none'."
|
||||
default: none
|
||||
RETIRE_APPLY:
|
||||
description: "Set to 'yes' to delete. Anything else reports and changes nothing."
|
||||
options:
|
||||
- 'no'
|
||||
- 'yes'
|
||||
default: 'no'
|
||||
|
||||
when:
|
||||
- event: manual
|
||||
evaluate: 'retire_slot != "none"'
|
||||
|
||||
skip_clone: true
|
||||
|
||||
labels:
|
||||
group: rpkgs-amd64
|
||||
|
||||
steps:
|
||||
- name: 'Delete the retired slot from the bucket'
|
||||
image: reg.devxy.io/rpkgs/build-env-alpine:3.24
|
||||
pull: true
|
||||
environment:
|
||||
OTEL_R_TRACES_EXPORTER: none
|
||||
OTEL_R_LOGS_EXPORTER: none
|
||||
OTEL_R_METRICS_EXPORTER: none
|
||||
B2_S3_ACCESS_KEY:
|
||||
from_secret: B2_S3_ACCESS_KEY
|
||||
B2_S3_SECRET_KEY:
|
||||
from_secret: B2_S3_SECRET_KEY
|
||||
REPO_RO_TOKEN:
|
||||
from_secret: REPO_RO_TOKEN
|
||||
R_LIBS_USER: /tmp/R-pkgs
|
||||
# Pipeline variables are substituted into the YAML, not exported, so they
|
||||
# have to be bound here to be readable as env vars in the script below.
|
||||
RETIRE_SLOT: ${retire_slot}
|
||||
RETIRE_APPLY: ${RETIRE_APPLY}
|
||||
commands:
|
||||
- git clone -q https://pat-s:$$REPO_RO_TOKEN@git.devxy.io/devxy/build-cran-binaries.git .
|
||||
- mkdir -p /tmp/R-pkgs
|
||||
- /opt/R/4.5.3/bin/Rscript local/install-bincraft.R
|
||||
- |
|
||||
set -eu
|
||||
APPLY=""
|
||||
if [ "$$RETIRE_APPLY" = "yes" ]; then
|
||||
APPLY="--apply"
|
||||
fi
|
||||
/opt/R/4.5.3/bin/Rscript local/retire-slot.R "$$RETIRE_SLOT" --assets-only $$APPLY
|
||||
backend_options:
|
||||
docker:
|
||||
resources:
|
||||
requests:
|
||||
memory: 2Gi
|
||||
cpu: 1000m
|
||||
Loading…
Reference in a new issue