-
Notifications
You must be signed in to change notification settings - Fork 73
feat(self-managed): record the installed stack version, and check migrations against the proposed bump #1983
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
6a9aed5
ci(stack): check migrations against the proposed stack version bump
kristinapathak f27c682
fix(stack): close three gaps CodeRabbit found in the upgrade-policy c…
kristinapathak b288d09
feat(self-managed): record the installed stack version in-cluster
kristinapathak 3ac39d8
docs(ci): say what the pull_request-only guard actually rules out
kristinapathak 69a3067
fix(self-managed): scope the receipt Role to the receipt ConfigMap
kristinapathak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
deploy/stacks/self-managed/charts/nvcf-upgrade-receipt/Chart.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| apiVersion: v2 | ||
| name: nvcf-upgrade-receipt | ||
| description: Records the installed NVCF stack version in-cluster so an upgrade can tell where it is starting from. | ||
| type: application | ||
| version: 0.1.0 | ||
| appVersion: "0.1.0" |
56 changes: 56 additions & 0 deletions
56
deploy/stacks/self-managed/charts/nvcf-upgrade-receipt/templates/job.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| {{- $version := required "stackVersion is required: a receipt that names the wrong version is worse than no receipt" .Values.stackVersion }} | ||
| apiVersion: batch/v1 | ||
| kind: Job | ||
| metadata: | ||
| name: {{ .Release.Name }} | ||
| namespace: {{ .Release.Namespace }} | ||
| annotations: | ||
| # post-* rather than pre-*: the receipt states what the cluster is running, | ||
| # so it must not be written until the release it describes has been applied. | ||
| # | ||
| # Both install and upgrade, because the first cluster to receive this chart | ||
| # has no prior release of it, and Helm runs post-install there rather than | ||
| # post-upgrade. Omitting post-install would leave exactly the clusters this | ||
| # exists for without a receipt. | ||
| "helm.sh/hook": post-install,post-upgrade | ||
| "helm.sh/hook-weight": "0" | ||
| "helm.sh/hook-delete-policy": before-hook-creation | ||
| spec: | ||
| backoffLimit: 3 | ||
| ttlSecondsAfterFinished: 600 | ||
| template: | ||
| metadata: | ||
| name: {{ .Release.Name }} | ||
| spec: | ||
| restartPolicy: Never | ||
| serviceAccountName: {{ .Release.Name }} | ||
| {{- with .Values.imagePullSecrets }} | ||
| imagePullSecrets: | ||
| {{ toYaml . | indent 8 }} | ||
| {{- end }} | ||
| containers: | ||
| - name: receipt | ||
| image: "{{ with .Values.image.registry }}{{ . }}/{{ end }}{{ .Values.image.repository }}:{{ .Values.image.tag }}" | ||
| imagePullPolicy: {{ .Values.image.pullPolicy }} | ||
| env: | ||
| - name: RECEIPT_CONFIGMAP | ||
| value: {{ .Values.configMapName | quote }} | ||
| - name: INSTALLED_STACK_VERSION | ||
| value: {{ $version | quote }} | ||
| command: | ||
| - /bin/sh | ||
| - -c | ||
| - | | ||
| set -eu | ||
| # Rendered through apply rather than create so that the first | ||
| # install and every later upgrade take the same path. A receipt | ||
| # that only appears on a fresh install would be absent from | ||
| # exactly the clusters that are upgrading. | ||
| kubectl create configmap "${RECEIPT_CONFIGMAP}" \ | ||
| --from-literal=installed_stack_version="${INSTALLED_STACK_VERSION}" \ | ||
| --from-literal=recorded_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ | ||
| --dry-run=client -o yaml \ | ||
| | kubectl apply -f - | ||
| echo "recorded installed_stack_version=${INSTALLED_STACK_VERSION} in ${RECEIPT_CONFIGMAP}" |
26 changes: 26 additions & 0 deletions
26
deploy/stacks/self-managed/charts/nvcf-upgrade-receipt/templates/role.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| apiVersion: rbac.authorization.k8s.io/v1 | ||
| kind: Role | ||
| metadata: | ||
| name: {{ .Release.Name }} | ||
| namespace: {{ .Release.Namespace }} | ||
| annotations: | ||
| "helm.sh/hook": post-install,post-upgrade | ||
| "helm.sh/hook-weight": "-5" | ||
| "helm.sh/hook-delete-policy": before-hook-creation | ||
| rules: | ||
| # Scoped to the receipt itself. get and patch cover the upgrade case where a | ||
| # receipt already exists, and naming the resource keeps this identity from | ||
| # reaching any other ConfigMap in the namespace. | ||
| - apiGroups: [""] | ||
| resources: ["configmaps"] | ||
| resourceNames: [{{ .Values.configMapName | quote }}] | ||
| verbs: ["get", "patch"] | ||
| # create cannot be scoped: RBAC matches resourceNames against an object that | ||
| # does not exist yet, so a create rule naming one is never satisfied. It is | ||
| # kept in its own rule so the unscoped verb is visible rather than buried | ||
| # alongside the scoped ones, and it is only reachable on a first install. | ||
| - apiGroups: [""] | ||
| resources: ["configmaps"] | ||
| verbs: ["create"] |
19 changes: 19 additions & 0 deletions
19
deploy/stacks/self-managed/charts/nvcf-upgrade-receipt/templates/rolebinding.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| apiVersion: rbac.authorization.k8s.io/v1 | ||
| kind: RoleBinding | ||
| metadata: | ||
| name: {{ .Release.Name }} | ||
| namespace: {{ .Release.Namespace }} | ||
| annotations: | ||
| "helm.sh/hook": post-install,post-upgrade | ||
| "helm.sh/hook-weight": "-5" | ||
| "helm.sh/hook-delete-policy": before-hook-creation | ||
| roleRef: | ||
| apiGroup: rbac.authorization.k8s.io | ||
| kind: Role | ||
| name: {{ .Release.Name }} | ||
| subjects: | ||
| - kind: ServiceAccount | ||
| name: {{ .Release.Name }} | ||
| namespace: {{ .Release.Namespace }} | ||
17 changes: 17 additions & 0 deletions
17
deploy/stacks/self-managed/charts/nvcf-upgrade-receipt/templates/serviceaccount.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| apiVersion: v1 | ||
| kind: ServiceAccount | ||
| metadata: | ||
| name: {{ .Release.Name }} | ||
| namespace: {{ .Release.Namespace }} | ||
| annotations: | ||
| # Must exist before the Job that uses it, and survive long enough to be | ||
| # bound. A lower weight than the Job is what orders them. | ||
| "helm.sh/hook": post-install,post-upgrade | ||
| "helm.sh/hook-weight": "-5" | ||
| "helm.sh/hook-delete-policy": before-hook-creation | ||
| {{- with .Values.imagePullSecrets }} | ||
| imagePullSecrets: | ||
| {{ toYaml . | indent 2 }} | ||
| {{- end }} |
19 changes: 19 additions & 0 deletions
19
deploy/stacks/self-managed/charts/nvcf-upgrade-receipt/values.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| # The stack version this bundle installs. The Helmfile supplies it from the | ||
| # bundle's own VERSION file; there is no sensible default, so rendering fails | ||
| # rather than recording a version the cluster is not running. | ||
| stackVersion: "" | ||
|
|
||
| image: | ||
| registry: "" | ||
| repository: alpine-k8s | ||
| tag: "1.33.1" | ||
| pullPolicy: IfNotPresent | ||
|
|
||
| imagePullSecrets: [] | ||
|
|
||
| # Name of the ConfigMap holding the receipt. An upgrade reads this to decide | ||
| # whether the jump it has been asked to make is one it can make safely. | ||
| configMapName: nvcf-upgrade-receipt |
30 changes: 30 additions & 0 deletions
30
deploy/stacks/self-managed/helmfile.d/04-upgrade-receipt.yaml.gotmpl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| environments: | ||
| default: | ||
| values: | ||
| - ../environments/base.yaml | ||
| - ../environments/{{ requiredEnv "HELMFILE_ENV" }}.yaml | ||
|
|
||
| --- | ||
|
|
||
| {{- /* | ||
| A stage of its own, and the last one, so the receipt is written only after | ||
| every other release has been applied. Ordering is a stage boundary rather | ||
| than a needs: edge on purpose: under the helmfile version this stack pins, | ||
| needs: places a release in a later DAG layer where it waits on every peer in | ||
| the previous one, and a single slow or failed peer silently skips it. See the | ||
| admin-issuer-proxy comment in 02-core.yaml.gotmpl. | ||
| */}} | ||
|
|
||
| releases: | ||
| - name: upgrade-receipt | ||
| chart: ../charts/nvcf-upgrade-receipt | ||
| namespace: nvcf | ||
| values: | ||
| - stackVersion: {{ readFile "../VERSION" | trim | quote }} | ||
| image: | ||
| registry: {{ .Values.global.image.registry | quote }} | ||
| repository: {{ .Values.global.image.repository }}/alpine-k8s | ||
| {{- with .Values.global.imagePullSecrets }} | ||
| imagePullSecrets: | ||
| {{- toYaml . | nindent 10 }} | ||
| {{- end }} |
52 changes: 52 additions & 0 deletions
52
deploy/stacks/self-managed/tests/upgrade-receipt-wiring.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| #!/usr/bin/env bash | ||
| # Test that the stack records the version it installed. | ||
| # | ||
| # An upgrade has to know where it is starting from, and nothing else in a | ||
| # cluster carries that: Helm tracks chart versions per release, and helmfile has | ||
| # no concept of the bundle's own version. Without this receipt every cluster | ||
| # looks identical to every other one at upgrade time. | ||
| # | ||
| # The assertions that matter are the hook kinds and the recorded version. A | ||
| # pre-* hook would claim a version before it was applied, and a post-upgrade | ||
| # hook alone would skip the first install of this chart, which is precisely the | ||
| # set of clusters that need a receipt written. | ||
| set -euo pipefail | ||
|
|
||
| stack_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" | ||
| expected_version="$(tr -d '[:space:]' < "$stack_dir/VERSION")" | ||
|
|
||
| rendered="$(cd "$stack_dir" && HELMFILE_ENV=base helmfile \ | ||
| --file helmfile.d/04-upgrade-receipt.yaml.gotmpl template)" | ||
|
|
||
| fail() { echo "FAIL: $1" >&2; exit 1; } | ||
|
|
||
| grep -q 'kind: Job' <<<"$rendered" || fail "no Job rendered" | ||
| grep -q '"helm.sh/hook": post-install,post-upgrade' <<<"$rendered" \ | ||
| || fail "receipt must run on both install and upgrade, after the release it describes" | ||
| grep -q "value: \"${expected_version}\"" <<<"$rendered" \ | ||
| || fail "recorded version does not match VERSION (${expected_version})" | ||
| # The ConfigMap is created by the Job at run time, not rendered, so its name | ||
| # reaches the cluster as the env var the script reads. | ||
| grep -q 'value: "nvcf-upgrade-receipt"' <<<"$rendered" \ | ||
| || fail "receipt ConfigMap name is not the one an upgrade will read" | ||
|
|
||
| for kind in ServiceAccount Role RoleBinding; do | ||
| grep -q "kind: ${kind}" <<<"$rendered" || fail "missing ${kind}; the Job cannot write the ConfigMap without it" | ||
| done | ||
| # get and patch are scoped to the receipt by name so this identity cannot | ||
| # reach any other ConfigMap. create cannot be scoped -- RBAC matches | ||
| # resourceNames against an object that does not exist yet. | ||
| grep -qE '^\s+resourceNames: \["nvcf-upgrade-receipt"\]' <<<"$rendered" \ | ||
| || fail "get/patch are not scoped to the receipt ConfigMap by name" | ||
| grep -qE '^\s+verbs: \["get", "patch"\]' <<<"$rendered" \ | ||
| || fail "scoped rule should carry only get and patch" | ||
| grep -qE '^\s+verbs: \["create"\]' <<<"$rendered" \ | ||
| || fail "create must remain, in its own rule, for the first install" | ||
|
|
||
| # The stage number is the ordering guarantee. needs: is deliberately not used | ||
| # here; see the comment in the stage file. | ||
| last_stage="$(ls "$stack_dir"/helmfile.d/*.gotmpl | sort | tail -1)" | ||
| [[ "$(basename "$last_stage")" == "04-upgrade-receipt.yaml.gotmpl" ]] \ | ||
| || fail "receipt is not the last stage; it would record a version before the stack finished applying" | ||
|
|
||
| echo "PASS: upgrade-receipt-wiring" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #!/usr/bin/env bash | ||
| # SPDX-FileCopyrightText: Copyright (c) NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Stable CI entrypoint for the Go tool in tools/stack-upgrade-policy. | ||
| # | ||
| # The wrapper exists for the same two reasons tools/ci/chart-service-edge does. | ||
| # | ||
| # The repository root. `go run -C <dir>` leaves the process running with that | ||
| # directory as its working directory, so the tool cannot find the release | ||
| # metadata or the git history on its own. Resolving the root from this script's | ||
| # own location means callers do not have to pass it. | ||
| # | ||
| # The exit code. `go run` does NOT propagate the program's status: it prints | ||
| # "exit status N" and exits 1. This tool distinguishes 1 (policy violation or | ||
| # error) from 2 (bad invocation), so collapsing them would be a trap. | ||
| # | ||
| # Run the tests with: go test -C tools/stack-upgrade-policy ./... | ||
| set -euo pipefail | ||
|
|
||
| repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" | ||
| bin_dir="$(mktemp -d)" | ||
| trap 'rm -rf "${bin_dir}"' EXIT | ||
|
|
||
| go build -C "${repo_root}/tools/stack-upgrade-policy" -o "${bin_dir}/stack-upgrade-policy" . | ||
|
|
||
| # Not exec, so the trap above still runs, and not under errexit, so the exit | ||
| # code reaches the caller rather than aborting the shell first. | ||
| set +e | ||
| "${bin_dir}/stack-upgrade-policy" --root "${repo_root}" "$@" | ||
| status=$? | ||
| set -e | ||
| exit "${status}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # go build ./... drops the binary here; it must never be committed. | ||
| /stack-upgrade-policy |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.