@@ -5,19 +5,25 @@ import (
5
5
"encoding/json"
6
6
"fmt"
7
7
"regexp"
8
+ "sort"
8
9
"strconv"
9
10
"strings"
10
11
11
12
"github.com/openshift/library-go/pkg/operator/v1helpers"
12
13
13
14
appsv1 "k8s.io/api/apps/v1"
14
15
"k8s.io/apimachinery/pkg/util/sets"
16
+ _ "k8s.io/apiserver/pkg/features"
17
+ "k8s.io/apiserver/pkg/util/feature"
15
18
"k8s.io/client-go/kubernetes"
19
+ "k8s.io/component-base/featuregate"
16
20
"k8s.io/klog/v2"
17
21
22
+ configv1 "github.com/openshift/api/config/v1"
18
23
operatorv1 "github.com/openshift/api/operator/v1"
19
24
"github.com/openshift/library-go/pkg/controller/factory"
20
25
libgoetcd "github.com/openshift/library-go/pkg/operator/configobserver/etcd"
26
+ "github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
21
27
"github.com/openshift/library-go/pkg/operator/events"
22
28
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
23
29
"github.com/openshift/library-go/pkg/operator/resource/resourcehash"
@@ -51,6 +57,8 @@ type OAuthAPIServerWorkload struct {
51
57
operatorImagePullSpec string
52
58
kubeClient kubernetes.Interface
53
59
versionRecorder status.VersionGetter
60
+
61
+ featureGates featuregates.FeatureGate
54
62
}
55
63
56
64
// NewOAuthAPIServerWorkload creates new OAuthAPIServerWorkload struct
@@ -61,6 +69,7 @@ func NewOAuthAPIServerWorkload(
61
69
targetNamespace string ,
62
70
targetImagePullSpec string ,
63
71
operatorImagePullSpec string ,
72
+ featureGates featuregates.FeatureGate ,
64
73
kubeClient kubernetes.Interface ,
65
74
versionRecorder status.VersionGetter ,
66
75
) * OAuthAPIServerWorkload {
@@ -71,6 +80,7 @@ func NewOAuthAPIServerWorkload(
71
80
targetNamespace : targetNamespace ,
72
81
targetImagePullSpec : targetImagePullSpec ,
73
82
operatorImagePullSpec : operatorImagePullSpec ,
83
+ featureGates : featureGates ,
74
84
kubeClient : kubeClient ,
75
85
versionRecorder : versionRecorder ,
76
86
}
@@ -157,6 +167,15 @@ func (c *OAuthAPIServerWorkload) syncDeployment(ctx context.Context, operatorSpe
157
167
// log level verbosity is taken from the spec always
158
168
args ["v" ] = []string {loglevelToKlog (operatorSpec .LogLevel )}
159
169
170
+ // Set feature gates
171
+ features , err := getFeatureGates (c .featureGates )
172
+ if err != nil {
173
+ return nil , err
174
+ }
175
+ if len (features ) > 0 {
176
+ args ["feature-gates" ] = []string {strings .Join (features , "," )}
177
+ }
178
+
160
179
// use string replacer for simple things
161
180
r := strings .NewReplacer (
162
181
"${IMAGE}" , c .targetImagePullSpec ,
@@ -287,3 +306,36 @@ func GetAPIServerArgumentsRaw(authOperatorSpec operatorv1.OperatorSpec) (map[str
287
306
288
307
return cfgUnstructured .APIServerArguments , nil
289
308
}
309
+
310
+ func getFeatureGates (featureGates featuregates.FeatureGate ) ([]string , error ) {
311
+ if featureGates == nil {
312
+ return nil , fmt .Errorf ("featureGates cannot be nil" )
313
+ }
314
+
315
+ // Get a list of known Kubernetes feature gates
316
+ known := feature .DefaultMutableFeatureGate .GetAll ()
317
+
318
+ // Filter out OCP-specific feature gates
319
+ filteredFeatures := []string {}
320
+ for _ , feature := range featureGates .KnownFeatures () {
321
+ _ , ok := known [featuregate .Feature (feature )]
322
+ if ! ok {
323
+ continue
324
+ }
325
+ filteredFeatures = append (filteredFeatures , string (feature ))
326
+ }
327
+ sort .Strings (filteredFeatures )
328
+
329
+ // Format feature gates statuses
330
+ formattedFeatures := []string {}
331
+ for _ , featureGate := range filteredFeatures {
332
+ fgName := configv1 .FeatureGateName (featureGate )
333
+ if featureGates .Enabled (fgName ) {
334
+ formattedFeatures = append (formattedFeatures , fmt .Sprintf ("%s=true" , featureGate ))
335
+ } else {
336
+ formattedFeatures = append (formattedFeatures , fmt .Sprintf ("%s=false" , featureGate ))
337
+ }
338
+ }
339
+
340
+ return formattedFeatures , nil
341
+ }
0 commit comments