@@ -7,8 +7,11 @@ import (
7
7
"io/ioutil"
8
8
"net/http"
9
9
"net/url"
10
+ "slices"
10
11
"strings"
11
12
13
+ "github.com/pkg/errors"
14
+ "github.com/sirupsen/logrus"
12
15
"k8s.io/apimachinery/pkg/runtime/schema"
13
16
14
17
corev1 "k8s.io/api/core/v1"
@@ -22,6 +25,7 @@ import (
22
25
operatorv1 "github.com/openshift/api/operator/v1"
23
26
configclient "github.com/openshift/client-go/config/clientset/versioned"
24
27
operatorclient "github.com/openshift/client-go/operator/clientset/versioned"
28
+
25
29
"github.com/openshift/origin/test/extended/util/azure"
26
30
)
27
31
@@ -70,6 +74,13 @@ type ClusterConfiguration struct {
70
74
71
75
// IsNoOptionalCapabilities indicates the cluster has no optional capabilities enabled
72
76
HasNoOptionalCapabilities bool
77
+
78
+ // APIGroups contains the set of API groups available in the cluster
79
+ APIGroups sets.Set [string ] `json:"-"`
80
+ // EnabledFeatureGates contains the set of enabled feature gates in the cluster
81
+ EnabledFeatureGates sets.Set [string ] `json:"-"`
82
+ // DisabledFeatureGates contains the set of disabled feature gates in the cluster
83
+ DisabledFeatureGates sets.Set [string ] `json:"-"`
73
84
}
74
85
75
86
func (c * ClusterConfiguration ) ToJSONString () string {
@@ -91,6 +102,80 @@ type ClusterState struct {
91
102
ControlPlaneTopology * configv1.TopologyMode
92
103
OptionalCapabilities []configv1.ClusterVersionCapability
93
104
Version * configv1.ClusterVersion
105
+ APIGroups sets.Set [string ]
106
+ EnabledFeatureGates sets.Set [string ]
107
+ DisabledFeatureGates sets.Set [string ]
108
+ }
109
+
110
+ // discoverAPIGroups discovers available API groups in the cluster
111
+ func discoverAPIGroups (coreClient clientset.Interface ) (sets.Set [string ], error ) {
112
+ logrus .Debugf ("Discovering API Groups..." )
113
+ discoveryClient := coreClient .Discovery ()
114
+ groups , err := discoveryClient .ServerGroups ()
115
+ if err != nil {
116
+ return nil , err
117
+ }
118
+
119
+ apiGroups := sets .New [string ]()
120
+ for _ , apiGroup := range groups .Groups {
121
+ // ignore the empty group
122
+ if apiGroup .Name == "" {
123
+ continue
124
+ }
125
+ apiGroups .Insert (apiGroup .Name )
126
+ }
127
+
128
+ sortedAPIGroups := apiGroups .UnsortedList ()
129
+ slices .Sort (sortedAPIGroups )
130
+
131
+ logrus .WithField ("apiGroups" , strings .Join (sortedAPIGroups , ", " )).
132
+ Debugf ("Discovered %d API Groups" , apiGroups .Len ())
133
+
134
+ return apiGroups , nil
135
+ }
136
+
137
+ // discoverFeatureGates discovers feature gates in the cluster
138
+ func discoverFeatureGates (configClient configclient.Interface , clusterVersion * configv1.ClusterVersion ) (enabled , disabled sets.Set [string ], err error ) {
139
+ logrus .Debugf ("Discovering feature gates..." )
140
+ featureGate , err := configClient .ConfigV1 ().FeatureGates ().Get (context .Background (), "cluster" , metav1.GetOptions {})
141
+ if err != nil {
142
+ return nil , nil , errors .WithMessage (err , "encountered an error while discovering feature gates" )
143
+ }
144
+
145
+ desiredVersion := clusterVersion .Status .Desired .Version
146
+ if len (desiredVersion ) == 0 && len (clusterVersion .Status .History ) > 0 {
147
+ desiredVersion = clusterVersion .Status .History [0 ].Version
148
+ }
149
+
150
+ enabled = sets .New [string ]()
151
+ disabled = sets .New [string ]()
152
+ for _ , featureGateValues := range featureGate .Status .FeatureGates {
153
+ if featureGateValues .Version != desiredVersion {
154
+ logrus .Warningf ("Feature gates for version %s not found, skipping" , desiredVersion )
155
+ continue
156
+ }
157
+ for _ , enabledGate := range featureGateValues .Enabled {
158
+ enabled .Insert (string (enabledGate .Name ))
159
+ }
160
+ for _ , disabledGate := range featureGateValues .Disabled {
161
+ disabled .Insert (string (disabledGate .Name ))
162
+ }
163
+ break
164
+ }
165
+
166
+ sortedEnabledGates := enabled .UnsortedList ()
167
+ slices .Sort (sortedEnabledGates )
168
+
169
+ logrus .WithField ("featureGates" , strings .Join (sortedEnabledGates , ", " )).
170
+ Debugf ("Discovered %d enabled feature gates" , len (sortedEnabledGates ))
171
+
172
+ sortedDisabledGates := disabled .UnsortedList ()
173
+ slices .Sort (sortedDisabledGates )
174
+
175
+ logrus .WithField ("featureGates" , strings .Join (sortedDisabledGates , ", " )).
176
+ Debugf ("Discovered %d disabled feature gates" , len (sortedDisabledGates ))
177
+
178
+ return enabled , disabled , nil
94
179
}
95
180
96
181
// DiscoverClusterState creates a ClusterState based on a live cluster
@@ -156,6 +241,24 @@ func DiscoverClusterState(clientConfig *rest.Config) (*ClusterState, error) {
156
241
state .Version = clusterVersion
157
242
state .OptionalCapabilities = clusterVersion .Status .Capabilities .EnabledCapabilities
158
243
244
+ // Discover available API groups
245
+ state .APIGroups , err = discoverAPIGroups (coreClient )
246
+ if err != nil {
247
+ return nil , errors .WithMessage (err , "encountered an error while discovering API groups" )
248
+ }
249
+
250
+ // Discover feature gates
251
+ if state .APIGroups .Has ("config.openshift.io" ) {
252
+ state .EnabledFeatureGates , state .DisabledFeatureGates , err = discoverFeatureGates (configClient , clusterVersion )
253
+ if err != nil {
254
+ logrus .WithError (err ).Warn ("ignoring error from discoverFeatureGates" )
255
+ }
256
+ } else {
257
+ state .EnabledFeatureGates = sets .New [string ]()
258
+ state .DisabledFeatureGates = sets .New [string ]()
259
+ logrus .Infof ("config.openshift.io API group not found, skipping feature gate discovery" )
260
+ }
261
+
159
262
return state , nil
160
263
}
161
264
@@ -271,63 +374,10 @@ func LoadConfig(state *ClusterState) (*ClusterConfiguration, error) {
271
374
// have to scan MachineConfig objects to figure this out? For now, callers can
272
375
// can just manually override with --provider...
273
376
274
- return config , nil
275
- }
276
-
277
- // MatchFn returns a function that tests if a named function should be run based on
278
- // the cluster configuration
279
- func (c * ClusterConfiguration ) MatchFn () func (string ) bool {
280
- var skips []string
281
- skips = append (skips , fmt .Sprintf ("[Skipped:%s]" , c .ProviderName ))
282
-
283
- if c .IsIBMROKS {
284
- skips = append (skips , "[Skipped:ibmroks]" )
285
- }
286
- if c .NetworkPlugin != "" {
287
- skips = append (skips , fmt .Sprintf ("[Skipped:Network/%s]" , c .NetworkPlugin ))
288
- if c .NetworkPluginMode != "" {
289
- skips = append (skips , fmt .Sprintf ("[Skipped:Network/%s/%s]" , c .NetworkPlugin , c .NetworkPluginMode ))
290
- }
291
- }
292
-
293
- if c .Disconnected {
294
- skips = append (skips , "[Skipped:Disconnected]" )
295
- }
377
+ // Copy API groups and feature gates from cluster state
378
+ config .APIGroups = state .APIGroups
379
+ config .EnabledFeatureGates = state .EnabledFeatureGates
380
+ config .DisabledFeatureGates = state .DisabledFeatureGates
296
381
297
- if c .IsProxied {
298
- skips = append (skips , "[Skipped:Proxy]" )
299
- }
300
-
301
- if c .SingleReplicaTopology {
302
- skips = append (skips , "[Skipped:SingleReplicaTopology]" )
303
- }
304
-
305
- if ! c .HasIPv4 {
306
- skips = append (skips , "[Feature:Networking-IPv4]" )
307
- }
308
- if ! c .HasIPv6 {
309
- skips = append (skips , "[Feature:Networking-IPv6]" )
310
- }
311
- if ! c .HasIPv4 || ! c .HasIPv6 {
312
- // lack of "]" is intentional; this matches multiple tags
313
- skips = append (skips , "[Feature:IPv6DualStack" )
314
- }
315
-
316
- if ! c .HasSCTP {
317
- skips = append (skips , "[Feature:SCTPConnectivity]" )
318
- }
319
-
320
- if c .HasNoOptionalCapabilities {
321
- skips = append (skips , "[Skipped:NoOptionalCapabilities]" )
322
- }
323
-
324
- matchFn := func (name string ) bool {
325
- for _ , skip := range skips {
326
- if strings .Contains (name , skip ) {
327
- return false
328
- }
329
- }
330
- return true
331
- }
332
- return matchFn
382
+ return config , nil
333
383
}
0 commit comments