Skip to content

Commit 95f30f1

Browse files
fxierhk8s-publishing-bot
authored andcommitted
[sample-apiserver] Fix: Use Correct Effective Version for kube (#125941)
* Fix slice copy of VersionedSpecs in FeatureGate. Signed-off-by: Siyuan Zhang <[email protected]> * Update wardle to kube version mapping Signed-off-by: Siyuan Zhang <[email protected]> Signed-off-by: Feilian Xie <[email protected]> Co-authored-by: Feilian Xie <[email protected]> * Add cap to wardleEmulationVersionToKubeEmulationVersion. Signed-off-by: Siyuan Zhang <[email protected]> * Add integration test for default BanFlunder behavior in version 1.2 without Wardle feature gate. Signed-off-by: Siyuan Zhang <[email protected]> --------- Signed-off-by: Siyuan Zhang <[email protected]> Signed-off-by: Feilian Xie <[email protected]> Co-authored-by: Siyuan Zhang <[email protected]> Kubernetes-commit: ebdca538058d2265cb8dc528d0145faea0a6a7cf
1 parent 763ac17 commit 95f30f1

File tree

4 files changed

+63
-27
lines changed

4 files changed

+63
-27
lines changed

featuregate/feature_gate.go

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,6 @@ type FeatureGate interface {
115115
// set on the copy without mutating the original. This is useful for validating
116116
// config against potential feature gate changes before committing those changes.
117117
DeepCopy() MutableVersionedFeatureGate
118-
// CopyKnownFeatures returns a partial copy of the FeatureGate object, with all the known features and overrides.
119-
// This is useful for creating a new instance of feature gate without inheriting all the enabled configurations of the base feature gate.
120-
CopyKnownFeatures() MutableVersionedFeatureGate
121118
// Validate checks if the flag gates are valid at the emulated version.
122119
Validate() []error
123120
}
@@ -189,6 +186,10 @@ type MutableVersionedFeatureGate interface {
189186
ExplicitlySet(name Feature) bool
190187
// ResetFeatureValueToDefault resets the value of the feature back to the default value.
191188
ResetFeatureValueToDefault(name Feature) error
189+
// DeepCopyAndReset copies all the registered features of the FeatureGate object, with all the known features and overrides,
190+
// and resets all the enabled status of the new feature gate.
191+
// This is useful for creating a new instance of feature gate without inheriting all the enabled configurations of the base feature gate.
192+
DeepCopyAndReset() MutableVersionedFeatureGate
192193
}
193194

194195
// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
@@ -423,10 +424,7 @@ func (f *featureGate) AddVersioned(features map[Feature]VersionedSpecs) error {
423424
}
424425

425426
// Copy existing state
426-
known := map[Feature]VersionedSpecs{}
427-
for k, v := range f.known.Load().(map[Feature]VersionedSpecs) {
428-
known[k] = v
429-
}
427+
known := f.GetAllVersioned()
430428

431429
for name, specs := range features {
432430
sort.Sort(specs)
@@ -458,11 +456,8 @@ func (f *featureGate) OverrideDefaultAtVersion(name Feature, override bool, ver
458456
return fmt.Errorf("cannot override default for feature %q: gates already added to a flag set", name)
459457
}
460458

461-
known := map[Feature]VersionedSpecs{}
462-
for k, v := range f.known.Load().(map[Feature]VersionedSpecs) {
463-
sort.Sort(v)
464-
known[k] = v
465-
}
459+
// Copy existing state
460+
known := f.GetAllVersioned()
466461

467462
specs, ok := known[name]
468463
if !ok {
@@ -509,7 +504,9 @@ func (f *featureGate) GetAll() map[Feature]FeatureSpec {
509504
func (f *featureGate) GetAllVersioned() map[Feature]VersionedSpecs {
510505
retval := map[Feature]VersionedSpecs{}
511506
for k, v := range f.known.Load().(map[Feature]VersionedSpecs) {
512-
retval[k] = v
507+
vCopy := make([]FeatureSpec, len(v))
508+
_ = copy(vCopy, v)
509+
retval[k] = vCopy
513510
}
514511
return retval
515512
}
@@ -660,9 +657,10 @@ func (f *featureGate) KnownFeatures() []string {
660657
return known
661658
}
662659

663-
// CopyKnownFeatures returns a partial copy of the FeatureGate object, with all the known features and overrides.
660+
// DeepCopyAndReset copies all the registered features of the FeatureGate object, with all the known features and overrides,
661+
// and resets all the enabled status of the new feature gate.
664662
// This is useful for creating a new instance of feature gate without inheriting all the enabled configurations of the base feature gate.
665-
func (f *featureGate) CopyKnownFeatures() MutableVersionedFeatureGate {
663+
func (f *featureGate) DeepCopyAndReset() MutableVersionedFeatureGate {
666664
fg := NewVersionedFeatureGate(f.EmulationVersion())
667665
known := f.GetAllVersioned()
668666
fg.known.Store(known)
@@ -676,10 +674,7 @@ func (f *featureGate) DeepCopy() MutableVersionedFeatureGate {
676674
f.lock.Lock()
677675
defer f.lock.Unlock()
678676
// Copy existing state.
679-
known := map[Feature]VersionedSpecs{}
680-
for k, v := range f.known.Load().(map[Feature]VersionedSpecs) {
681-
known[k] = v
682-
}
677+
known := f.GetAllVersioned()
683678
enabled := map[Feature]bool{}
684679
for k, v := range f.enabled.Load().(map[Feature]bool) {
685680
enabled[k] = v

featuregate/feature_gate_test.go

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ func TestFeatureGateOverrideDefault(t *testing.T) {
600600
f := NewFeatureGate()
601601
require.NoError(t, f.Add(map[Feature]FeatureSpec{"TestFeature": {Default: false}}))
602602
require.NoError(t, f.OverrideDefault("TestFeature", true))
603-
fcopy := f.CopyKnownFeatures()
603+
fcopy := f.DeepCopyAndReset()
604604
if !f.Enabled("TestFeature") {
605605
t.Error("TestFeature should be enabled by override")
606606
}
@@ -609,6 +609,19 @@ func TestFeatureGateOverrideDefault(t *testing.T) {
609609
}
610610
})
611611

612+
t.Run("overrides are not passed over after CopyKnownFeatures", func(t *testing.T) {
613+
f := NewFeatureGate()
614+
require.NoError(t, f.Add(map[Feature]FeatureSpec{"TestFeature": {Default: false}}))
615+
fcopy := f.DeepCopyAndReset()
616+
require.NoError(t, f.OverrideDefault("TestFeature", true))
617+
if !f.Enabled("TestFeature") {
618+
t.Error("TestFeature should be enabled by override")
619+
}
620+
if fcopy.Enabled("TestFeature") {
621+
t.Error("default override should not be passed over after CopyKnownFeatures")
622+
}
623+
})
624+
612625
t.Run("reflected in known features", func(t *testing.T) {
613626
f := NewFeatureGate()
614627
if err := f.Add(map[Feature]FeatureSpec{"TestFeature": {
@@ -1351,6 +1364,34 @@ func TestVersionedFeatureGateOverrideDefault(t *testing.T) {
13511364
}
13521365
})
13531366

1367+
t.Run("overrides are not passed over after deep copies", func(t *testing.T) {
1368+
f := NewVersionedFeatureGate(version.MustParse("1.29"))
1369+
require.NoError(t, f.SetEmulationVersion(version.MustParse("1.28")))
1370+
if err := f.AddVersioned(map[Feature]VersionedSpecs{
1371+
"TestFeature": {
1372+
{Version: version.MustParse("1.28"), Default: false},
1373+
{Version: version.MustParse("1.29"), Default: true},
1374+
},
1375+
}); err != nil {
1376+
t.Fatal(err)
1377+
}
1378+
assert.False(t, f.Enabled("TestFeature"))
1379+
1380+
fcopy := f.DeepCopy()
1381+
require.NoError(t, f.OverrideDefault("TestFeature", true))
1382+
require.NoError(t, f.OverrideDefaultAtVersion("TestFeature", false, version.MustParse("1.29")))
1383+
assert.True(t, f.Enabled("TestFeature"))
1384+
assert.False(t, fcopy.Enabled("TestFeature"))
1385+
1386+
require.NoError(t, f.SetEmulationVersion(version.MustParse("1.29")))
1387+
assert.False(t, f.Enabled("TestFeature"))
1388+
assert.False(t, fcopy.Enabled("TestFeature"))
1389+
1390+
require.NoError(t, fcopy.SetEmulationVersion(version.MustParse("1.29")))
1391+
assert.False(t, f.Enabled("TestFeature"))
1392+
assert.True(t, fcopy.Enabled("TestFeature"))
1393+
})
1394+
13541395
t.Run("reflected in known features", func(t *testing.T) {
13551396
f := NewVersionedFeatureGate(version.MustParse("1.29"))
13561397
require.NoError(t, f.SetEmulationVersion(version.MustParse("1.28")))
@@ -1536,7 +1577,7 @@ func TestCopyKnownFeatures(t *testing.T) {
15361577
require.NoError(t, f.Add(map[Feature]FeatureSpec{"FeatureA": {Default: false}, "FeatureB": {Default: false}}))
15371578
require.NoError(t, f.Set("FeatureA=true"))
15381579
require.NoError(t, f.OverrideDefault("FeatureB", true))
1539-
fcopy := f.CopyKnownFeatures()
1580+
fcopy := f.DeepCopyAndReset()
15401581
require.NoError(t, f.Add(map[Feature]FeatureSpec{"FeatureC": {Default: false}}))
15411582

15421583
assert.True(t, f.Enabled("FeatureA"))

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ require (
2626
golang.org/x/sys v0.21.0
2727
gopkg.in/yaml.v2 v2.4.0
2828
k8s.io/apimachinery v0.0.0-20240720202316-95b78024e3fe
29-
k8s.io/client-go v0.0.0-20240725170742-93c6a5bf507f
29+
k8s.io/client-go v0.0.0-20240725210749-4536e5a391f8
3030
k8s.io/klog/v2 v2.130.1
3131
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
3232
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd
@@ -76,7 +76,7 @@ require (
7676
google.golang.org/protobuf v1.34.2 // indirect
7777
gopkg.in/inf.v0 v0.9.1 // indirect
7878
gopkg.in/yaml.v3 v3.0.1 // indirect
79-
k8s.io/api v0.0.0-20240724031224-63e21d3bdab9 // indirect
79+
k8s.io/api v0.0.0-20240725200553-fb1fc3084c0e // indirect
8080
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
8181
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
8282
sigs.k8s.io/yaml v1.4.0 // indirect

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,12 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
204204
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
205205
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
206206
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
207-
k8s.io/api v0.0.0-20240724031224-63e21d3bdab9 h1:DsdxdppkdprdzZ/IwMZY+uNpvEcKtpJpKQRgll5PXto=
208-
k8s.io/api v0.0.0-20240724031224-63e21d3bdab9/go.mod h1:ytlEzqC2wOTwYET71W7+J+k7O2V7vrDuzmNLBSpgT+k=
207+
k8s.io/api v0.0.0-20240725200553-fb1fc3084c0e h1:zSGnlOF57ubuWLnmPjHd1c9XRaXJeXdcVsszq+wm17o=
208+
k8s.io/api v0.0.0-20240725200553-fb1fc3084c0e/go.mod h1:ytlEzqC2wOTwYET71W7+J+k7O2V7vrDuzmNLBSpgT+k=
209209
k8s.io/apimachinery v0.0.0-20240720202316-95b78024e3fe h1:V9MwpYUwbKlfLKVrhpVuKWiat/LBIhm1pGB9/xdHm5Q=
210210
k8s.io/apimachinery v0.0.0-20240720202316-95b78024e3fe/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
211-
k8s.io/client-go v0.0.0-20240725170742-93c6a5bf507f h1:PwgWcIHZw0QbiNWDz57rSH7GnSgq7d8lOo/kJoHd/DI=
212-
k8s.io/client-go v0.0.0-20240725170742-93c6a5bf507f/go.mod h1:duh6Hk8A52zAEoC179uJBw/MGC05zB74mzfF/nESIyU=
211+
k8s.io/client-go v0.0.0-20240725210749-4536e5a391f8 h1:ne00XpPG8VqvDVLT5nhjP/GpVQSQVthGm3ivE/YCawA=
212+
k8s.io/client-go v0.0.0-20240725210749-4536e5a391f8/go.mod h1:SORxrGJjz+pQkGtVEBP5ilXUslm+iXOJRgvngcKr6+Q=
213213
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
214214
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
215215
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=

0 commit comments

Comments
 (0)