Skip to content

Commit 2d6aae6

Browse files
committed
Add major version manifest filtering
1 parent bdd3553 commit 2d6aae6

29 files changed

Lines changed: 1044 additions & 1123 deletions

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/onsi/ginkgo/v2 v2.21.0
1212
github.com/onsi/gomega v1.35.1
1313
github.com/openshift-eng/openshift-tests-extension v0.0.0-20250220212757-b9c4d98a0c45
14-
github.com/openshift/api v0.0.0-20260116192047-6fb7fdae95fd
14+
github.com/openshift/api v0.0.0-20260126183958-606bd613f9f7
1515
github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13
1616
github.com/openshift/library-go v0.0.0-20260121132910-dc3a1c884c04
1717
github.com/operator-framework/api v0.17.1
@@ -34,6 +34,8 @@ require (
3434
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
3535
)
3636

37+
replace github.com/openshift/library-go => github.com/JoelSpeed/library-go v0.0.0-20260130121715-6e5ccfd0da42
38+
3739
require (
3840
cel.dev/expr v0.24.0 // indirect
3941
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
22
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
3+
github.com/JoelSpeed/library-go v0.0.0-20260130121715-6e5ccfd0da42 h1:uIrR1qWklQm8U7WgtSZnyxj8bxCRtzvQ9JDKWvihOCg=
4+
github.com/JoelSpeed/library-go v0.0.0-20260130121715-6e5ccfd0da42/go.mod h1:DCRz1EgdayEmr9b6KXKDL+DWBN0rGHu/VYADeHzPoOk=
35
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
46
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
57
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -86,12 +88,10 @@ github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
8688
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
8789
github.com/openshift-eng/openshift-tests-extension v0.0.0-20250220212757-b9c4d98a0c45 h1:hXpbYtP3iTh8oy/RKwKkcMziwchY3fIk95ciczf7cOA=
8890
github.com/openshift-eng/openshift-tests-extension v0.0.0-20250220212757-b9c4d98a0c45/go.mod h1:6gkP5f2HL0meusT0Aim8icAspcD1cG055xxBZ9yC68M=
89-
github.com/openshift/api v0.0.0-20260116192047-6fb7fdae95fd h1:Hpjq/55Qb0Gy65RewTSWWlyxpSovaRF86EPjYQkdlRU=
90-
github.com/openshift/api v0.0.0-20260116192047-6fb7fdae95fd/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY=
91+
github.com/openshift/api v0.0.0-20260126183958-606bd613f9f7 h1:96rhgJpWlWzKEslMd6aYFMixV9vQVY32M71JcO4Gzn0=
92+
github.com/openshift/api v0.0.0-20260126183958-606bd613f9f7/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY=
9193
github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13 h1:6rd4zSo2UaWQcAPZfHK9yzKVqH0BnMv1hqMzqXZyTds=
9294
github.com/openshift/client-go v0.0.0-20260108185524-48f4ccfc4e13/go.mod h1:YvOmPmV7wcJxpfhTDuFqqs2Xpb3M3ovsM6Qs/i2ptq4=
93-
github.com/openshift/library-go v0.0.0-20260121132910-dc3a1c884c04 h1:Fm9C8pT4l6VjpdqdhI1cBX9Y3D3S+rFxptVhCPBbMAI=
94-
github.com/openshift/library-go v0.0.0-20260121132910-dc3a1c884c04/go.mod h1:nIzWQQE49XbiKizVnVOip9CEB7HJ0hoJwNi3g3YKnKc=
9595
github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20241205171354-8006f302fd12 h1:AKx/w1qpS8We43bsRgf8Nll3CGlDHpr/WAXvuedTNZI=
9696
github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20241205171354-8006f302fd12/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
9797
github.com/operator-framework/api v0.17.1 h1:J/6+Xj4IEV8C7hcirqUFwOiZAU3PbnJhWvB0/bB51c4=

lib/manifest/manifest.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ type InclusionConfiguration struct {
3636

3737
// EnabledFeatureGates excludes manifests with a feature gate requirement when the condition is not met.
3838
EnabledFeatureGates sets.Set[string]
39+
40+
// MajorVersion, if non-nil, excludes manifests unless they match the major version.
41+
MajorVersion *uint64
3942
}
4043

4144
// GetImplicitlyEnabledCapabilities returns a set of capabilities that are implicitly enabled after a cluster update.
@@ -61,6 +64,7 @@ func GetImplicitlyEnabledCapabilities(
6164
manifestInclusionConfiguration.Capabilities,
6265
manifestInclusionConfiguration.Overrides,
6366
manifestInclusionConfiguration.EnabledFeatureGates,
67+
manifestInclusionConfiguration.MajorVersion,
6468
true,
6569
)
6670
// update manifest is enabled, no need to check
@@ -79,6 +83,7 @@ func GetImplicitlyEnabledCapabilities(
7983
manifestInclusionConfiguration.Capabilities,
8084
manifestInclusionConfiguration.Overrides,
8185
manifestInclusionConfiguration.EnabledFeatureGates,
86+
manifestInclusionConfiguration.MajorVersion,
8287
true,
8388
); err != nil {
8489
continue

pkg/cvo/featuregate_integration_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func TestFeatureGateManifestFiltering(t *testing.T) {
100100
}
101101

102102
// Test the manifest inclusion logic
103-
err := manifest.Include(nil, nil, nil, nil, nil, tt.enabledGates)
103+
err := manifest.Include(nil, nil, nil, nil, nil, tt.enabledGates, nil)
104104

105105
if tt.shouldInclude {
106106
if err != nil {
@@ -143,7 +143,7 @@ func TestSyncWorkIntegration(t *testing.T) {
143143
Obj: testObj,
144144
}
145145

146-
err := manifest.Include(nil, nil, nil, nil, nil, work.EnabledFeatureGates)
146+
err := manifest.Include(nil, nil, nil, nil, nil, work.EnabledFeatureGates, nil)
147147
if err != nil {
148148
t.Errorf("Expected manifest to be included with TestGate1 enabled, got error: %v", err)
149149
}
@@ -153,7 +153,7 @@ func TestSyncWorkIntegration(t *testing.T) {
153153
"release.openshift.io/feature-gate": "DisabledGate",
154154
})
155155

156-
err = manifest.Include(nil, nil, nil, nil, nil, work.EnabledFeatureGates)
156+
err = manifest.Include(nil, nil, nil, nil, nil, work.EnabledFeatureGates, nil)
157157
if err == nil {
158158
t.Error("Expected manifest to be excluded with DisabledGate not enabled, but no error occurred")
159159
}
@@ -262,7 +262,7 @@ func TestManifestFilteringExamples(t *testing.T) {
262262
Obj: obj,
263263
}
264264

265-
err := manifest.Include(nil, nil, nil, nil, nil, example.enabledGates)
265+
err := manifest.Include(nil, nil, nil, nil, nil, example.enabledGates, nil)
266266

267267
if example.shouldInclude {
268268
if err != nil {

pkg/cvo/sync_worker.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ func (w *SyncWorker) syncPayload(ctx context.Context, work *SyncWork) ([]configv
446446

447447
if w.payload != nil {
448448
implicitlyEnabledCaps = capability.SortedList(payload.GetImplicitlyEnabledCapabilities(payloadUpdate.Manifests, w.payload.Manifests,
449-
work.Capabilities, work.EnabledFeatureGates))
449+
work.Capabilities, work.EnabledFeatureGates, w.payload.MajorVersion))
450450
}
451451

452452
w.payload = payloadUpdate
@@ -1065,7 +1065,7 @@ func (w *SyncWorker) apply(ctx context.Context, work *SyncWork, maxWorkers int,
10651065
if task.Manifest.GVK != configv1.GroupVersion.WithKind("ClusterOperator") {
10661066
continue
10671067
}
1068-
if err := task.Manifest.Include(nil, nil, nil, &capabilities, work.Overrides, work.EnabledFeatureGates); err != nil {
1068+
if err := task.Manifest.Include(nil, nil, nil, &capabilities, work.Overrides, work.EnabledFeatureGates, payloadUpdate.MajorVersion); err != nil {
10691069
klog.V(manifestVerbosity).Infof("Skipping precreation of %s: %s", task, err)
10701070
continue
10711071
}
@@ -1085,7 +1085,7 @@ func (w *SyncWorker) apply(ctx context.Context, work *SyncWork, maxWorkers int,
10851085

10861086
klog.V(manifestVerbosity).Infof("Running sync for %s", task)
10871087

1088-
if err := task.Manifest.Include(nil, nil, nil, &capabilities, work.Overrides, work.EnabledFeatureGates); err != nil {
1088+
if err := task.Manifest.Include(nil, nil, nil, &capabilities, work.Overrides, work.EnabledFeatureGates, payloadUpdate.MajorVersion); err != nil {
10891089
klog.V(manifestVerbosity).Infof("Skipping %s: %s", task, err)
10901090
continue
10911091
}

pkg/payload/payload.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"time"
1414

1515
"k8s.io/klog/v2"
16+
"k8s.io/utils/ptr"
1617

1718
utilerrors "k8s.io/apimachinery/pkg/util/errors"
1819
"k8s.io/apimachinery/pkg/util/sets"
@@ -110,6 +111,7 @@ type Update struct {
110111
ImageRef *imagev1.ImageStream
111112

112113
Architecture string
114+
MajorVersion *uint64
113115

114116
// manifestHash is a hash of the manifests included in this payload
115117
ManifestHash string
@@ -211,7 +213,7 @@ func LoadUpdate(dir, releaseImage, excludeIdentifier string, requiredFeatureSet
211213
filteredMs := []manifest.Manifest{}
212214

213215
for _, manifest := range ms {
214-
if err := manifest.Include(&excludeIdentifier, &requiredFeatureSet, &profile, onlyKnownCaps, nil, enabledFeatureGates); err != nil {
216+
if err := manifest.Include(&excludeIdentifier, &requiredFeatureSet, &profile, onlyKnownCaps, nil, enabledFeatureGates, payload.MajorVersion); err != nil {
215217
klog.V(2).Infof("excluding %s: %v\n", manifest.String(), err)
216218
continue
217219
}
@@ -243,12 +245,12 @@ func LoadUpdate(dir, releaseImage, excludeIdentifier string, requiredFeatureSet
243245
// the current payload the updated manifest's capabilities are checked to see if any must be implicitly enabled.
244246
// All capabilities requiring implicit enablement are returned.
245247
func GetImplicitlyEnabledCapabilities(updatePayloadManifests []manifest.Manifest, currentPayloadManifests []manifest.Manifest,
246-
capabilities capability.ClusterCapabilities, enabledFeatureGates sets.Set[string]) sets.Set[configv1.ClusterVersionCapability] {
248+
capabilities capability.ClusterCapabilities, enabledFeatureGates sets.Set[string], majorVersion *uint64) sets.Set[configv1.ClusterVersionCapability] {
247249
clusterCaps := capability.GetCapabilitiesStatus(capabilities)
248250
return localmanifest.GetImplicitlyEnabledCapabilities(
249251
updatePayloadManifests,
250252
currentPayloadManifests,
251-
localmanifest.InclusionConfiguration{Capabilities: &clusterCaps, EnabledFeatureGates: enabledFeatureGates},
253+
localmanifest.InclusionConfiguration{Capabilities: &clusterCaps, EnabledFeatureGates: enabledFeatureGates, MajorVersion: majorVersion},
252254
capabilities.ImplicitlyEnabled,
253255
)
254256
}
@@ -284,6 +286,11 @@ func loadPayloadMetadata(releaseDir, releaseImage string) (*Update, error) {
284286
klog.V(2).Infof("Architecture from %s (%s) retrieved from runtime: %q", cincinnatiJSONFile, release.Version, arch)
285287
}
286288

289+
parsedVersion, err := semver.Parse(release.Version)
290+
if err != nil {
291+
return nil, fmt.Errorf("failed to parse release version %s: %w", release.Version, err)
292+
}
293+
287294
release.Image = releaseImage
288295

289296
imageRef, err := loadImageReferences(releaseDir)
@@ -299,6 +306,7 @@ func loadPayloadMetadata(releaseDir, releaseImage string) (*Update, error) {
299306
Release: release,
300307
ImageRef: imageRef,
301308
Architecture: arch,
309+
MajorVersion: ptr.To(parsedVersion.Major),
302310
}, nil
303311
}
304312

pkg/payload/payload_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"k8s.io/apimachinery/pkg/runtime/schema"
1616
"k8s.io/apimachinery/pkg/util/sets"
1717
"k8s.io/klog/v2"
18+
"k8s.io/utils/ptr"
1819

1920
configv1 "github.com/openshift/api/config/v1"
2021
imagev1 "github.com/openshift/api/image/v1"
@@ -66,6 +67,7 @@ func TestLoadUpdate(t *testing.T) {
6667
},
6768
},
6869
Architecture: architecture,
70+
MajorVersion: ptr.To(uint64(1)),
6971
ManifestHash: "DL-FFQ2Uem8=",
7072
Manifests: []manifest.Manifest{
7173
{
@@ -177,6 +179,7 @@ func TestLoadUpdateArchitecture(t *testing.T) {
177179
},
178180
},
179181
Architecture: "Multi",
182+
MajorVersion: ptr.To(uint64(1)),
180183
ManifestHash: "fvnVhLw92pE=",
181184
Manifests: []manifest.Manifest{
182185
{
@@ -365,7 +368,7 @@ func TestGetImplicitlyEnabledCapabilities(t *testing.T) {
365368
if tt.pathExt == "test10" {
366369
updateMans = append(updateMans, updateMans[0])
367370
}
368-
caps := GetImplicitlyEnabledCapabilities(updateMans, currentMans, tt.capabilities, sets.Set[string]{})
371+
caps := GetImplicitlyEnabledCapabilities(updateMans, currentMans, tt.capabilities, sets.Set[string]{}, nil)
369372
if diff := cmp.Diff(tt.wantImplicit, caps); diff != "" {
370373
t.Errorf("%s: wantImplicit differs from expected:\n%s", tt.name, diff)
371374
}

pkg/payload/render.go

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package payload
22

33
import (
44
"bytes"
5+
"encoding/json"
56
"fmt"
67
"os"
78
"path/filepath"
89
"strings"
910
"text/template"
1011

12+
"github.com/blang/semver/v4"
1113
"github.com/openshift/api/config"
1214
configv1 "github.com/openshift/api/config/v1"
1315
"github.com/openshift/library-go/pkg/manifest"
@@ -40,6 +42,11 @@ func Render(outputDir, releaseImage, featureGateManifestPath, clusterProfile str
4042
return fmt.Errorf("error parsing feature gate manifest: %w", err)
4143
}
4244

45+
payloadVersion, err := loadReleaseVersion(releaseManifestsDir)
46+
if err != nil {
47+
return fmt.Errorf("error loading release version: %w", err)
48+
}
49+
4350
tasks := []struct {
4451
idir string
4552
odir string
@@ -70,7 +77,7 @@ func Render(outputDir, releaseImage, featureGateManifestPath, clusterProfile str
7077
}}
7178
var errs []error
7279
for _, task := range tasks {
73-
if err := renderDir(renderConfig, task.idir, task.odir, requiredFeatureSet, enabledFeatureGates, &clusterProfile, task.processTemplate, task.skipFiles, task.filterGroupKind); err != nil {
80+
if err := renderDir(renderConfig, task.idir, task.odir, requiredFeatureSet, enabledFeatureGates, &clusterProfile, ptr.To(payloadVersion.Major), task.processTemplate, task.skipFiles, task.filterGroupKind); err != nil {
7481
errs = append(errs, err)
7582
}
7683
}
@@ -82,8 +89,8 @@ func Render(outputDir, releaseImage, featureGateManifestPath, clusterProfile str
8289
return nil
8390
}
8491

85-
func renderDir(renderConfig manifestRenderConfig, idir, odir string, requiredFeatureSet *string, enabledFeatureGates sets.Set[string], clusterProfile *string, processTemplate bool, skipFiles sets.Set[string], filterGroupKind sets.Set[schema.GroupKind]) error {
86-
klog.Infof("Filtering manifests in %s for feature set %v, cluster profile %v and enabled feature gates %v", idir, *requiredFeatureSet, *clusterProfile, enabledFeatureGates.UnsortedList())
92+
func renderDir(renderConfig manifestRenderConfig, idir, odir string, requiredFeatureSet *string, enabledFeatureGates sets.Set[string], clusterProfile *string, majorVersion *uint64, processTemplate bool, skipFiles sets.Set[string], filterGroupKind sets.Set[schema.GroupKind]) error {
93+
klog.Infof("Filtering manifests in %s for feature set %v, cluster profile %v, enabled feature gates %v, and major version %v", idir, *requiredFeatureSet, *clusterProfile, enabledFeatureGates.UnsortedList(), ptr.Deref(majorVersion, 0))
8794

8895
if err := os.MkdirAll(odir, 0666); err != nil {
8996
return err
@@ -133,7 +140,7 @@ func renderDir(renderConfig manifestRenderConfig, idir, odir string, requiredFea
133140
for _, manifest := range manifests {
134141
if len(filterGroupKind) > 0 && !filterGroupKind.Has(manifest.GVK.GroupKind()) {
135142
klog.Infof("excluding %s because we do not render that group/kind", manifest.String())
136-
} else if err := manifest.Include(nil, requiredFeatureSet, clusterProfile, nil, nil, enabledFeatureGates); err != nil {
143+
} else if err := manifest.Include(nil, requiredFeatureSet, clusterProfile, nil, nil, enabledFeatureGates, majorVersion); err != nil {
137144
klog.Infof("excluding %s: %v", manifest.String(), err)
138145
} else {
139146
filteredManifests = append(filteredManifests, string(manifest.Raw))
@@ -238,3 +245,27 @@ func parseFeatureGateManifest(featureGateManifestPath string) (*string, sets.Set
238245

239246
return requiredFeatureSet, enabledFeatureGates, nil
240247
}
248+
249+
func loadReleaseVersion(releaseDir string) (semver.Version, error) {
250+
path := filepath.Join(releaseDir, cincinnatiJSONFile)
251+
data, err := os.ReadFile(path)
252+
if err != nil {
253+
return semver.Version{}, err
254+
}
255+
256+
var metadata metadata
257+
if err := json.Unmarshal(data, &metadata); err != nil {
258+
return semver.Version{}, fmt.Errorf("unmarshal Cincinnati metadata: %w", err)
259+
}
260+
261+
if metadata.Version == "" {
262+
return semver.Version{}, errors.New("missing required Cincinnati metadata version")
263+
}
264+
265+
parsedVersion, err := semver.Parse(metadata.Version)
266+
if err != nil {
267+
return semver.Version{}, fmt.Errorf("Cincinnati metadata version %q is not a valid semantic version: %v", metadata.Version, err)
268+
}
269+
270+
return parsedVersion, nil
271+
}

0 commit comments

Comments
 (0)