From ce86fca8cd55eab2747ce32c432bcbdeafab099a Mon Sep 17 00:00:00 2001 From: Michael Aspinwall Date: Thu, 12 Jun 2025 22:35:45 +0000 Subject: [PATCH] Add warnings for use of Alpha features with Emulated Version Warn for both api and feature flag use of alpha features with emulated versions. This is an unsupported use case and users may run into issues. Signed-off-by: Michael Aspinwall --- .../pkg/server/options/api_enablement.go | 9 ++++ .../component-base/compatibility/registry.go | 19 ++++++++ .../compatibility/registry_test.go | 44 ++++++++++++++++++- 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/api_enablement.go b/staging/src/k8s.io/apiserver/pkg/server/options/api_enablement.go index d5b518b050e..33663353453 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/api_enablement.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/api_enablement.go @@ -26,6 +26,7 @@ import ( "k8s.io/apiserver/pkg/server/resourceconfig" serverstore "k8s.io/apiserver/pkg/server/storage" cliflag "k8s.io/component-base/cli/flag" + "k8s.io/klog/v2" ) // APIEnablementOptions contains the options for which resources to turn on and off. @@ -105,6 +106,14 @@ func (s *APIEnablementOptions) ApplyTo(c *server.Config, defaultResourceConfig * c.MergedResourceConfig = mergedResourceConfig + if c.EffectiveVersion.BinaryVersion() != c.EffectiveVersion.EmulationVersion() { + for _, version := range registry.PrioritizedVersionsAllGroups() { + if strings.Contains(version.Version, "alpha") { + klog.Warning("alpha api enabled with emulated groupVersion, this is unsupported, proceed at your own risk: api=", version.String()) + } + } + } + return err } diff --git a/staging/src/k8s.io/component-base/compatibility/registry.go b/staging/src/k8s.io/component-base/compatibility/registry.go index cdff77b07ec..cdcbbe23bb2 100644 --- a/staging/src/k8s.io/component-base/compatibility/registry.go +++ b/staging/src/k8s.io/component-base/compatibility/registry.go @@ -386,13 +386,32 @@ func (r *componentGlobalsRegistry) Validate() []error { defer r.mutex.Unlock() for _, globals := range r.componentGlobals { errs = append(errs, globals.effectiveVersion.Validate()...) + var features map[featuregate.Feature]featuregate.FeatureSpec if globals.featureGate != nil { errs = append(errs, globals.featureGate.Validate()...) + features = globals.featureGate.GetAll() + } + binaryVersion := globals.effectiveVersion.BinaryVersion() + emulatedVersion := globals.effectiveVersion.EmulationVersion() + if binaryVersion.GreaterThan(emulatedVersion) { + if enabled := enabledAlphaFeatures(features, globals); len(enabled) != 0 { + klog.Warningf("component has alpha features enabled in emulated version, this is unsupported: features=%v", enabled) + } } } return errs } +func enabledAlphaFeatures(features map[featuregate.Feature]featuregate.FeatureSpec, globals *ComponentGlobals) []string { + var enabled []string + for feat, featSpec := range features { + if featSpec.PreRelease == featuregate.Alpha && globals.featureGate.Enabled(feat) { + enabled = append(enabled, string(feat)) + } + } + return enabled +} + func (r *componentGlobalsRegistry) SetEmulationVersionMapping(fromComponent, toComponent string, f VersionMapping) error { if f == nil { return nil diff --git a/staging/src/k8s.io/component-base/compatibility/registry_test.go b/staging/src/k8s.io/component-base/compatibility/registry_test.go index 90c7bd8aaac..16228e37325 100644 --- a/staging/src/k8s.io/component-base/compatibility/registry_test.go +++ b/staging/src/k8s.io/component-base/compatibility/registry_test.go @@ -18,11 +18,11 @@ package compatibility import ( "fmt" + "reflect" "strings" "testing" "github.com/spf13/pflag" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/version" "k8s.io/component-base/featuregate" @@ -450,3 +450,45 @@ func assertVersionEqualTo(t *testing.T, ver *version.Version, expectedVer string } t.Errorf("expected: %s, got %s", expectedVer, ver.String()) } + +func Test_enabledAlphaFeatures(t *testing.T) { + features := map[featuregate.Feature]featuregate.FeatureSpec{ + "myFeat": { + PreRelease: featuregate.Alpha, + }, + "myOtherFeat": { + PreRelease: featuregate.Beta, + }, + "otherFeatDisabled": { + PreRelease: featuregate.Alpha, + }, + } + + alphaGate := featuregate.NewFeatureGate() + if err := alphaGate.Add(features); err != nil { + t.Fatalf("Unable to add features, %s", err) + } + + err := alphaGate.SetFromMap( + map[string]bool{ + "myFeat": true, + "myOtherFeat": true, + "otherFeatDisabled": false, + }, + ) + if err != nil { + t.Fatalf("Unable to set feature gate, %s", err) + } + + globals := &ComponentGlobals{ + featureGate: alphaGate, + } + + want := []string{ + "myFeat", + } + + if got := enabledAlphaFeatures(features, globals); !reflect.DeepEqual(got, want) { + t.Errorf("enabledAlphaFeatures() = %v, want %v", got, want) + } +}