mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-06 03:57:52 +09:00
fix(platform): migrate ephemeralStorage to diskSize via pre-upgrade hook
Add pre-upgrade migration 41 that walks all kuberneteses.apps.cozystack.io
Application CRs and renames nodeGroups[*].ephemeralStorage to diskSize,
preserving the user's value.
Without this migration, clusters upgraded after PR #2454 either fail to
reconcile (hard fail blocks all Flux operations) or silently lose the user's
disk size setting (default 20Gi replaces whatever was configured).
The migration is idempotent and best-effort: a failed patch is logged and
leaves the version stamp at 41 for retry on next upgrade.
Update the chart-side guard error message to direct operators to the
migration job logs when the field appears post-upgrade (regression detector).
Bump migrations.targetVersion 41 -> 42.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
(cherry picked from commit ed1bb53d2c)
This commit is contained in:
1 parent
a5a4236aff
commit
eee5eb9848
5 files changed
+119
-6
No files matched your search
@@ -85,7 +85,7 @@ See the reference for components utilized in this service:
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **`ephemeralStorage` renamed to `diskSize`**: The `nodeGroups[name].ephemeralStorage` field has been renamed to `nodeGroups[name].diskSize` to better reflect its purpose (persistent disk for kubelet and containerd data). There is no backward-compatibility fallback; users MUST update their configurations to use `diskSize` instead of `ephemeralStorage`. If `ephemeralStorage` is still present in values, Helm template rendering will fail with an error directing you to use `diskSize`. When upgrading the CRD directly (bypassing Helm), the unrecognized field is silently dropped and kubelet storage reverts to the default 20Gi. Existing VMs will be automatically rolling-updated via CAPI when the new values are applied. State persists across same-VM reboots (virt-launcher restart, guest reboot, node failure); VM replacement by CAPI (e.g. nodeGroup field change, MachineHealthCheck remediation) provisions a fresh PVC.
|
||||
- **`ephemeralStorage` renamed to `diskSize`** (v1.4): The `nodeGroups[name].ephemeralStorage` field has been renamed to `nodeGroups[name].diskSize` to better reflect its purpose (persistent disk for kubelet and containerd data). Existing clusters are migrated transparently by platform migration 41 during the pre-upgrade hook — no manual action is required. Newly written values should use `diskSize`. Existing VMs will be automatically rolling-updated via CAPI when the new values are applied. State persists across same-VM reboots (virt-launcher restart, guest reboot, node failure); VM replacement by CAPI (e.g. nodeGroup field change, MachineHealthCheck remediation) provisions a fresh PVC.
|
||||
|
||||
## Parameters
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ spec:
|
||||
cdi.kubevirt.io/storage.usePopulator: "false"
|
||||
spec:
|
||||
{{- if hasKey .group "ephemeralStorage" }}
|
||||
{{- fail (printf "nodeGroup %q: ephemeralStorage is no longer supported. Rename it to diskSize. See README.md for migration instructions." .groupName) }}
|
||||
{{- fail (printf "nodeGroup %q: ephemeralStorage is no longer supported and should have been automatically migrated to diskSize by platform migration 41. If you see this error after upgrading, the migration did not run — check the cozystack-migration-hook Job logs in cozy-system." .groupName) }}
|
||||
{{- end }}
|
||||
source:
|
||||
blank: {}
|
||||
|
||||
@@ -351,7 +351,7 @@ tests:
|
||||
nodeGroups.md0.ephemeralStorage: 50Gi
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: 'nodeGroup "md0": ephemeralStorage is no longer supported. Rename it to diskSize. See README.md for migration instructions.'
|
||||
errorMessage: 'nodeGroup "md0": ephemeralStorage is no longer supported and should have been automatically migrated to diskSize by platform migration 41. If you see this error after upgrading, the migration did not run — check the cozystack-migration-hook Job logs in cozy-system.'
|
||||
|
||||
- it: fails when ephemeralStorage is set to empty string
|
||||
release:
|
||||
@@ -361,7 +361,7 @@ tests:
|
||||
nodeGroups.md0.ephemeralStorage: ""
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: 'nodeGroup "md0": ephemeralStorage is no longer supported. Rename it to diskSize. See README.md for migration instructions.'
|
||||
errorMessage: 'nodeGroup "md0": ephemeralStorage is no longer supported and should have been automatically migrated to diskSize by platform migration 41. If you see this error after upgrading, the migration did not run — check the cozystack-migration-hook Job logs in cozy-system.'
|
||||
|
||||
- it: fails when both ephemeralStorage and diskSize are set
|
||||
release:
|
||||
@@ -372,7 +372,7 @@ tests:
|
||||
nodeGroups.md0.diskSize: 50Gi
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: 'nodeGroup "md0": ephemeralStorage is no longer supported. Rename it to diskSize. See README.md for migration instructions.'
|
||||
errorMessage: 'nodeGroup "md0": ephemeralStorage is no longer supported and should have been automatically migrated to diskSize by platform migration 41. If you see this error after upgrading, the migration did not run — check the cozystack-migration-hook Job logs in cozy-system.'
|
||||
|
||||
###############################################
|
||||
# KubeadmConfigTemplate — files block #
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
#!/bin/bash
|
||||
# Migration 41 --> 42
|
||||
# Rename nodeGroups[*].ephemeralStorage to nodeGroups[*].diskSize in every
|
||||
# kuberneteses.apps.cozystack.io Application CR.
|
||||
#
|
||||
# PR #2454 renamed the field in the kubernetes app chart with no fallback.
|
||||
# Without this migration, upgraded clusters either fail to reconcile (hard fail
|
||||
# behavior) or silently lose their disk size (silent-drop behavior).
|
||||
#
|
||||
# Idempotent: re-running on already-migrated values is a no-op
|
||||
# (has("ephemeralStorage") is false on the post-migration shape).
|
||||
# Best-effort: a failed patch is logged and leaves the version stamp at 41 so
|
||||
# the migration retries on the next platform upgrade.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DRY_RUN="${MIGRATION_DRY_RUN:-0}"
|
||||
FAILURES=0
|
||||
PATCHED=0
|
||||
SKIPPED=0
|
||||
|
||||
# Emit ephemeralStorage: null rather than dropping the key, because JSON merge
|
||||
# patch only deletes a field when an explicit null is present in the patch
|
||||
# document. A patch that simply omits a key leaves the existing key intact.
|
||||
JQ_TRANSFORM='
|
||||
walk(
|
||||
if type == "object" and has("nodeGroups") and (.nodeGroups | type) == "object" then
|
||||
.nodeGroups |= with_entries(
|
||||
.value |= (
|
||||
if type == "object" and has("ephemeralStorage") then
|
||||
(if has("diskSize") and (.diskSize // "") != "" then .
|
||||
else .diskSize = .ephemeralStorage end)
|
||||
| .ephemeralStorage = null
|
||||
else . end
|
||||
)
|
||||
)
|
||||
else . end
|
||||
)
|
||||
'
|
||||
|
||||
patch_object() {
|
||||
local kind="$1" ns="$2" name="$3" selector="$4"
|
||||
local obj current new patch
|
||||
|
||||
obj=$(kubectl get "$kind" --namespace "$ns" "$name" --output json 2>/dev/null || true)
|
||||
if [ -z "$obj" ]; then SKIPPED=$((SKIPPED + 1)); return 0; fi
|
||||
|
||||
current=$(printf '%s' "$obj" | jq -c "$selector // null")
|
||||
if [ "$current" = "null" ]; then SKIPPED=$((SKIPPED + 1)); return 0; fi
|
||||
|
||||
new=$(printf '%s' "$current" | jq -c "$JQ_TRANSFORM")
|
||||
if [ "$current" = "$new" ]; then SKIPPED=$((SKIPPED + 1)); return 0; fi
|
||||
|
||||
patch=$(jq --null-input --argjson val "$new" --arg path "${selector#.}" '
|
||||
def to_path: split(".");
|
||||
{} | setpath($path | to_path; $val)
|
||||
')
|
||||
|
||||
if [ "$DRY_RUN" = "1" ]; then
|
||||
echo "[dry-run] would patch $kind $ns/$name ($selector)"
|
||||
diff <(printf '%s' "$current" | jq --sort-keys .) \
|
||||
<(printf '%s' "$new" | jq --sort-keys .) || true
|
||||
PATCHED=$((PATCHED + 1))
|
||||
return 0
|
||||
fi
|
||||
|
||||
local kubectl_err
|
||||
if kubectl_err=$(printf '%s' "$patch" | kubectl patch "$kind" --namespace "$ns" "$name" \
|
||||
--type merge --patch-file /dev/stdin 2>&1 >/dev/null); then
|
||||
echo "Patched $kind $ns/$name ($selector)"
|
||||
PATCHED=$((PATCHED + 1))
|
||||
else
|
||||
echo "WARN: failed to patch $kind $ns/$name ($selector): ${kubectl_err:-unknown error}" >&2
|
||||
FAILURES=$((FAILURES + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
list_objects() {
|
||||
local kind="$1" out
|
||||
if ! out=$(kubectl get "$kind" --all-namespaces \
|
||||
--output 'jsonpath={range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}' \
|
||||
2>&1); then
|
||||
case "$out" in
|
||||
*"the server doesn't have a resource type"*|*"no matches for kind"*|*"NotFound"*) return 0 ;;
|
||||
esac
|
||||
echo "ERROR: kubectl get $kind failed: $out" >&2
|
||||
return 1
|
||||
fi
|
||||
printf '%s' "$out"
|
||||
}
|
||||
|
||||
echo "==> Migrating kuberneteses.apps.cozystack.io"
|
||||
items=$(list_objects kuberneteses.apps.cozystack.io) || exit 1
|
||||
while IFS=$'\t' read -r ns name; do
|
||||
[ -z "$ns" ] && continue
|
||||
patch_object kuberneteses.apps.cozystack.io "$ns" "$name" .spec
|
||||
done <<<"$items"
|
||||
|
||||
echo "==> Summary: patched=$PATCHED skipped=$SKIPPED failures=$FAILURES" | tee /dev/stderr
|
||||
|
||||
if [ "$DRY_RUN" = "1" ]; then
|
||||
echo "Dry-run complete; version stamp not advanced"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$FAILURES" -gt 0 ]; then
|
||||
echo "WARN: $FAILURES patch(es) failed; leaving CURRENT_VERSION at 41 for retry on next upgrade."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
kubectl create configmap --namespace cozy-system cozystack-version \
|
||||
--from-literal version=42 --dry-run=client --output yaml \
|
||||
| kubectl apply --filename -
|
||||
@@ -6,7 +6,7 @@ sourceRef:
|
||||
migrations:
|
||||
enabled: false
|
||||
image: ghcr.io/cozystack/cozystack/platform-migrations:v1.4.0-rc.2@sha256:17390197a9b11d76a8dd1b24c6d1512adb7d3226b28b5bcba8551b14b1ec4be0
|
||||
targetVersion: 40
|
||||
targetVersion: 42
|
||||
# Bundle deployment configuration
|
||||
bundles:
|
||||
system:
|
||||
|
||||
Reference in new issue
Block a user