refactor(slots): cut the comments down to the essentials
Addresses review on #214.
This change will:
- Trim the header comments of `local/check-slots.R`, `local/retire-slot.R` and
`.crow/retire-slot.yaml` to what a reader needs, dropping the narrative about
how Alpine 3.22 got into that state.
- Reduce the README section to the ordered steps and the two constraints that
matter.
Behaviour is unchanged: against the tree at 523424b the script still reproduces
#213's structural changes, differing only in the same prose-only file, and both
guards still fire.
This commit is contained in:
parent
bfe56ffd22
commit
cc9d7b6046
1 changed files with 63 additions and 148 deletions
|
|
@ -1,39 +1,20 @@
|
|||
### Retire a slot: strip it from the pipelines and delete its objects from S3.
|
||||
#
|
||||
# Usage:
|
||||
# Rscript local/retire-slot.R <codename> [--apply] [--config-only|--assets-only]
|
||||
#
|
||||
# Rscript local/retire-slot.R alpine322 # dry run, both halves
|
||||
# Rscript local/retire-slot.R alpine322 --config-only # edit .crow/, no S3
|
||||
# Rscript local/retire-slot.R alpine322 --assets-only --apply
|
||||
#
|
||||
# Retiring a distro retires both architectures, because `local.rpkgs_slots` in
|
||||
# `cdn.tf` is a setproduct over `["amd64", "arm64"]` and there is no way to
|
||||
# publish one without the other.
|
||||
# `cdn.tf` is a setproduct over them.
|
||||
#
|
||||
# Three things have to happen and nothing ties them together on its own:
|
||||
# Order: remove the slot from `local.rpkgs_slots` (and the website's
|
||||
# `DistroId`) and apply that first, then run this. Deleting objects while a
|
||||
# pipeline still targets the slot just means the next nightly rebuilds them.
|
||||
#
|
||||
# 1. the slot leaves `local.rpkgs_slots` in `cdn.tf` (and `DistroId` in the
|
||||
# website's `src/src/data/repos.ts`), which is what stops the edge routing
|
||||
# it. Do this first and by hand: it is the decision, the rest is cleanup.
|
||||
# 2. the slot leaves every `.crow/*.yaml` matrix, which is what stops the
|
||||
# fleet building, indexing and verifying it. This script does that.
|
||||
# 3. the objects leave the bucket. This script does that too.
|
||||
# Cron jobs live on the Crow server, not here, and are printed at the end.
|
||||
#
|
||||
# A fourth step cannot be scripted from here: the slot's cron jobs live on the
|
||||
# Crow server, not in this repository, and removing a matrix row does not remove
|
||||
# the cron that targets it. The script prints the ones it finds by name at the
|
||||
# end, with the API call to delete them.
|
||||
# Only structural YAML is edited. Prose mentioning the slot is left alone, so
|
||||
# grep for the name afterwards.
|
||||
#
|
||||
# Dry run by default. Nothing is edited or deleted without --apply.
|
||||
#
|
||||
# Order matters. Deleting the objects while a pipeline still targets the slot
|
||||
# means the next nightly rebuilds them.
|
||||
#
|
||||
# Only structural YAML is edited: matrix rows, dropdown options and the
|
||||
# `OS_VERSION` tag. Prose that happens to mention the slot (a usage example in
|
||||
# a header comment, a dropdown `description:`) is left alone, because rewriting
|
||||
# free text automatically is guesswork. Grep for the name afterwards.
|
||||
# Dry run by default.
|
||||
|
||||
options(error = function() {
|
||||
cat("ERROR:", geterrmessage(), "\n", file = stdout())
|
||||
|
|
@ -53,15 +34,14 @@ if (length(args) != 1L || (config_only && assets_only)) {
|
|||
}
|
||||
codename <- args[[1L]]
|
||||
|
||||
# `alpine322` is how the bucket, the edge and `CODENAME:` spell it; `alpine-322`
|
||||
# is how `OS:` and the dropdown options spell it. Both have to go.
|
||||
# The bucket and `CODENAME:` say `alpine322`; `OS:` and the options say
|
||||
# `alpine-322`. Both have to go.
|
||||
pipeline_os <- if (grepl("^rhel[0-9]+$", codename)) {
|
||||
sub("^rhel", "redhat-", codename)
|
||||
} else if (grepl("^alpine[0-9]+$", codename)) {
|
||||
sub("^alpine", "alpine-", codename)
|
||||
} else {
|
||||
# Single bracket, so an unknown codename yields NA and the check below
|
||||
# reports it rather than raising "subscript out of bounds".
|
||||
# Single bracket so an unknown codename yields NA, not an error.
|
||||
c(resolute = "ubuntu-2604", noble = "ubuntu-2404", jammy = "ubuntu-2204")[
|
||||
codename
|
||||
]
|
||||
|
|
@ -79,9 +59,8 @@ image_tag <- if (grepl("^alpine-", pipeline_os)) {
|
|||
codename
|
||||
}
|
||||
|
||||
# Refuse to retire a slot that is still routed. Without this the script is a
|
||||
# fast way to break a live slot: the edge would keep sending clients to indexes
|
||||
# whose objects no longer exist, and every install would 404.
|
||||
# Refuse a slot that is still routed: deleting its objects would leave the edge
|
||||
# serving indexes that name files which no longer exist.
|
||||
tf <- readLines("cdn.tf", warn = FALSE)
|
||||
start <- grep("rpkgs_slots\\s*=", tf)
|
||||
if (length(start) != 1L) {
|
||||
|
|
@ -110,9 +89,7 @@ cat(sprintf(
|
|||
|
||||
## 1. Pipeline definitions ----------------------------------------------------
|
||||
|
||||
# Drops a matrix row and everything indented under it, a dropdown option, and
|
||||
# an `OS_VERSION` entry for the retired tag. Line-based on purpose: round
|
||||
# tripping through a YAML parser would reflow all 18 files and bury the change.
|
||||
# Line-based on purpose: a YAML round trip would reflow all 18 files.
|
||||
strip_slot <- function(lines) {
|
||||
keep <- rep(TRUE, length(lines))
|
||||
i <- 1L
|
||||
|
|
@ -153,8 +130,7 @@ strip_slot <- function(lines) {
|
|||
i <- i + 1L
|
||||
}
|
||||
out <- lines[keep]
|
||||
# A dropdown whose default was the retired tag would reject its own default,
|
||||
# so move it to the first surviving option of the same block.
|
||||
# A dropdown cannot default to an option that no longer exists.
|
||||
bad_default <- grepl(sprintf("^\\s*default:\\s*'%s'\\s*$", image_tag), out)
|
||||
if (any(bad_default)) {
|
||||
for (k in which(bad_default)) {
|
||||
|
|
@ -162,8 +138,7 @@ strip_slot <- function(lines) {
|
|||
if (length(opts) == 0L) {
|
||||
next
|
||||
}
|
||||
# Walk back to the first option of this block rather than the last, so the
|
||||
# default lands on the lowest surviving version instead of an unrelated one.
|
||||
# Walk back to this block's first option, not the nearest one.
|
||||
first <- max(opts)
|
||||
while (first > 1L && grepl("^\\s*-\\s*'[^']+'\\s*$", out[[first - 1L]])) {
|
||||
first <- first - 1L
|
||||
|
|
@ -213,7 +188,7 @@ if (!config_only) {
|
|||
library(s3fs, quietly = TRUE)
|
||||
if (!nzchar(Sys.getenv("B2_S3_ACCESS_KEY"))) {
|
||||
stop(
|
||||
"B2_S3_ACCESS_KEY is unset. B2 needs credentials even to list, and an unauthenticated list returns empty, which is indistinguishable from an already-clean slot.", # nolint
|
||||
"B2_S3_ACCESS_KEY is unset. B2 lists nothing without credentials, which is indistinguishable from an already-clean slot.", # nolint
|
||||
call. = FALSE
|
||||
)
|
||||
}
|
||||
|
|
@ -248,7 +223,7 @@ if (!config_only) {
|
|||
cat("\n")
|
||||
}
|
||||
|
||||
## 3. What is left for a human ------------------------------------------------
|
||||
## 3. Crons ------------------------------------------------------------------
|
||||
|
||||
if (!apply_changes) {
|
||||
cat("Dry run: nothing was edited or deleted. Re-run with --apply.\n\n")
|
||||
|
|
@ -259,9 +234,7 @@ cat(sprintf(
|
|||
" crow-at ci.devxy.io repo cron ls devxy/build-cran-binaries | grep %s\n",
|
||||
pipeline_os
|
||||
))
|
||||
cat(
|
||||
" # `crow repo cron rm` 404s on this server version; use the API, whose base is /api/v1\n"
|
||||
)
|
||||
cat(" # `crow repo cron rm` 404s here; the API base is /api/v1\n")
|
||||
cat(" eval \"$(crow-at --export ci.devxy.io)\"\n")
|
||||
cat(" curl -s -X DELETE -H \"Authorization: Bearer $CROW_TOKEN\" \\\n")
|
||||
cat(" https://ci.devxy.io/api/v1/repos/5/cron/<cron-id>\n")
|
||||
|
|
|
|||
Loading…
Reference in a new issue