From 3f5f8d7760ea4c4260233b650e223bfd2b4104c7 Mon Sep 17 00:00:00 2001 From: Jakub Hadvig Date: Thu, 9 Jul 2026 20:53:01 +0200 Subject: [PATCH] pkg/payload: Tolerate unknown template fields during payload loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make template rendering errors non-fatal during LoadUpdate. When an older CVO binary loads a newer payload that uses template fields the older binary does not know about (e.g. .Images added in 5.0), the manifest is skipped with a warning instead of failing the entire payload load. The new CVO binary will re-load the full payload after it replaces the old one at run-level 0. Without this fix, 4.22→5.0 major upgrades fail with ReleaseAccepted=False because the 4.22 CVO cannot render 5.0 manifests that reference .Images. Co-Authored-By: Claude Opus 4.6 (1M context) --- pkg/payload/payload.go | 8 +++++++- pkg/payload/payload_test.go | 20 +++++++++++++++++++ .../manifests/0000_00_valid.yaml | 9 +++++++++ .../manifests/0000_50_unknown-field.yaml | 9 +++++++++ .../release-manifests/image-references | 7 +++++++ .../release-manifests/release-metadata | 1 + 6 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 pkg/payload/testdata/payload-unknown-template/manifests/0000_00_valid.yaml create mode 100644 pkg/payload/testdata/payload-unknown-template/manifests/0000_50_unknown-field.yaml create mode 100644 pkg/payload/testdata/payload-unknown-template/release-manifests/image-references create mode 100644 pkg/payload/testdata/payload-unknown-template/release-manifests/release-metadata diff --git a/pkg/payload/payload.go b/pkg/payload/payload.go index 7c7af838b8..f71b76fb2b 100644 --- a/pkg/payload/payload.go +++ b/pkg/payload/payload.go @@ -195,7 +195,13 @@ func LoadUpdate(dir, releaseImage, excludeIdentifier string, requiredFeatureSet if task.preprocess != nil { raw, err = task.preprocess(raw) if err != nil { - errs = append(errs, fmt.Errorf("preprocess %s: %w", file.Name(), err)) + // Template rendering may fail when an older CVO binary + // loads a newer payload that uses template fields the + // older binary does not know about (e.g. .Images). Skip + // the manifest with a warning — the new CVO binary will + // re-load the full payload after it replaces the old one + // at run-level 0. + klog.Warningf("Skipping manifest %s: template rendering failed (may require newer CVO): %v", file.Name(), err) continue } } diff --git a/pkg/payload/payload_test.go b/pkg/payload/payload_test.go index cf2bf0856e..ba76f5614c 100644 --- a/pkg/payload/payload_test.go +++ b/pkg/payload/payload_test.go @@ -150,6 +150,26 @@ func TestLoadUpdate(t *testing.T) { } } +func TestLoadUpdateSkipsUnknownTemplateFields(t *testing.T) { + update, err := LoadUpdate("testdata/payload-unknown-template", "image:test", "", "", DefaultClusterProfile, nil, sets.Set[string]{}) + if err != nil { + t.Fatalf("LoadUpdate should not fail when a manifest uses unknown template fields, got: %v", err) + } + + var foundValid bool + for _, m := range update.Manifests { + if m.OriginalFilename == "0000_00_valid.yaml" { + foundValid = true + } + if m.OriginalFilename == "0000_50_unknown-field.yaml" { + t.Error("manifest with unknown template field should have been skipped, but was loaded") + } + } + if !foundValid { + t.Error("expected valid manifest (0000_00_valid.yaml) to be loaded") + } +} + func TestLoadUpdateArchitecture(t *testing.T) { type args struct { dir string diff --git a/pkg/payload/testdata/payload-unknown-template/manifests/0000_00_valid.yaml b/pkg/payload/testdata/payload-unknown-template/manifests/0000_00_valid.yaml new file mode 100644 index 0000000000..e8295d59d1 --- /dev/null +++ b/pkg/payload/testdata/payload-unknown-template/manifests/0000_00_valid.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: valid-manifest + namespace: test + annotations: + include.release.openshift.io/self-managed-high-availability: "true" +data: + release-image: '{{.ReleaseImage}}' diff --git a/pkg/payload/testdata/payload-unknown-template/manifests/0000_50_unknown-field.yaml b/pkg/payload/testdata/payload-unknown-template/manifests/0000_50_unknown-field.yaml new file mode 100644 index 0000000000..746c4c8ad5 --- /dev/null +++ b/pkg/payload/testdata/payload-unknown-template/manifests/0000_50_unknown-field.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: future-manifest + namespace: test + annotations: + include.release.openshift.io/self-managed-high-availability: "true" +data: + image: '{{index .FutureField "some-key"}}' diff --git a/pkg/payload/testdata/payload-unknown-template/release-manifests/image-references b/pkg/payload/testdata/payload-unknown-template/release-manifests/image-references new file mode 100644 index 0000000000..c955da2e3c --- /dev/null +++ b/pkg/payload/testdata/payload-unknown-template/release-manifests/image-references @@ -0,0 +1,7 @@ +{ + "kind": "ImageStream", + "apiVersion": "image.openshift.io/v1", + "metadata": { + "name": "1.0.0-test" + } +} diff --git a/pkg/payload/testdata/payload-unknown-template/release-manifests/release-metadata b/pkg/payload/testdata/payload-unknown-template/release-manifests/release-metadata new file mode 100644 index 0000000000..4f6bdf4d9c --- /dev/null +++ b/pkg/payload/testdata/payload-unknown-template/release-manifests/release-metadata @@ -0,0 +1 @@ +{"kind":"cincinnati-metadata-v0","version":"1.0.0-test"} \ No newline at end of file