Merge pull request #135343 from michaelasp/automated-cherry-pick-of-#135327-upstream-release-1.34

Automated cherry pick of #135327: Fix alpha API warnings for patch version differences
This commit is contained in:
Kubernetes Prow Robot
2025-12-04 03:56:57 -08:00
committed by GitHub
2 changed files with 311 additions and 2 deletions

View File

@@ -106,10 +106,22 @@ func (s *APIEnablementOptions) ApplyTo(c *server.Config, defaultResourceConfig *
c.MergedResourceConfig = mergedResourceConfig
if binVersion, emulatedVersion := c.EffectiveVersion.BinaryVersion(), c.EffectiveVersion.EmulationVersion(); !binVersion.EqualTo(emulatedVersion) {
binVersion, emulatedVersion := c.EffectiveVersion.BinaryVersion(), c.EffectiveVersion.EmulationVersion()
if binVersion != nil && emulatedVersion != nil && (binVersion.Major() != emulatedVersion.Major() || binVersion.Minor() != emulatedVersion.Minor()) {
for _, version := range registry.PrioritizedVersionsAllGroups() {
if strings.Contains(version.Version, "alpha") {
klog.Warningf("alpha api enabled with emulated version %s instead of the binary's version %s, this is unsupported, proceed at your own risk: api=%s", emulatedVersion, binVersion, version.String())
// Check if this alpha API is actually enabled before warning
entireVersionEnabled := c.MergedResourceConfig.ExplicitGroupVersionConfigs[version]
individualResourceEnabled := false
for resource, enabled := range c.MergedResourceConfig.ExplicitResourceConfigs {
if enabled && resource.Group == version.Group && resource.Version == version.Version {
individualResourceEnabled = true
break
}
}
if entireVersionEnabled || individualResourceEnabled {
klog.Warningf("alpha api enabled with emulated version %s instead of the binary's version %s, this is unsupported, proceed at your own risk: api=%s", emulatedVersion, binVersion, version.String())
}
}
}
}

View File

@@ -17,11 +17,19 @@ limitations under the License.
package options
import (
"bytes"
"strings"
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/version"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"k8s.io/apiserver/pkg/server"
serverstore "k8s.io/apiserver/pkg/server/storage"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/component-base/compatibility"
"k8s.io/klog/v2"
)
type fakeGroupRegistry struct{}
@@ -77,3 +85,292 @@ func TestAPIEnablementOptionsValidate(t *testing.T) {
})
}
}
type fakeGroupVersionRegistry struct {
versions []schema.GroupVersion
}
func (f fakeGroupVersionRegistry) PrioritizedVersionsAllGroups() []schema.GroupVersion {
return f.versions
}
func (f fakeGroupVersionRegistry) PrioritizedVersionsForGroup(group string) []schema.GroupVersion {
var result []schema.GroupVersion
for _, gv := range f.versions {
if gv.Group == group {
result = append(result, gv)
}
}
return result
}
func (f fakeGroupVersionRegistry) IsGroupRegistered(group string) bool {
for _, gv := range f.versions {
if gv.Group == group {
return true
}
}
return false
}
func (f fakeGroupVersionRegistry) IsVersionRegistered(gv schema.GroupVersion) bool {
for _, version := range f.versions {
if version == gv {
return true
}
}
return false
}
func (f fakeGroupVersionRegistry) GroupVersions() []schema.GroupVersion {
return f.versions
}
type fakeEffectiveVersion struct {
binaryVersion *version.Version
emulationVersion *version.Version
}
func (f fakeEffectiveVersion) BinaryVersion() *version.Version {
return f.binaryVersion
}
func (f fakeEffectiveVersion) EmulationVersion() *version.Version {
return f.emulationVersion
}
func (f fakeEffectiveVersion) MinCompatibilityVersion() *version.Version {
return nil
}
func (f fakeEffectiveVersion) EqualTo(other compatibility.EffectiveVersion) bool {
return f.binaryVersion.EqualTo(other.BinaryVersion()) && f.emulationVersion.EqualTo(other.EmulationVersion())
}
func (f fakeEffectiveVersion) String() string {
return "fake"
}
func (f fakeEffectiveVersion) Info() *apimachineryversion.Info {
return nil
}
func (f fakeEffectiveVersion) AllowedEmulationVersionRange() string {
return "fake range"
}
func (f fakeEffectiveVersion) AllowedMinCompatibilityVersionRange() string {
return "fake range"
}
func (f fakeEffectiveVersion) Validate() []error {
return nil
}
func TestAPIEnablementOptionsApplyToVersionComparison(t *testing.T) {
// Helper function to capture klog output
captureKlogOutput := func(fn func()) string {
var buf bytes.Buffer
klog.SetOutput(&buf)
klog.LogToStderr(false)
defer func() {
klog.SetOutput(nil)
klog.LogToStderr(true)
}()
fn()
klog.Flush()
return buf.String()
}
testCases := []struct {
name string
binaryVersion string
emulationVersion string
alphaAPIsPresent bool
versionEnabled bool
expectWarning bool
expectWarningContent string
}{
{
name: "same major.minor versions, different patch - no warning",
binaryVersion: "1.34.1",
emulationVersion: "1.34.0",
alphaAPIsPresent: true,
versionEnabled: true,
expectWarning: false,
},
{
name: "same major.minor versions, no patch in emulation - no warning",
binaryVersion: "1.34.1",
emulationVersion: "1.34",
alphaAPIsPresent: true,
versionEnabled: true,
expectWarning: false,
},
{
name: "identical versions - no warning",
binaryVersion: "1.34.1",
emulationVersion: "1.34.1",
alphaAPIsPresent: true,
versionEnabled: true,
expectWarning: false,
},
{
name: "different major versions but not enabled - should not warn",
binaryVersion: "1.34.1",
emulationVersion: "1.33.0",
alphaAPIsPresent: true,
expectWarning: false,
},
{
name: "different major versions - should warn",
binaryVersion: "1.34.1",
emulationVersion: "1.33.0",
alphaAPIsPresent: true,
expectWarning: true,
versionEnabled: true,
expectWarningContent: "alpha api enabled with emulated version",
},
{
name: "different minor versions - should warn",
binaryVersion: "1.34.1",
emulationVersion: "1.33.5",
alphaAPIsPresent: true,
expectWarning: true,
versionEnabled: true,
expectWarningContent: "alpha api enabled with emulated version",
},
{
name: "different major.minor but no alpha APIs - no warning",
binaryVersion: "1.34.1",
emulationVersion: "1.33.0",
alphaAPIsPresent: false,
expectWarning: false,
versionEnabled: true,
},
{
name: "same major.minor with alpha APIs - no warning",
binaryVersion: "1.34.5",
emulationVersion: "1.34.0",
alphaAPIsPresent: true,
expectWarning: false,
versionEnabled: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
binaryVer := version.MustParse(tc.binaryVersion)
emulationVer := version.MustParse(tc.emulationVersion)
effectiveVersion := fakeEffectiveVersion{
binaryVersion: binaryVer,
emulationVersion: emulationVer,
}
var versions []schema.GroupVersion
if tc.alphaAPIsPresent {
versions = []schema.GroupVersion{
{Group: "rbac.authorization.k8s.io", Version: "v1alpha1"},
{Group: "storage.k8s.io", Version: "v1alpha1"},
}
} else {
versions = []schema.GroupVersion{
{Group: "rbac.authorization.k8s.io", Version: "v1"},
{Group: "storage.k8s.io", Version: "v1beta1"},
}
}
registry := fakeGroupVersionRegistry{versions: versions}
config := &server.Config{EffectiveVersion: effectiveVersion}
options := &APIEnablementOptions{RuntimeConfig: make(cliflag.ConfigurationMap)}
// Enable the API
resourceConfig := serverstore.NewResourceConfig()
if tc.versionEnabled {
resourceConfig.ExplicitGroupVersionConfigs[schema.GroupVersion{Group: "rbac.authorization.k8s.io", Version: "v1alpha1"}] = true
}
// Capture log output during ApplyTo execution
logOutput := captureKlogOutput(func() {
err := options.ApplyTo(config, resourceConfig, registry)
if err != nil {
t.Errorf("ApplyTo failed: %v", err)
}
})
// Verify warning expectations
if tc.expectWarning {
if !strings.Contains(logOutput, tc.expectWarningContent) {
t.Errorf("Expected warning containing '%s', but got log output: %s", tc.expectWarningContent, logOutput)
}
if !strings.Contains(logOutput, "W") { // klog warning prefix
t.Errorf("Expected warning log level, but got log output: %s", logOutput)
}
} else if strings.Contains(logOutput, "alpha api enabled") {
t.Errorf("Expected no warning, but got log output: %s", logOutput)
}
})
}
}
func TestAPIEnablementOptionsApplyToErrorCases(t *testing.T) {
// Create a default effective version for test configs
defaultEffectiveVersion := fakeEffectiveVersion{
binaryVersion: version.MustParse("1.34.0"),
emulationVersion: version.MustParse("1.34.0"),
}
testCases := []struct {
name string
options *APIEnablementOptions
config *server.Config
expectError bool
errorContains string
}{
{
name: "nil options should not error",
options: nil,
config: &server.Config{
EffectiveVersion: defaultEffectiveVersion,
},
expectError: false,
},
{
name: "invalid runtime config value should error",
options: &APIEnablementOptions{
RuntimeConfig: cliflag.ConfigurationMap{
"api/all": "invalid-value", // Must be "true" or "false"
},
},
config: &server.Config{
EffectiveVersion: defaultEffectiveVersion,
},
expectError: true,
errorContains: "invalid value",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
registry := fakeGroupVersionRegistry{versions: []schema.GroupVersion{
{Group: "rbac.authorization.k8s.io", Version: "v1"},
}}
err := tc.options.ApplyTo(tc.config, serverstore.NewResourceConfig(), registry)
if tc.expectError {
if err == nil {
t.Errorf("Expected error but got none")
} else if tc.errorContains != "" && !strings.Contains(err.Error(), tc.errorContains) {
t.Errorf("Expected error containing '%s', but got: %v", tc.errorContains, err)
}
} else {
if err != nil {
t.Errorf("Expected no error but got: %v", err)
}
}
})
}
}