|
| 1 | +#!/bin/bash |
| 2 | +# Migration 51 --> 52 |
| 3 | +# Backfill the apps.cozystack.io/application.name release label onto pre-existing |
| 4 | +# VictoriaMetrics / VictoriaLogs storage PVCs of the monitoring module. |
| 5 | +# |
| 6 | +# PR #3094 adds apps.cozystack.io/application.name to the VMCluster/VLCluster |
| 7 | +# storage volumeClaimTemplates (packages/system/monitoring) and a post-delete |
| 8 | +# hook that garbage-collects PVCs carrying that label. But vm-operator only |
| 9 | +# stamps volumeClaimTemplate.metadata.labels onto PVCs it creates *after* the |
| 10 | +# change; the Kubernetes StatefulSet controller applies claim-template labels |
| 11 | +# only at PVC creation and never re-labels existing PVCs, and vm-operator's PVC |
| 12 | +# reconciler is resize-only. Storage provisioned before this upgrade therefore |
| 13 | +# stays unlabeled, the cleanup hook's selector misses it, and it keeps leaking on |
| 14 | +# delete (issue #3091). This migration relabels those PVCs once so the hook can |
| 15 | +# reclaim them. |
| 16 | +# |
| 17 | +# The label value is read from each CR's spec.managedMetadata so we relabel only |
| 18 | +# cozystack-managed monitoring clusters (a user's own VMCluster carries no such |
| 19 | +# label and is left untouched) and always stamp the exact value the hook selects. |
| 20 | +# |
| 21 | +# Best-effort by design: the worst case if a relabel is skipped is the |
| 22 | +# pre-existing leak this PR set out to fix, which is strictly no worse than the |
| 23 | +# status quo. A transient apiserver hiccup must therefore NOT abort the whole |
| 24 | +# platform upgrade, so the CR list and per-PVC reads tolerate failure (|| true) |
| 25 | +# rather than exiting non-zero. |
| 26 | + |
| 27 | +set -euo pipefail |
| 28 | + |
| 29 | +# shellcheck source=lib/cozystack-version.sh |
| 30 | +. "$(dirname "$0")/lib/cozystack-version.sh" |
| 31 | + |
| 32 | +label_key="apps.cozystack.io/application.name" |
| 33 | +# jsonpath escapes the dots/slash in the label key. |
| 34 | +label_path='{.spec.managedMetadata.labels.apps\.cozystack\.io/application\.name}' |
| 35 | + |
| 36 | +# relabel_storage <crd> <pvc-name-regex> |
| 37 | +# For every CR of <crd> that carries the cozystack application.name label, relabel |
| 38 | +# its storage PVCs (matched by the StatefulSet-derived <pvc-name-regex>, with the |
| 39 | +# CR name spliced in) to the same value. |
| 40 | +relabel_storage() { |
| 41 | + crd="$1" |
| 42 | + pvc_regex_tmpl="$2" |
| 43 | + |
| 44 | + # This migration runs platform-wide (targetVersion bump), including on clusters |
| 45 | + # that never installed monitoring. Skip when the CRD is absent. The `|| true` |
| 46 | + # on the list additionally keeps a transient apiserver error from aborting the |
| 47 | + # upgrade — there is nothing safety-critical to gate on. |
| 48 | + if ! kubectl get crd "$crd" >/dev/null 2>&1; then |
| 49 | + echo "$crd not present; skipping monitoring PVC label backfill" |
| 50 | + return 0 |
| 51 | + fi |
| 52 | + |
| 53 | + crs=$(kubectl get "$crd" -A \ |
| 54 | + -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' || true) |
| 55 | + |
| 56 | + echo "$crs" | while read -r ns name; do |
| 57 | + [ -n "${ns:-}" ] || continue |
| 58 | + |
| 59 | + appname=$(kubectl get "$crd" -n "$ns" "$name" -o jsonpath="$label_path" 2>/dev/null || true) |
| 60 | + if [ -z "$appname" ]; then |
| 61 | + echo "$crd $ns/$name has no $label_key; not a cozystack-managed cluster, skipping" |
| 62 | + continue |
| 63 | + fi |
| 64 | + |
| 65 | + # Splice the CR name into the PVC regex (e.g. "(vmstorage|vmselect)-NAME-[0-9]+$"). |
| 66 | + pvc_regex=$(printf '%s' "$pvc_regex_tmpl" | sed "s/NAME/${name}/g") |
| 67 | + |
| 68 | + # grep exits 1 when a namespace has no matching PVCs; tolerate it so pipefail |
| 69 | + # does not abort the whole migration on an empty match. |
| 70 | + pvcs=$(kubectl get pvc -n "$ns" \ |
| 71 | + -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null \ |
| 72 | + | grep -E "$pvc_regex" || true) |
| 73 | + |
| 74 | + for pvc in $pvcs; do |
| 75 | + [ -n "${pvc:-}" ] || continue |
| 76 | + current=$(kubectl get pvc -n "$ns" "$pvc" \ |
| 77 | + -o jsonpath="{.metadata.labels.apps\.cozystack\.io/application\.name}" 2>/dev/null || true) |
| 78 | + if [ "$current" = "$appname" ]; then |
| 79 | + echo "PVC $ns/$pvc already labeled $label_key=$appname; skipping" |
| 80 | + continue |
| 81 | + fi |
| 82 | + echo "Labeling PVC $ns/$pvc with $label_key=$appname" |
| 83 | + kubectl label pvc -n "$ns" "$pvc" "$label_key=$appname" --overwrite |
| 84 | + done |
| 85 | + done |
| 86 | +} |
| 87 | + |
| 88 | +# vm-operator storage PVCs are named "<claim-template>-<sts>-<ordinal>" and the |
| 89 | +# StatefulSet is "<component>-<cr>", so every PVC ends with |
| 90 | +# "<component>-<cr>-<ordinal>". The regex suffix-matches that tail, so it is |
| 91 | +# robust to the claim-template prefix (e.g. vmstorage-db-vmstorage-<cr>-0 and |
| 92 | +# vmselect-cachedir-vmselect-<cr>-0 both match on the vmselect/vmstorage arm). |
| 93 | +relabel_storage vmclusters.operator.victoriametrics.com '(vmstorage|vmselect)-NAME-[0-9]+$' |
| 94 | +# vlstorage STS PVCs are "<claim-template>-vlstorage-<cr>-<ordinal>". |
| 95 | +relabel_storage vlclusters.operator.victoriametrics.com 'vlstorage-NAME-[0-9]+$' |
| 96 | + |
| 97 | +# Stamp version via the shared helper so the cozystack-version ConfigMap keeps |
| 98 | +# the platform.cozystack.io/no-delete label. |
| 99 | +stamp_cozystack_version 52 |
0 commit comments