@@ -2,9 +2,10 @@ package tests
22
33import (
44 "fmt"
5+ "io/fs"
56 "os"
6- "path"
77 "path/filepath"
8+ "strconv"
89 "strings"
910
1011 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -66,11 +67,12 @@ func perTestRuntimeInfo(suitePath, crdName string, featureGates []string) (*PerT
6667 crdFilesToCheck = append (crdFilesToCheck , filename )
6768 continue
6869 }
70+ versionsForCRD := versionsFrom (currCRD .Annotations )
6971
7072 // if the manifest has more than one clusterProfile, then the crd schema must have been the same no matter which
7173 // featuregates were used. Simply select the first one to check.
7274 clusterProfileToCheck := clusterProfilesForCRD .List ()[0 ]
73- featureGateStatus , err := featureGatesForClusterProfileFeatureSet ("../payload-manifests/featuregates" , clusterProfileToCheck , featureSet )
75+ featureGateStatus , err := featureGatesForClusterProfileFeatureSetVersion ("../payload-manifests/featuregates" , clusterProfileToCheck , featureSet , versionsForCRD )
7476 if err != nil {
7577 return nil , fmt .Errorf ("unable to find featureGates to check for %v: %w" , filename , err )
7678 }
@@ -138,6 +140,27 @@ func clusterProfilesFrom(annotations map[string]string) sets.String {
138140 return ret
139141}
140142
143+ func versionsFrom (annotations map [string ]string ) sets.Set [uint64 ] {
144+ var versionString string
145+ for k , v := range annotations {
146+ if strings .HasPrefix (k , "release.openshift.io/major-version" ) {
147+ versionString = v
148+ break
149+ }
150+ }
151+
152+ versions := sets .New [uint64 ]()
153+ for _ , version := range strings .Split (versionString , "," ) {
154+ versionInt , err := strconv .ParseUint (version , 10 , 64 )
155+ if err != nil {
156+ continue
157+ }
158+ versions .Insert (versionInt )
159+ }
160+
161+ return versions
162+ }
163+
141164func clusterProfilesShortNamesFrom (annotations map [string ]string ) sets.String {
142165 ret := sets .NewString ()
143166 for k , v := range annotations {
@@ -148,25 +171,51 @@ func clusterProfilesShortNamesFrom(annotations map[string]string) sets.String {
148171 return ret
149172}
150173
151- func featureGatesForClusterProfileFeatureSet (payloadFeatureGatePath , clusterProfile , featureSetName string ) (map [string ]bool , error ) {
174+ func featureGatesForClusterProfileFeatureSetVersion (payloadFeatureGatePath , clusterProfile , featureSetName string , crdVersions sets. Set [ uint64 ] ) (map [string ]bool , error ) {
152175 if len (featureSetName ) == 0 {
153176 // if the featureSetName is ungated, then all CRD schemas for every featureset on this clusterProfile must be the same.
154177 // Choose Default so that we get a valid manifest to check.
155178 featureSetName = "Default"
156179 }
157180
158- featureGateFilename := path .Join (
159- payloadFeatureGatePath ,
160- fmt .Sprintf ("featureGate-%s-%s.yaml" , clusterProfileToShortName [clusterProfile ], featureSetName ),
161- )
162- featureGateBytes , err := os .ReadFile (featureGateFilename )
163- if err != nil {
181+ var uncastFeatureGate map [string ]interface {}
182+
183+ if err := filepath .WalkDir (payloadFeatureGatePath , func (path string , d fs.DirEntry , err error ) error {
184+ if err != nil {
185+ return fmt .Errorf ("unable to walk directory %q: %w" , payloadFeatureGatePath , err )
186+ }
187+
188+ if d .IsDir () {
189+ return nil
190+ }
191+
192+ rawFile , err := os .ReadFile (path )
193+ if err != nil {
194+ return err
195+ }
196+ featureGate := map [string ]interface {}{}
197+ if err := kyaml .Unmarshal (rawFile , & featureGate ); err != nil {
198+ return err
199+ }
200+
201+ annotations , _ , err := unstructured .NestedStringMap (featureGate , "metadata" , "annotations" )
202+ if err != nil {
203+ return err
204+ }
205+
206+ if matchesClusterProfile (annotations , clusterProfile ) && matchesFeatureSet (annotations , featureSetName ) && matchesVersions (annotations , crdVersions ) {
207+ uncastFeatureGate = featureGate
208+ // We've found a matching feature gate yaml, so stop walking.
209+ return filepath .SkipAll
210+ }
211+
212+ return nil
213+ }); err != nil {
164214 return nil , err
165215 }
166- // use unstructured to pull this information to avoid vendoring openshift/api
167- uncastFeatureGate := map [string ]interface {}{}
168- if err := kyaml .Unmarshal (featureGateBytes , & uncastFeatureGate ); err != nil {
169- return nil , fmt .Errorf ("unable to parse featuregate %q: %w" , featureGateFilename , err )
216+
217+ if uncastFeatureGate == nil {
218+ return nil , fmt .Errorf ("no feature gate found for cluster profile %q, feature set %q, and versions %v" , clusterProfile , featureSetName , crdVersions )
170219 }
171220
172221 uncastFeatureGateSlice , _ , err := unstructured .NestedSlice (uncastFeatureGate , "status" , "featureGates" )
@@ -200,3 +249,24 @@ func featureGatesForClusterProfileFeatureSet(payloadFeatureGatePath, clusterProf
200249
201250 return featureGateMapping , nil
202251}
252+
253+ func matchesClusterProfile (annotations map [string ]string , clusterProfile string ) bool {
254+ _ , ok := annotations [clusterProfile ]
255+ return ok
256+ }
257+
258+ func matchesFeatureSet (annotations map [string ]string , featureSetName string ) bool {
259+ featureSet := annotations ["release.openshift.io/feature-set" ]
260+
261+ if featureSetName == "Default" {
262+ return featureSet == "" || featureSet == "Default"
263+ }
264+
265+ return featureSet == featureSetName
266+ }
267+
268+ func matchesVersions (annotations map [string ]string , crdVersions sets.Set [uint64 ]) bool {
269+ // When the CRD specified no versions, the we assume there is no variance across versions.
270+ // So we match all versions.
271+ return len (crdVersions ) == 0 || versionsFrom (annotations ).Intersection (crdVersions ).Len () > 0
272+ }
0 commit comments