mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Refactor compatibility version code
Replace DefaultComponentGlobalsRegistry with new instance of componentGlobalsRegistry in test api server. Signed-off-by: Siyuan Zhang <sizhang@google.com> move kube effective version validation out of component base. Signed-off-by: Siyuan Zhang <sizhang@google.com> move DefaultComponentGlobalsRegistry out of component base. Signed-off-by: Siyuan Zhang <sizhang@google.com> move ComponentGlobalsRegistry out of featuregate pkg. Signed-off-by: Siyuan Zhang <sizhang@google.com> remove usage of DefaultComponentGlobalsRegistry in test files. Signed-off-by: Siyuan Zhang <sizhang@google.com> change non-test DefaultKubeEffectiveVersion to use DefaultBuildEffectiveVersion. Signed-off-by: Siyuan Zhang <sizhang@google.com> Restore useDefaultBuildBinaryVersion in effective version. Signed-off-by: Siyuan Zhang <sizhang@google.com> rename DefaultKubeEffectiveVersion to DefaultKubeEffectiveVersionForTest. Signed-off-by: Siyuan Zhang <sizhang@google.com> pass options.ComponentGlobalsRegistry into config for controller manager and scheduler. Signed-off-by: Siyuan Zhang <sizhang@google.com> Pass apiserver effective version to DefaultResourceEncodingConfig. Signed-off-by: Siyuan Zhang <sizhang@google.com> change statusz registry to take effective version from the components. Signed-off-by: Siyuan Zhang <sizhang@google.com> Address review comments Signed-off-by: Siyuan Zhang <sizhang@google.com> update vendor Signed-off-by: Siyuan Zhang <sizhang@google.com>
This commit is contained in:
		@@ -35,10 +35,10 @@ import (
 | 
				
			|||||||
	auditbuffered "k8s.io/apiserver/plugin/pkg/audit/buffered"
 | 
						auditbuffered "k8s.io/apiserver/plugin/pkg/audit/buffered"
 | 
				
			||||||
	audittruncate "k8s.io/apiserver/plugin/pkg/audit/truncate"
 | 
						audittruncate "k8s.io/apiserver/plugin/pkg/audit/truncate"
 | 
				
			||||||
	cliflag "k8s.io/component-base/cli/flag"
 | 
						cliflag "k8s.io/component-base/cli/flag"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	"k8s.io/component-base/logs"
 | 
						"k8s.io/component-base/logs"
 | 
				
			||||||
	"k8s.io/component-base/metrics"
 | 
						"k8s.io/component-base/metrics"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	kapi "k8s.io/kubernetes/pkg/apis/core"
 | 
						kapi "k8s.io/kubernetes/pkg/apis/core"
 | 
				
			||||||
	controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver/options"
 | 
						controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver/options"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/controlplane/reconcilers"
 | 
						"k8s.io/kubernetes/pkg/controlplane/reconcilers"
 | 
				
			||||||
@@ -49,14 +49,12 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAddFlags(t *testing.T) {
 | 
					func TestAddFlags(t *testing.T) {
 | 
				
			||||||
	componentGlobalsRegistry := featuregate.DefaultComponentGlobalsRegistry
 | 
						componentGlobalsRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
	t.Cleanup(func() {
 | 
					 | 
				
			||||||
		componentGlobalsRegistry.Reset()
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	fs := pflag.NewFlagSet("addflagstest", pflag.PanicOnError)
 | 
						fs := pflag.NewFlagSet("addflagstest", pflag.PanicOnError)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	utilruntime.Must(componentGlobalsRegistry.Register("test", utilversion.NewEffectiveVersion("1.32"), featuregate.NewFeatureGate()))
 | 
						utilruntime.Must(componentGlobalsRegistry.Register("test", basecompatibility.NewEffectiveVersionFromString("1.32", "1.31", "1.31"), featuregate.NewFeatureGate()))
 | 
				
			||||||
	s := NewServerRunOptions()
 | 
						s := NewServerRunOptions()
 | 
				
			||||||
 | 
						s.GenericServerRunOptions.ComponentGlobalsRegistry = componentGlobalsRegistry
 | 
				
			||||||
	for _, f := range s.Flags().FlagSets {
 | 
						for _, f := range s.Flags().FlagSets {
 | 
				
			||||||
		fs.AddFlagSet(f)
 | 
							fs.AddFlagSet(f)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -150,7 +148,7 @@ func TestAddFlags(t *testing.T) {
 | 
				
			|||||||
				JSONPatchMaxCopyBytes:        int64(3 * 1024 * 1024),
 | 
									JSONPatchMaxCopyBytes:        int64(3 * 1024 * 1024),
 | 
				
			||||||
				MaxRequestBodyBytes:          int64(3 * 1024 * 1024),
 | 
									MaxRequestBodyBytes:          int64(3 * 1024 * 1024),
 | 
				
			||||||
				ComponentGlobalsRegistry:     componentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:     componentGlobalsRegistry,
 | 
				
			||||||
				ComponentName:                featuregate.DefaultKubeComponent,
 | 
									ComponentName:                basecompatibility.DefaultKubeComponent,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Admission: &kubeoptions.AdmissionOptions{
 | 
								Admission: &kubeoptions.AdmissionOptions{
 | 
				
			||||||
				GenericAdmission: &apiserveroptions.AdmissionOptions{
 | 
									GenericAdmission: &apiserveroptions.AdmissionOptions{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	genericoptions "k8s.io/apiserver/pkg/server/options"
 | 
						genericoptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	netutils "k8s.io/utils/net"
 | 
						netutils "k8s.io/utils/net"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver/options"
 | 
						controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver/options"
 | 
				
			||||||
@@ -142,10 +141,5 @@ func (s CompletedOptions) Validate() []error {
 | 
				
			|||||||
		errs = append(errs, fmt.Errorf("--apiserver-count should be a positive number, but value '%d' provided", s.MasterCount))
 | 
							errs = append(errs, fmt.Errorf("--apiserver-count should be a positive number, but value '%d' provided", s.MasterCount))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	effectiveVersion := s.GenericServerRunOptions.ComponentGlobalsRegistry.EffectiveVersionFor(s.GenericServerRunOptions.ComponentName)
 | 
					 | 
				
			||||||
	if err := utilversion.ValidateKubeEffectiveVersion(effectiveVersion); err != nil {
 | 
					 | 
				
			||||||
		errs = append(errs, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return errs
 | 
						return errs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,6 +41,7 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/rest"
 | 
						"k8s.io/client-go/rest"
 | 
				
			||||||
	cliflag "k8s.io/component-base/cli/flag"
 | 
						cliflag "k8s.io/component-base/cli/flag"
 | 
				
			||||||
	"k8s.io/component-base/cli/globalflag"
 | 
						"k8s.io/component-base/cli/globalflag"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	"k8s.io/component-base/logs"
 | 
						"k8s.io/component-base/logs"
 | 
				
			||||||
	logsapi "k8s.io/component-base/logs/api/v1"
 | 
						logsapi "k8s.io/component-base/logs/api/v1"
 | 
				
			||||||
@@ -64,10 +65,9 @@ func init() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// NewAPIServerCommand creates a *cobra.Command object with default parameters
 | 
					// NewAPIServerCommand creates a *cobra.Command object with default parameters
 | 
				
			||||||
func NewAPIServerCommand() *cobra.Command {
 | 
					func NewAPIServerCommand() *cobra.Command {
 | 
				
			||||||
	_, featureGate := featuregate.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister(
 | 
					 | 
				
			||||||
		featuregate.DefaultKubeComponent, utilversion.DefaultBuildEffectiveVersion(), utilfeature.DefaultMutableFeatureGate)
 | 
					 | 
				
			||||||
	s := options.NewServerRunOptions()
 | 
						s := options.NewServerRunOptions()
 | 
				
			||||||
	ctx := genericapiserver.SetupSignalContext()
 | 
						ctx := genericapiserver.SetupSignalContext()
 | 
				
			||||||
 | 
						featureGate := s.GenericServerRunOptions.ComponentGlobalsRegistry.FeatureGateFor(basecompatibility.DefaultKubeComponent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd := &cobra.Command{
 | 
						cmd := &cobra.Command{
 | 
				
			||||||
		Use: "kube-apiserver",
 | 
							Use: "kube-apiserver",
 | 
				
			||||||
@@ -79,7 +79,7 @@ cluster's shared state through which all other components interact.`,
 | 
				
			|||||||
		// stop printing usage when the command errors
 | 
							// stop printing usage when the command errors
 | 
				
			||||||
		SilenceUsage: true,
 | 
							SilenceUsage: true,
 | 
				
			||||||
		PersistentPreRunE: func(*cobra.Command, []string) error {
 | 
							PersistentPreRunE: func(*cobra.Command, []string) error {
 | 
				
			||||||
			if err := featuregate.DefaultComponentGlobalsRegistry.Set(); err != nil {
 | 
								if err := s.GenericServerRunOptions.ComponentGlobalsRegistry.Set(); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// silence client-go warnings.
 | 
								// silence client-go warnings.
 | 
				
			||||||
@@ -108,7 +108,7 @@ cluster's shared state through which all other components interact.`,
 | 
				
			|||||||
				return utilerrors.NewAggregate(errs)
 | 
									return utilerrors.NewAggregate(errs)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// add feature enablement metrics
 | 
								// add feature enablement metrics
 | 
				
			||||||
			featureGate.AddMetrics()
 | 
								featureGate.(featuregate.MutableFeatureGate).AddMetrics()
 | 
				
			||||||
			return Run(ctx, completedOptions)
 | 
								return Run(ctx, completedOptions)
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Args: func(cmd *cobra.Command, args []string) error {
 | 
							Args: func(cmd *cobra.Command, args []string) error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,22 +43,20 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/api/errors"
 | 
						"k8s.io/apimachinery/pkg/api/errors"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
 | 
						utilerrors "k8s.io/apimachinery/pkg/util/errors"
 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	serveroptions "k8s.io/apiserver/pkg/server/options"
 | 
						serveroptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/storage/storagebackend"
 | 
						"k8s.io/apiserver/pkg/storage/storagebackend"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/storageversion"
 | 
						"k8s.io/apiserver/pkg/storageversion"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/client-go/kubernetes"
 | 
						"k8s.io/client-go/kubernetes"
 | 
				
			||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
	clientgotransport "k8s.io/client-go/transport"
 | 
						clientgotransport "k8s.io/client-go/transport"
 | 
				
			||||||
	"k8s.io/client-go/util/cert"
 | 
						"k8s.io/client-go/util/cert"
 | 
				
			||||||
	"k8s.io/client-go/util/keyutil"
 | 
						"k8s.io/client-go/util/keyutil"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
						featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
				
			||||||
	logsapi "k8s.io/component-base/logs/api/v1"
 | 
						logsapi "k8s.io/component-base/logs/api/v1"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
	"k8s.io/kube-aggregator/pkg/apiserver"
 | 
						"k8s.io/kube-aggregator/pkg/apiserver"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
						"k8s.io/kubernetes/pkg/features"
 | 
				
			||||||
@@ -104,11 +102,8 @@ type TestServerInstanceOptions struct {
 | 
				
			|||||||
	// an apiserver version skew scenario where all apiservers use the same proxyCA to verify client connections.
 | 
						// an apiserver version skew scenario where all apiservers use the same proxyCA to verify client connections.
 | 
				
			||||||
	ProxyCA *ProxyCA
 | 
						ProxyCA *ProxyCA
 | 
				
			||||||
	// Set the BinaryVersion of server effective version.
 | 
						// Set the BinaryVersion of server effective version.
 | 
				
			||||||
	// If empty, effective version will default to version.DefaultKubeBinaryVersion.
 | 
						// If empty, effective version will default to DefaultKubeEffectiveVersion.
 | 
				
			||||||
	BinaryVersion string
 | 
						BinaryVersion string
 | 
				
			||||||
	// Set the EmulationVersion of server effective version.
 | 
					 | 
				
			||||||
	// If empty, emulation version will default to the effective version.
 | 
					 | 
				
			||||||
	EmulationVersion string
 | 
					 | 
				
			||||||
	// Set non-default request timeout in the server.
 | 
						// Set non-default request timeout in the server.
 | 
				
			||||||
	RequestTimeout time.Duration
 | 
						RequestTimeout time.Duration
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -194,21 +189,20 @@ func StartTestServer(t ktesting.TB, instanceOptions *TestServerInstanceOptions,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	fs := pflag.NewFlagSet("test", pflag.PanicOnError)
 | 
						fs := pflag.NewFlagSet("test", pflag.PanicOnError)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	featureGate := utilfeature.DefaultMutableFeatureGate
 | 
						featureGate := utilfeature.DefaultMutableFeatureGate.DeepCopy()
 | 
				
			||||||
	featureGate.AddMetrics()
 | 
						effectiveVersion := compatibility.DefaultKubeEffectiveVersionForTest()
 | 
				
			||||||
	effectiveVersion := utilversion.DefaultKubeEffectiveVersion()
 | 
					 | 
				
			||||||
	if instanceOptions.BinaryVersion != "" {
 | 
						if instanceOptions.BinaryVersion != "" {
 | 
				
			||||||
		effectiveVersion = utilversion.NewEffectiveVersion(instanceOptions.BinaryVersion)
 | 
							effectiveVersion = basecompatibility.NewEffectiveVersionFromString(instanceOptions.BinaryVersion, "", "")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if instanceOptions.EmulationVersion != "" {
 | 
						effectiveVersion.SetEmulationVersion(featureGate.EmulationVersion())
 | 
				
			||||||
		effectiveVersion.SetEmulationVersion(version.MustParse(instanceOptions.EmulationVersion))
 | 
						componentGlobalsRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
 | 
						if err := componentGlobalsRegistry.Register(basecompatibility.DefaultKubeComponent, effectiveVersion, featureGate); err != nil {
 | 
				
			||||||
 | 
							return result, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// need to call SetFeatureGateEmulationVersionDuringTest to reset the feature gate emulation version at the end of the test.
 | 
					 | 
				
			||||||
	featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, featureGate, effectiveVersion.EmulationVersion())
 | 
					 | 
				
			||||||
	featuregate.DefaultComponentGlobalsRegistry.Reset()
 | 
					 | 
				
			||||||
	utilruntime.Must(featuregate.DefaultComponentGlobalsRegistry.Register(featuregate.DefaultKubeComponent, effectiveVersion, featureGate))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s := options.NewServerRunOptions()
 | 
						s := options.NewServerRunOptions()
 | 
				
			||||||
 | 
						// set up new instance of ComponentGlobalsRegistry instead of using the DefaultComponentGlobalsRegistry to avoid contention in parallel tests.
 | 
				
			||||||
 | 
						s.Options.GenericServerRunOptions.ComponentGlobalsRegistry = componentGlobalsRegistry
 | 
				
			||||||
	if instanceOptions.RequestTimeout > 0 {
 | 
						if instanceOptions.RequestTimeout > 0 {
 | 
				
			||||||
		s.GenericServerRunOptions.RequestTimeout = instanceOptions.RequestTimeout
 | 
							s.GenericServerRunOptions.RequestTimeout = instanceOptions.RequestTimeout
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -330,15 +324,6 @@ func StartTestServer(t ktesting.TB, instanceOptions *TestServerInstanceOptions,
 | 
				
			|||||||
			return result, err
 | 
								return result, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		s.Authentication.ClientCert.ClientCA = clientCACertFile
 | 
							s.Authentication.ClientCert.ClientCA = clientCACertFile
 | 
				
			||||||
		if utilfeature.DefaultFeatureGate.Enabled(features.UnknownVersionInteroperabilityProxy) {
 | 
					 | 
				
			||||||
			// TODO: set up a general clean up for testserver
 | 
					 | 
				
			||||||
			if clientgotransport.DialerStopCh == wait.NeverStop {
 | 
					 | 
				
			||||||
				ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
 | 
					 | 
				
			||||||
				t.Cleanup(cancel)
 | 
					 | 
				
			||||||
				clientgotransport.DialerStopCh = ctx.Done()
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			s.PeerCAFile = filepath.Join(s.SecureServing.ServerCert.CertDirectory, s.SecureServing.ServerCert.PairName+".crt")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s.SecureServing.ExternalAddress = s.SecureServing.Listener.Addr().(*net.TCPAddr).IP // use listener addr although it is a loopback device
 | 
						s.SecureServing.ExternalAddress = s.SecureServing.Listener.Addr().(*net.TCPAddr).IP // use listener addr although it is a loopback device
 | 
				
			||||||
@@ -374,8 +359,32 @@ func StartTestServer(t ktesting.TB, instanceOptions *TestServerInstanceOptions,
 | 
				
			|||||||
		s.Authentication.RequestHeader.ExtraHeaderPrefixes = extraHeaders
 | 
							s.Authentication.RequestHeader.ExtraHeaderPrefixes = extraHeaders
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := featuregate.DefaultComponentGlobalsRegistry.Set(); err != nil {
 | 
						if err := componentGlobalsRegistry.Set(); err != nil {
 | 
				
			||||||
		return result, err
 | 
							return result, fmt.Errorf("%w\nIf you are using SetFeatureGate*DuringTest, try using --emulated-version and --feature-gates flags instead", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// If the local ComponentGlobalsRegistry is changed by the flags,
 | 
				
			||||||
 | 
						// we need to copy the new feature values back to the DefaultFeatureGate because most feature checks still use the DefaultFeatureGate.
 | 
				
			||||||
 | 
						// We cannot directly use DefaultFeatureGate in ComponentGlobalsRegistry because the changes done by ComponentGlobalsRegistry.Set() will not be undone at the end of the test.
 | 
				
			||||||
 | 
						if !featureGate.EmulationVersion().EqualTo(utilfeature.DefaultMutableFeatureGate.EmulationVersion()) {
 | 
				
			||||||
 | 
							featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultMutableFeatureGate, effectiveVersion.EmulationVersion())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for f := range utilfeature.DefaultMutableFeatureGate.GetAll() {
 | 
				
			||||||
 | 
							if featureGate.Enabled(f) != utilfeature.DefaultFeatureGate.Enabled(f) {
 | 
				
			||||||
 | 
								featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, f, featureGate.Enabled(f))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						utilfeature.DefaultMutableFeatureGate.AddMetrics()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if instanceOptions.EnableCertAuth {
 | 
				
			||||||
 | 
							if featureGate.Enabled(features.UnknownVersionInteroperabilityProxy) {
 | 
				
			||||||
 | 
								// TODO: set up a general clean up for testserver
 | 
				
			||||||
 | 
								if clientgotransport.DialerStopCh == wait.NeverStop {
 | 
				
			||||||
 | 
									ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
 | 
				
			||||||
 | 
									t.Cleanup(cancel)
 | 
				
			||||||
 | 
									clientgotransport.DialerStopCh = ctx.Done()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								s.PeerCAFile = filepath.Join(s.SecureServing.ServerCert.CertDirectory, s.SecureServing.ServerCert.PairName+".crt")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	saSigningKeyFile, err := os.CreateTemp("/tmp", "insecure_test_key")
 | 
						saSigningKeyFile, err := os.CreateTemp("/tmp", "insecure_test_key")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ import (
 | 
				
			|||||||
	clientset "k8s.io/client-go/kubernetes"
 | 
						clientset "k8s.io/client-go/kubernetes"
 | 
				
			||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
	"k8s.io/client-go/tools/record"
 | 
						"k8s.io/client-go/tools/record"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	kubectrlmgrconfig "k8s.io/kubernetes/pkg/controller/apis/config"
 | 
						kubectrlmgrconfig "k8s.io/kubernetes/pkg/controller/apis/config"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -43,6 +44,9 @@ type Config struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	EventBroadcaster record.EventBroadcaster
 | 
						EventBroadcaster record.EventBroadcaster
 | 
				
			||||||
	EventRecorder    record.EventRecorder
 | 
						EventRecorder    record.EventRecorder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ComponentGlobalsRegistry is the registry where the effective versions and feature gates for all components are stored.
 | 
				
			||||||
 | 
						ComponentGlobalsRegistry basecompatibility.ComponentGlobalsRegistry
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type completedConfig struct {
 | 
					type completedConfig struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,6 +54,7 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/util/keyutil"
 | 
						"k8s.io/client-go/util/keyutil"
 | 
				
			||||||
	cliflag "k8s.io/component-base/cli/flag"
 | 
						cliflag "k8s.io/component-base/cli/flag"
 | 
				
			||||||
	"k8s.io/component-base/cli/globalflag"
 | 
						"k8s.io/component-base/cli/globalflag"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/configz"
 | 
						"k8s.io/component-base/configz"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	"k8s.io/component-base/logs"
 | 
						"k8s.io/component-base/logs"
 | 
				
			||||||
@@ -99,9 +100,6 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// NewControllerManagerCommand creates a *cobra.Command object with default parameters
 | 
					// NewControllerManagerCommand creates a *cobra.Command object with default parameters
 | 
				
			||||||
func NewControllerManagerCommand() *cobra.Command {
 | 
					func NewControllerManagerCommand() *cobra.Command {
 | 
				
			||||||
	_, _ = featuregate.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister(
 | 
					 | 
				
			||||||
		featuregate.DefaultKubeComponent, utilversion.DefaultBuildEffectiveVersion(), utilfeature.DefaultMutableFeatureGate)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	s, err := options.NewKubeControllerManagerOptions()
 | 
						s, err := options.NewKubeControllerManagerOptions()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		klog.Background().Error(err, "Unable to initialize command options")
 | 
							klog.Background().Error(err, "Unable to initialize command options")
 | 
				
			||||||
@@ -142,7 +140,7 @@ controller, and serviceaccounts controller.`,
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// add feature enablement metrics
 | 
								// add feature enablement metrics
 | 
				
			||||||
			fg := s.ComponentGlobalsRegistry.FeatureGateFor(featuregate.DefaultKubeComponent)
 | 
								fg := s.ComponentGlobalsRegistry.FeatureGateFor(basecompatibility.DefaultKubeComponent)
 | 
				
			||||||
			fg.(featuregate.MutableFeatureGate).AddMetrics()
 | 
								fg.(featuregate.MutableFeatureGate).AddMetrics()
 | 
				
			||||||
			return Run(context.Background(), c.Complete())
 | 
								return Run(context.Background(), c.Complete())
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -218,7 +216,7 @@ func Run(ctx context.Context, c *config.CompletedConfig) error {
 | 
				
			|||||||
		slis.SLIMetricsWithReset{}.Install(unsecuredMux)
 | 
							slis.SLIMetricsWithReset{}.Install(unsecuredMux)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentStatusz) {
 | 
							if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentStatusz) {
 | 
				
			||||||
			statusz.Install(unsecuredMux, kubeControllerManager, statusz.NewRegistry())
 | 
								statusz.Install(unsecuredMux, kubeControllerManager, statusz.NewRegistry(c.ComponentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent)))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		handler := genericcontrollermanager.BuildHandlerChain(unsecuredMux, &c.Authorization, &c.Authentication)
 | 
							handler := genericcontrollermanager.BuildHandlerChain(unsecuredMux, &c.Authorization, &c.Authentication)
 | 
				
			||||||
@@ -289,11 +287,11 @@ func Run(ctx context.Context, c *config.CompletedConfig) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.CoordinatedLeaderElection) {
 | 
						if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.CoordinatedLeaderElection) {
 | 
				
			||||||
		binaryVersion, err := semver.ParseTolerant(featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent).BinaryVersion().String())
 | 
							binaryVersion, err := semver.ParseTolerant(c.ComponentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent).BinaryVersion().String())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		emulationVersion, err := semver.ParseTolerant(featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent).EmulationVersion().String())
 | 
							emulationVersion, err := semver.ParseTolerant(c.ComponentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent).EmulationVersion().String())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@ import (
 | 
				
			|||||||
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
 | 
						utilerrors "k8s.io/apimachinery/pkg/util/errors"
 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	apiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
						apiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	clientgofeaturegate "k8s.io/client-go/features"
 | 
						clientgofeaturegate "k8s.io/client-go/features"
 | 
				
			||||||
	clientset "k8s.io/client-go/kubernetes"
 | 
						clientset "k8s.io/client-go/kubernetes"
 | 
				
			||||||
@@ -36,11 +37,11 @@ import (
 | 
				
			|||||||
	cpnames "k8s.io/cloud-provider/names"
 | 
						cpnames "k8s.io/cloud-provider/names"
 | 
				
			||||||
	cpoptions "k8s.io/cloud-provider/options"
 | 
						cpoptions "k8s.io/cloud-provider/options"
 | 
				
			||||||
	cliflag "k8s.io/component-base/cli/flag"
 | 
						cliflag "k8s.io/component-base/cli/flag"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	"k8s.io/component-base/logs"
 | 
						"k8s.io/component-base/logs"
 | 
				
			||||||
	logsapi "k8s.io/component-base/logs/api/v1"
 | 
						logsapi "k8s.io/component-base/logs/api/v1"
 | 
				
			||||||
	"k8s.io/component-base/metrics"
 | 
						"k8s.io/component-base/metrics"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	cmoptions "k8s.io/controller-manager/options"
 | 
						cmoptions "k8s.io/controller-manager/options"
 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
	kubectrlmgrconfigv1alpha1 "k8s.io/kube-controller-manager/config/v1alpha1"
 | 
						kubectrlmgrconfigv1alpha1 "k8s.io/kube-controller-manager/config/v1alpha1"
 | 
				
			||||||
@@ -106,7 +107,7 @@ type KubeControllerManagerOptions struct {
 | 
				
			|||||||
	ShowHiddenMetricsForVersion string
 | 
						ShowHiddenMetricsForVersion string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ComponentGlobalsRegistry is the registry where the effective versions and feature gates for all components are stored.
 | 
						// ComponentGlobalsRegistry is the registry where the effective versions and feature gates for all components are stored.
 | 
				
			||||||
	ComponentGlobalsRegistry featuregate.ComponentGlobalsRegistry
 | 
						ComponentGlobalsRegistry basecompatibility.ComponentGlobalsRegistry
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewKubeControllerManagerOptions creates a new KubeControllerManagerOptions with a default config.
 | 
					// NewKubeControllerManagerOptions creates a new KubeControllerManagerOptions with a default config.
 | 
				
			||||||
@@ -116,10 +117,12 @@ func NewKubeControllerManagerOptions() (*KubeControllerManagerOptions, error) {
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent) == nil {
 | 
						componentGlobalsRegistry := compatibility.DefaultComponentGlobalsRegistry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if componentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent) == nil {
 | 
				
			||||||
		featureGate := utilfeature.DefaultMutableFeatureGate
 | 
							featureGate := utilfeature.DefaultMutableFeatureGate
 | 
				
			||||||
		effectiveVersion := utilversion.DefaultKubeEffectiveVersion()
 | 
							effectiveVersion := compatibility.DefaultBuildEffectiveVersion()
 | 
				
			||||||
		utilruntime.Must(featuregate.DefaultComponentGlobalsRegistry.Register(featuregate.DefaultKubeComponent, effectiveVersion, featureGate))
 | 
							utilruntime.Must(componentGlobalsRegistry.Register(basecompatibility.DefaultKubeComponent, effectiveVersion, featureGate))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s := KubeControllerManagerOptions{
 | 
						s := KubeControllerManagerOptions{
 | 
				
			||||||
@@ -211,7 +214,7 @@ func NewKubeControllerManagerOptions() (*KubeControllerManagerOptions, error) {
 | 
				
			|||||||
		Authorization:            apiserveroptions.NewDelegatingAuthorizationOptions(),
 | 
							Authorization:            apiserveroptions.NewDelegatingAuthorizationOptions(),
 | 
				
			||||||
		Metrics:                  metrics.NewOptions(),
 | 
							Metrics:                  metrics.NewOptions(),
 | 
				
			||||||
		Logs:                     logs.NewOptions(),
 | 
							Logs:                     logs.NewOptions(),
 | 
				
			||||||
		ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
							ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s.Authentication.RemoteKubeConfigFileOptional = true
 | 
						s.Authentication.RemoteKubeConfigFileOptional = true
 | 
				
			||||||
@@ -230,7 +233,6 @@ func NewKubeControllerManagerOptions() (*KubeControllerManagerOptions, error) {
 | 
				
			|||||||
	s.GarbageCollectorController.GCIgnoredResources = gcIgnoredResources
 | 
						s.GarbageCollectorController.GCIgnoredResources = gcIgnoredResources
 | 
				
			||||||
	s.Generic.LeaderElection.ResourceName = "kube-controller-manager"
 | 
						s.Generic.LeaderElection.ResourceName = "kube-controller-manager"
 | 
				
			||||||
	s.Generic.LeaderElection.ResourceNamespace = "kube-system"
 | 
						s.Generic.LeaderElection.ResourceNamespace = "kube-system"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return &s, nil
 | 
						return &s, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -452,7 +454,6 @@ func (s *KubeControllerManagerOptions) Validate(allControllers []string, disable
 | 
				
			|||||||
	errs = append(errs, s.Authentication.Validate()...)
 | 
						errs = append(errs, s.Authentication.Validate()...)
 | 
				
			||||||
	errs = append(errs, s.Authorization.Validate()...)
 | 
						errs = append(errs, s.Authorization.Validate()...)
 | 
				
			||||||
	errs = append(errs, s.Metrics.Validate()...)
 | 
						errs = append(errs, s.Metrics.Validate()...)
 | 
				
			||||||
	errs = append(errs, utilversion.ValidateKubeEffectiveVersion(s.ComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent)))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// in-tree cloud providers are disabled since v1.31 (KEP-2395)
 | 
						// in-tree cloud providers are disabled since v1.31 (KEP-2395)
 | 
				
			||||||
	if len(s.KubeCloudShared.CloudProvider.Name) > 0 && !cloudprovider.IsExternal(s.KubeCloudShared.CloudProvider.Name) {
 | 
						if len(s.KubeCloudShared.CloudProvider.Name) > 0 && !cloudprovider.IsExternal(s.KubeCloudShared.CloudProvider.Name) {
 | 
				
			||||||
@@ -502,6 +503,7 @@ func (s KubeControllerManagerOptions) Config(allControllers []string, disabledBy
 | 
				
			|||||||
		Kubeconfig:               kubeconfig,
 | 
							Kubeconfig:               kubeconfig,
 | 
				
			||||||
		EventBroadcaster:         eventBroadcaster,
 | 
							EventBroadcaster:         eventBroadcaster,
 | 
				
			||||||
		EventRecorder:            eventRecorder,
 | 
							EventRecorder:            eventRecorder,
 | 
				
			||||||
 | 
							ComponentGlobalsRegistry: s.ComponentGlobalsRegistry,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := s.ApplyTo(c, allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
 | 
						if err := s.ApplyTo(c, allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apiserver/pkg/apis/apiserver"
 | 
						"k8s.io/apiserver/pkg/apis/apiserver"
 | 
				
			||||||
	apiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
						apiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	componentbaseconfig "k8s.io/component-base/config"
 | 
						componentbaseconfig "k8s.io/component-base/config"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
@@ -450,7 +450,8 @@ func TestAddFlags(t *testing.T) {
 | 
				
			|||||||
		Master:  "192.168.4.20",
 | 
							Master:  "192.168.4.20",
 | 
				
			||||||
		Metrics: &metrics.Options{},
 | 
							Metrics: &metrics.Options{},
 | 
				
			||||||
		Logs:    logs.NewOptions(),
 | 
							Logs:    logs.NewOptions(),
 | 
				
			||||||
		ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
							// ignores comparing ComponentGlobalsRegistry in this test.
 | 
				
			||||||
 | 
							ComponentGlobalsRegistry: s.ComponentGlobalsRegistry,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Sort GCIgnoredResources because it's built from a map, which means the
 | 
						// Sort GCIgnoredResources because it's built from a map, which means the
 | 
				
			||||||
@@ -736,27 +737,6 @@ func TestApplyTo(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestEmulatedVersion(t *testing.T) {
 | 
					func TestEmulatedVersion(t *testing.T) {
 | 
				
			||||||
	var cleanupAndSetupFunc = func() featuregate.FeatureGate {
 | 
					 | 
				
			||||||
		componentGlobalsRegistry := featuregate.DefaultComponentGlobalsRegistry
 | 
					 | 
				
			||||||
		componentGlobalsRegistry.Reset() // make sure this test have a clean state
 | 
					 | 
				
			||||||
		t.Cleanup(func() {
 | 
					 | 
				
			||||||
			componentGlobalsRegistry.Reset() // make sure this test doesn't leak a dirty state
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		verKube := utilversion.NewEffectiveVersion("1.32")
 | 
					 | 
				
			||||||
		fg := featuregate.NewVersionedFeatureGate(version.MustParse("1.32"))
 | 
					 | 
				
			||||||
		utilruntime.Must(fg.AddVersioned(map[featuregate.Feature]featuregate.VersionedSpecs{
 | 
					 | 
				
			||||||
			"kubeA": {
 | 
					 | 
				
			||||||
				{Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Beta},
 | 
					 | 
				
			||||||
				{Version: version.MustParse("1.32"), Default: true, LockToDefault: true, PreRelease: featuregate.GA},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			"kubeB": {
 | 
					 | 
				
			||||||
				{Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Alpha},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		}))
 | 
					 | 
				
			||||||
		utilruntime.Must(componentGlobalsRegistry.Register(featuregate.DefaultKubeComponent, verKube, fg))
 | 
					 | 
				
			||||||
		return fg
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	testcases := []struct {
 | 
						testcases := []struct {
 | 
				
			||||||
		name              string
 | 
							name              string
 | 
				
			||||||
@@ -808,9 +788,8 @@ func TestEmulatedVersion(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, tc := range testcases {
 | 
						for _, tc := range testcases {
 | 
				
			||||||
		t.Run(tc.name, func(t *testing.T) {
 | 
							t.Run(tc.name, func(t *testing.T) {
 | 
				
			||||||
			fg := cleanupAndSetupFunc()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			fs, s := setupControllerManagerFlagSet(t)
 | 
								fs, s := setupControllerManagerFlagSet(t)
 | 
				
			||||||
 | 
								fg := s.ComponentGlobalsRegistry.FeatureGateFor(basecompatibility.DefaultKubeComponent)
 | 
				
			||||||
			err := fs.Parse(tc.flags)
 | 
								err := fs.Parse(tc.flags)
 | 
				
			||||||
			checkTestError(t, err, false, "")
 | 
								checkTestError(t, err, false, "")
 | 
				
			||||||
			err = s.Validate([]string{""}, []string{""}, nil)
 | 
								err = s.Validate([]string{""}, []string{""}, nil)
 | 
				
			||||||
@@ -1558,6 +1537,22 @@ func setupControllerManagerFlagSet(t *testing.T) (*pflag.FlagSet, *KubeControlle
 | 
				
			|||||||
		t.Fatal(fmt.Errorf("NewKubeControllerManagerOptions failed with %w", err))
 | 
							t.Fatal(fmt.Errorf("NewKubeControllerManagerOptions failed with %w", err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						componentGlobalsRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						verKube := basecompatibility.NewEffectiveVersionFromString("1.32", "1.31", "1.31")
 | 
				
			||||||
 | 
						fg := featuregate.NewVersionedFeatureGate(version.MustParse("1.32"))
 | 
				
			||||||
 | 
						utilruntime.Must(fg.AddVersioned(map[featuregate.Feature]featuregate.VersionedSpecs{
 | 
				
			||||||
 | 
							"kubeA": {
 | 
				
			||||||
 | 
								{Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Beta},
 | 
				
			||||||
 | 
								{Version: version.MustParse("1.32"), Default: true, LockToDefault: true, PreRelease: featuregate.GA},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"kubeB": {
 | 
				
			||||||
 | 
								{Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						utilruntime.Must(componentGlobalsRegistry.Register(basecompatibility.DefaultKubeComponent, verKube, fg))
 | 
				
			||||||
 | 
						s.ComponentGlobalsRegistry = componentGlobalsRegistry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, f := range s.Flags([]string{""}, []string{""}, nil).FlagSets {
 | 
						for _, f := range s.Flags([]string{""}, []string{""}, nil).FlagSets {
 | 
				
			||||||
		fs.AddFlagSet(f)
 | 
							fs.AddFlagSet(f)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ import (
 | 
				
			|||||||
	"k8s.io/apiserver/pkg/server/healthz"
 | 
						"k8s.io/apiserver/pkg/server/healthz"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/server/mux"
 | 
						"k8s.io/apiserver/pkg/server/mux"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/server/routes"
 | 
						"k8s.io/apiserver/pkg/server/routes"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/client-go/informers"
 | 
						"k8s.io/client-go/informers"
 | 
				
			||||||
	clientset "k8s.io/client-go/kubernetes"
 | 
						clientset "k8s.io/client-go/kubernetes"
 | 
				
			||||||
@@ -474,7 +475,7 @@ func serveMetrics(ctx context.Context, bindAddress string, proxyMode kubeproxyco
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentStatusz) {
 | 
						if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentStatusz) {
 | 
				
			||||||
		statusz.Install(proxyMux, kubeProxy, statusz.NewRegistry())
 | 
							statusz.Install(proxyMux, kubeProxy, statusz.NewRegistry(compatibility.DefaultBuildEffectiveVersion()))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn := func() {
 | 
						fn := func() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ import (
 | 
				
			|||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
	"k8s.io/client-go/tools/events"
 | 
						"k8s.io/client-go/tools/events"
 | 
				
			||||||
	"k8s.io/client-go/tools/leaderelection"
 | 
						"k8s.io/client-go/tools/leaderelection"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/zpages/flagz"
 | 
						"k8s.io/component-base/zpages/flagz"
 | 
				
			||||||
	kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
 | 
						kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -61,6 +62,9 @@ type Config struct {
 | 
				
			|||||||
	// value, the pod will be moved from unschedulablePods to backoffQ or activeQ.
 | 
						// value, the pod will be moved from unschedulablePods to backoffQ or activeQ.
 | 
				
			||||||
	// If this value is empty, the default value (5min) will be used.
 | 
						// If this value is empty, the default value (5min) will be used.
 | 
				
			||||||
	PodMaxInUnschedulablePodsDuration time.Duration
 | 
						PodMaxInUnschedulablePodsDuration time.Duration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ComponentGlobalsRegistry is the registry where the effective versions and feature gates for all components are stored.
 | 
				
			||||||
 | 
						ComponentGlobalsRegistry basecompatibility.ComponentGlobalsRegistry
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type completedConfig struct {
 | 
					type completedConfig struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,7 @@ import (
 | 
				
			|||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/uuid"
 | 
						"k8s.io/apimachinery/pkg/util/uuid"
 | 
				
			||||||
	apiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
						apiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/client-go/dynamic"
 | 
						"k8s.io/client-go/dynamic"
 | 
				
			||||||
	"k8s.io/client-go/dynamic/dynamicinformer"
 | 
						"k8s.io/client-go/dynamic/dynamicinformer"
 | 
				
			||||||
@@ -39,13 +40,12 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/tools/leaderelection/resourcelock"
 | 
						"k8s.io/client-go/tools/leaderelection/resourcelock"
 | 
				
			||||||
	"k8s.io/client-go/tools/record"
 | 
						"k8s.io/client-go/tools/record"
 | 
				
			||||||
	cliflag "k8s.io/component-base/cli/flag"
 | 
						cliflag "k8s.io/component-base/cli/flag"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	componentbaseconfig "k8s.io/component-base/config"
 | 
						componentbaseconfig "k8s.io/component-base/config"
 | 
				
			||||||
	"k8s.io/component-base/config/options"
 | 
						"k8s.io/component-base/config/options"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
					 | 
				
			||||||
	"k8s.io/component-base/logs"
 | 
						"k8s.io/component-base/logs"
 | 
				
			||||||
	logsapi "k8s.io/component-base/logs/api/v1"
 | 
						logsapi "k8s.io/component-base/logs/api/v1"
 | 
				
			||||||
	"k8s.io/component-base/metrics"
 | 
						"k8s.io/component-base/metrics"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	zpagesfeatures "k8s.io/component-base/zpages/features"
 | 
						zpagesfeatures "k8s.io/component-base/zpages/features"
 | 
				
			||||||
	"k8s.io/component-base/zpages/flagz"
 | 
						"k8s.io/component-base/zpages/flagz"
 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
@@ -78,7 +78,7 @@ type Options struct {
 | 
				
			|||||||
	Master string
 | 
						Master string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ComponentGlobalsRegistry is the registry where the effective versions and feature gates for all components are stored.
 | 
						// ComponentGlobalsRegistry is the registry where the effective versions and feature gates for all components are stored.
 | 
				
			||||||
	ComponentGlobalsRegistry featuregate.ComponentGlobalsRegistry
 | 
						ComponentGlobalsRegistry basecompatibility.ComponentGlobalsRegistry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Flags hold the parsed CLI flags.
 | 
						// Flags hold the parsed CLI flags.
 | 
				
			||||||
	Flags *cliflag.NamedFlagSets
 | 
						Flags *cliflag.NamedFlagSets
 | 
				
			||||||
@@ -86,12 +86,17 @@ type Options struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// NewOptions returns default scheduler app options.
 | 
					// NewOptions returns default scheduler app options.
 | 
				
			||||||
func NewOptions() *Options {
 | 
					func NewOptions() *Options {
 | 
				
			||||||
 | 
						componentGlobalsRegistry := compatibility.DefaultComponentGlobalsRegistry
 | 
				
			||||||
	// make sure DefaultKubeComponent is registered in the DefaultComponentGlobalsRegistry.
 | 
						// make sure DefaultKubeComponent is registered in the DefaultComponentGlobalsRegistry.
 | 
				
			||||||
	if featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent) == nil {
 | 
						if componentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent) == nil {
 | 
				
			||||||
		featureGate := utilfeature.DefaultMutableFeatureGate
 | 
							featureGate := utilfeature.DefaultMutableFeatureGate
 | 
				
			||||||
		effectiveVersion := utilversion.DefaultKubeEffectiveVersion()
 | 
							effectiveVersion := compatibility.DefaultBuildEffectiveVersion()
 | 
				
			||||||
		utilruntime.Must(featuregate.DefaultComponentGlobalsRegistry.Register(featuregate.DefaultKubeComponent, effectiveVersion, featureGate))
 | 
							utilruntime.Must(componentGlobalsRegistry.Register(basecompatibility.DefaultKubeComponent, effectiveVersion, featureGate))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return NewOptionsWithComponentGlobalsRegistry(componentGlobalsRegistry)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewOptionsWithComponentGlobalsRegistry(componentGlobalsRegistry basecompatibility.ComponentGlobalsRegistry) *Options {
 | 
				
			||||||
	o := &Options{
 | 
						o := &Options{
 | 
				
			||||||
		SecureServing:  apiserveroptions.NewSecureServingOptions().WithLoopback(),
 | 
							SecureServing:  apiserveroptions.NewSecureServingOptions().WithLoopback(),
 | 
				
			||||||
		Authentication: apiserveroptions.NewDelegatingAuthenticationOptions(),
 | 
							Authentication: apiserveroptions.NewDelegatingAuthenticationOptions(),
 | 
				
			||||||
@@ -110,7 +115,7 @@ func NewOptions() *Options {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		Metrics:                  metrics.NewOptions(),
 | 
							Metrics:                  metrics.NewOptions(),
 | 
				
			||||||
		Logs:                     logs.NewOptions(),
 | 
							Logs:                     logs.NewOptions(),
 | 
				
			||||||
		ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
							ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o.Authentication.TolerateInClusterLookupFailure = true
 | 
						o.Authentication.TolerateInClusterLookupFailure = true
 | 
				
			||||||
@@ -287,11 +292,6 @@ func (o *Options) Validate() []error {
 | 
				
			|||||||
	errs = append(errs, o.Authorization.Validate()...)
 | 
						errs = append(errs, o.Authorization.Validate()...)
 | 
				
			||||||
	errs = append(errs, o.Metrics.Validate()...)
 | 
						errs = append(errs, o.Metrics.Validate()...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	effectiveVersion := o.ComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent)
 | 
					 | 
				
			||||||
	if err := utilversion.ValidateKubeEffectiveVersion(effectiveVersion); err != nil {
 | 
					 | 
				
			||||||
		errs = append(errs, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return errs
 | 
						return errs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -337,6 +337,7 @@ func (o *Options) Config(ctx context.Context) (*schedulerappconfig.Config, error
 | 
				
			|||||||
	dynClient := dynamic.NewForConfigOrDie(c.KubeConfig)
 | 
						dynClient := dynamic.NewForConfigOrDie(c.KubeConfig)
 | 
				
			||||||
	c.DynInformerFactory = dynamicinformer.NewFilteredDynamicSharedInformerFactory(dynClient, 0, corev1.NamespaceAll, nil)
 | 
						c.DynInformerFactory = dynamicinformer.NewFilteredDynamicSharedInformerFactory(dynClient, 0, corev1.NamespaceAll, nil)
 | 
				
			||||||
	c.LeaderElection = leaderElectionConfig
 | 
						c.LeaderElection = leaderElectionConfig
 | 
				
			||||||
 | 
						c.ComponentGlobalsRegistry = o.ComponentGlobalsRegistry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return c, nil
 | 
						return c, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,8 +32,8 @@ import (
 | 
				
			|||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	apiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
						apiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	componentbaseconfig "k8s.io/component-base/config"
 | 
						componentbaseconfig "k8s.io/component-base/config"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
					 | 
				
			||||||
	"k8s.io/component-base/logs"
 | 
						"k8s.io/component-base/logs"
 | 
				
			||||||
	"k8s.io/klog/v2/ktesting"
 | 
						"k8s.io/klog/v2/ktesting"
 | 
				
			||||||
	v1 "k8s.io/kube-scheduler/config/v1"
 | 
						v1 "k8s.io/kube-scheduler/config/v1"
 | 
				
			||||||
@@ -282,6 +282,8 @@ profiles:
 | 
				
			|||||||
	defaultPodMaxBackoffSeconds := int64(10)
 | 
						defaultPodMaxBackoffSeconds := int64(10)
 | 
				
			||||||
	defaultPercentageOfNodesToScore := ptr.To[int32](0)
 | 
						defaultPercentageOfNodesToScore := ptr.To[int32](0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						componentGlobalsRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	testcases := []struct {
 | 
						testcases := []struct {
 | 
				
			||||||
		name             string
 | 
							name             string
 | 
				
			||||||
		options          *Options
 | 
							options          *Options
 | 
				
			||||||
@@ -323,7 +325,7 @@ profiles:
 | 
				
			|||||||
					AlwaysAllowGroups:            []string{"system:masters"},
 | 
										AlwaysAllowGroups:            []string{"system:masters"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedUsername: "config",
 | 
								expectedUsername: "config",
 | 
				
			||||||
			expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
								expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
				
			||||||
@@ -375,7 +377,7 @@ profiles:
 | 
				
			|||||||
					return cfg
 | 
										return cfg
 | 
				
			||||||
				}(),
 | 
									}(),
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedError: "no kind \"KubeSchedulerConfiguration\" is registered for version \"componentconfig/v1alpha1\"",
 | 
								expectedError: "no kind \"KubeSchedulerConfiguration\" is registered for version \"componentconfig/v1alpha1\"",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -384,7 +386,7 @@ profiles:
 | 
				
			|||||||
			options: &Options{
 | 
								options: &Options{
 | 
				
			||||||
				ConfigFile:               unknownVersionConfig,
 | 
									ConfigFile:               unknownVersionConfig,
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedError: "no kind \"KubeSchedulerConfiguration\" is registered for version \"kubescheduler.config.k8s.io/unknown\"",
 | 
								expectedError: "no kind \"KubeSchedulerConfiguration\" is registered for version \"kubescheduler.config.k8s.io/unknown\"",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -393,7 +395,7 @@ profiles:
 | 
				
			|||||||
			options: &Options{
 | 
								options: &Options{
 | 
				
			||||||
				ConfigFile:               noVersionConfig,
 | 
									ConfigFile:               noVersionConfig,
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedError: "Object 'apiVersion' is missing",
 | 
								expectedError: "Object 'apiVersion' is missing",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -430,7 +432,7 @@ profiles:
 | 
				
			|||||||
					AlwaysAllowGroups:            []string{"system:masters"},
 | 
										AlwaysAllowGroups:            []string{"system:masters"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedUsername: "flag",
 | 
								expectedUsername: "flag",
 | 
				
			||||||
			expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
								expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
				
			||||||
@@ -503,7 +505,7 @@ profiles:
 | 
				
			|||||||
					AlwaysAllowGroups:            []string{"system:masters"},
 | 
										AlwaysAllowGroups:            []string{"system:masters"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
								expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
				
			||||||
				TypeMeta: metav1.TypeMeta{
 | 
									TypeMeta: metav1.TypeMeta{
 | 
				
			||||||
@@ -548,7 +550,7 @@ profiles:
 | 
				
			|||||||
			options: &Options{
 | 
								options: &Options{
 | 
				
			||||||
				ConfigFile:               pluginConfigFile,
 | 
									ConfigFile:               pluginConfigFile,
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedUsername: "config",
 | 
								expectedUsername: "config",
 | 
				
			||||||
			expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
								expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
				
			||||||
@@ -669,7 +671,7 @@ profiles:
 | 
				
			|||||||
			options: &Options{
 | 
								options: &Options{
 | 
				
			||||||
				ConfigFile:               multiProfilesConfig,
 | 
									ConfigFile:               multiProfilesConfig,
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedUsername: "config",
 | 
								expectedUsername: "config",
 | 
				
			||||||
			expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
								expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
				
			||||||
@@ -784,7 +786,7 @@ profiles:
 | 
				
			|||||||
			name: "no config",
 | 
								name: "no config",
 | 
				
			||||||
			options: &Options{
 | 
								options: &Options{
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedError: "no configuration has been provided",
 | 
								expectedError: "no configuration has been provided",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -793,7 +795,7 @@ profiles:
 | 
				
			|||||||
			options: &Options{
 | 
								options: &Options{
 | 
				
			||||||
				ConfigFile:               unknownFieldConfig,
 | 
									ConfigFile:               unknownFieldConfig,
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedError: `unknown field "foo"`,
 | 
								expectedError: `unknown field "foo"`,
 | 
				
			||||||
			checkErrFn:    runtime.IsStrictDecodingError,
 | 
								checkErrFn:    runtime.IsStrictDecodingError,
 | 
				
			||||||
@@ -803,7 +805,7 @@ profiles:
 | 
				
			|||||||
			options: &Options{
 | 
								options: &Options{
 | 
				
			||||||
				ConfigFile:               duplicateFieldConfig,
 | 
									ConfigFile:               duplicateFieldConfig,
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedError: `key "leaderElect" already set`,
 | 
								expectedError: `key "leaderElect" already set`,
 | 
				
			||||||
			checkErrFn:    runtime.IsStrictDecodingError,
 | 
								checkErrFn:    runtime.IsStrictDecodingError,
 | 
				
			||||||
@@ -813,7 +815,7 @@ profiles:
 | 
				
			|||||||
			options: &Options{
 | 
								options: &Options{
 | 
				
			||||||
				ConfigFile:               highThroughputProfileConfig,
 | 
									ConfigFile:               highThroughputProfileConfig,
 | 
				
			||||||
				Logs:                     logs.NewOptions(),
 | 
									Logs:                     logs.NewOptions(),
 | 
				
			||||||
				ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry: componentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectedUsername: "config",
 | 
								expectedUsername: "config",
 | 
				
			||||||
			expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
								expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,6 +46,7 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/tools/leaderelection"
 | 
						"k8s.io/client-go/tools/leaderelection"
 | 
				
			||||||
	cliflag "k8s.io/component-base/cli/flag"
 | 
						cliflag "k8s.io/component-base/cli/flag"
 | 
				
			||||||
	"k8s.io/component-base/cli/globalflag"
 | 
						"k8s.io/component-base/cli/globalflag"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/configz"
 | 
						"k8s.io/component-base/configz"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	"k8s.io/component-base/logs"
 | 
						"k8s.io/component-base/logs"
 | 
				
			||||||
@@ -84,10 +85,6 @@ type Option func(runtime.Registry) error
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// NewSchedulerCommand creates a *cobra.Command object with default parameters and registryOptions
 | 
					// NewSchedulerCommand creates a *cobra.Command object with default parameters and registryOptions
 | 
				
			||||||
func NewSchedulerCommand(registryOptions ...Option) *cobra.Command {
 | 
					func NewSchedulerCommand(registryOptions ...Option) *cobra.Command {
 | 
				
			||||||
	// explicitly register (if not already registered) the kube effective version and feature gate in DefaultComponentGlobalsRegistry,
 | 
					 | 
				
			||||||
	// which will be used in NewOptions.
 | 
					 | 
				
			||||||
	_, _ = featuregate.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister(
 | 
					 | 
				
			||||||
		featuregate.DefaultKubeComponent, utilversion.DefaultBuildEffectiveVersion(), utilfeature.DefaultMutableFeatureGate)
 | 
					 | 
				
			||||||
	opts := options.NewOptions()
 | 
						opts := options.NewOptions()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd := &cobra.Command{
 | 
						cmd := &cobra.Command{
 | 
				
			||||||
@@ -138,7 +135,7 @@ for more information about scheduling and the kube-scheduler component.`,
 | 
				
			|||||||
// runCommand runs the scheduler.
 | 
					// runCommand runs the scheduler.
 | 
				
			||||||
func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Option) error {
 | 
					func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Option) error {
 | 
				
			||||||
	verflag.PrintAndExitIfRequested()
 | 
						verflag.PrintAndExitIfRequested()
 | 
				
			||||||
	fg := opts.ComponentGlobalsRegistry.FeatureGateFor(featuregate.DefaultKubeComponent)
 | 
						fg := opts.ComponentGlobalsRegistry.FeatureGateFor(basecompatibility.DefaultKubeComponent)
 | 
				
			||||||
	// Activate logging as soon as possible, after that
 | 
						// Activate logging as soon as possible, after that
 | 
				
			||||||
	// show flags with the final logging configuration.
 | 
						// show flags with the final logging configuration.
 | 
				
			||||||
	if err := logsapi.ValidateAndApply(opts.Logs, fg); err != nil {
 | 
						if err := logsapi.ValidateAndApply(opts.Logs, fg); err != nil {
 | 
				
			||||||
@@ -216,11 +213,11 @@ func Run(ctx context.Context, cc *schedulerserverconfig.CompletedConfig, sched *
 | 
				
			|||||||
	readyzChecks = append(readyzChecks, handlerSyncCheck)
 | 
						readyzChecks = append(readyzChecks, handlerSyncCheck)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if cc.LeaderElection != nil && utilfeature.DefaultFeatureGate.Enabled(kubefeatures.CoordinatedLeaderElection) {
 | 
						if cc.LeaderElection != nil && utilfeature.DefaultFeatureGate.Enabled(kubefeatures.CoordinatedLeaderElection) {
 | 
				
			||||||
		binaryVersion, err := semver.ParseTolerant(featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent).BinaryVersion().String())
 | 
							binaryVersion, err := semver.ParseTolerant(cc.ComponentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent).BinaryVersion().String())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		emulationVersion, err := semver.ParseTolerant(featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent).EmulationVersion().String())
 | 
							emulationVersion, err := semver.ParseTolerant(cc.ComponentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent).EmulationVersion().String())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,10 +36,10 @@ import (
 | 
				
			|||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/util/feature"
 | 
						"k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	componentbaseconfig "k8s.io/component-base/config"
 | 
						componentbaseconfig "k8s.io/component-base/config"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
						featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	configv1 "k8s.io/kube-scheduler/config/v1"
 | 
						configv1 "k8s.io/kube-scheduler/config/v1"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kube-scheduler/app/options"
 | 
						"k8s.io/kubernetes/cmd/kube-scheduler/app/options"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
						"k8s.io/kubernetes/pkg/features"
 | 
				
			||||||
@@ -438,12 +438,8 @@ leaderElection:
 | 
				
			|||||||
			for k, v := range tc.restoreFeatures {
 | 
								for k, v := range tc.restoreFeatures {
 | 
				
			||||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, k, v)
 | 
									featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, k, v)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			componentGlobalsRegistry := featuregate.DefaultComponentGlobalsRegistry
 | 
								componentGlobalsRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
			t.Cleanup(func() {
 | 
								verKube := basecompatibility.NewEffectiveVersionFromString("1.32", "1.31", "1.31")
 | 
				
			||||||
				componentGlobalsRegistry.Reset()
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
			componentGlobalsRegistry.Reset()
 | 
					 | 
				
			||||||
			verKube := utilversion.NewEffectiveVersion("1.32")
 | 
					 | 
				
			||||||
			fg := feature.DefaultFeatureGate.DeepCopy()
 | 
								fg := feature.DefaultFeatureGate.DeepCopy()
 | 
				
			||||||
			utilruntime.Must(fg.AddVersioned(map[featuregate.Feature]featuregate.VersionedSpecs{
 | 
								utilruntime.Must(fg.AddVersioned(map[featuregate.Feature]featuregate.VersionedSpecs{
 | 
				
			||||||
				"kubeA": {
 | 
									"kubeA": {
 | 
				
			||||||
@@ -454,10 +450,10 @@ leaderElection:
 | 
				
			|||||||
					{Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Alpha},
 | 
										{Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			}))
 | 
								}))
 | 
				
			||||||
			utilruntime.Must(componentGlobalsRegistry.Register(featuregate.DefaultKubeComponent, verKube, fg))
 | 
								utilruntime.Must(componentGlobalsRegistry.Register(basecompatibility.DefaultKubeComponent, verKube, fg))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			fs := pflag.NewFlagSet("test", pflag.PanicOnError)
 | 
								fs := pflag.NewFlagSet("test", pflag.PanicOnError)
 | 
				
			||||||
			opts := options.NewOptions()
 | 
								opts := options.NewOptionsWithComponentGlobalsRegistry(componentGlobalsRegistry)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// use listeners instead of static ports so parallel test runs don't conflict
 | 
								// use listeners instead of static ports so parallel test runs don't conflict
 | 
				
			||||||
			opts.SecureServing.Listener = makeListener(t)
 | 
								opts.SecureServing.Listener = makeListener(t)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -189,8 +189,7 @@ func BuildGenericConfig(
 | 
				
			|||||||
		s.Etcd.StorageConfig.Transport.TracerProvider = noopoteltrace.NewTracerProvider()
 | 
							s.Etcd.StorageConfig.Transport.TracerProvider = noopoteltrace.NewTracerProvider()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	storageFactoryConfig := kubeapiserver.NewStorageFactoryConfig()
 | 
						storageFactoryConfig := kubeapiserver.NewStorageFactoryConfigEffectiveVersion(genericConfig.EffectiveVersion)
 | 
				
			||||||
	storageFactoryConfig.CurrentVersion = genericConfig.EffectiveVersion
 | 
					 | 
				
			||||||
	storageFactoryConfig.APIResourceConfig = genericConfig.MergedResourceConfig
 | 
						storageFactoryConfig.APIResourceConfig = genericConfig.MergedResourceConfig
 | 
				
			||||||
	storageFactoryConfig.DefaultResourceEncoding.SetEffectiveVersion(genericConfig.EffectiveVersion)
 | 
						storageFactoryConfig.DefaultResourceEncoding.SetEffectiveVersion(genericConfig.EffectiveVersion)
 | 
				
			||||||
	storageFactory, lastErr = storageFactoryConfig.Complete(s.Etcd).New()
 | 
						storageFactory, lastErr = storageFactoryConfig.Complete(s.Etcd).New()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,10 +40,10 @@ import (
 | 
				
			|||||||
	auditbuffered "k8s.io/apiserver/plugin/pkg/audit/buffered"
 | 
						auditbuffered "k8s.io/apiserver/plugin/pkg/audit/buffered"
 | 
				
			||||||
	audittruncate "k8s.io/apiserver/plugin/pkg/audit/truncate"
 | 
						audittruncate "k8s.io/apiserver/plugin/pkg/audit/truncate"
 | 
				
			||||||
	cliflag "k8s.io/component-base/cli/flag"
 | 
						cliflag "k8s.io/component-base/cli/flag"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	"k8s.io/component-base/logs"
 | 
						"k8s.io/component-base/logs"
 | 
				
			||||||
	"k8s.io/component-base/metrics"
 | 
						"k8s.io/component-base/metrics"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
 | 
						kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/serviceaccount"
 | 
						"k8s.io/kubernetes/pkg/serviceaccount"
 | 
				
			||||||
	v1alpha1testing "k8s.io/kubernetes/pkg/serviceaccount/externaljwt/plugin/testing/v1alpha1"
 | 
						v1alpha1testing "k8s.io/kubernetes/pkg/serviceaccount/externaljwt/plugin/testing/v1alpha1"
 | 
				
			||||||
@@ -51,13 +51,11 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAddFlags(t *testing.T) {
 | 
					func TestAddFlags(t *testing.T) {
 | 
				
			||||||
	componentGlobalsRegistry := featuregate.DefaultComponentGlobalsRegistry
 | 
						componentGlobalsRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
	t.Cleanup(func() {
 | 
					 | 
				
			||||||
		componentGlobalsRegistry.Reset()
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	fs := pflag.NewFlagSet("addflagstest", pflag.PanicOnError)
 | 
						fs := pflag.NewFlagSet("addflagstest", pflag.PanicOnError)
 | 
				
			||||||
	utilruntime.Must(componentGlobalsRegistry.Register("test", utilversion.NewEffectiveVersion("1.32"), featuregate.NewFeatureGate()))
 | 
						utilruntime.Must(componentGlobalsRegistry.Register("test", basecompatibility.NewEffectiveVersionFromString("1.32", "1.31", "1.31"), featuregate.NewFeatureGate()))
 | 
				
			||||||
	s := NewOptions()
 | 
						s := NewOptions()
 | 
				
			||||||
 | 
						s.GenericServerRunOptions.ComponentGlobalsRegistry = componentGlobalsRegistry
 | 
				
			||||||
	var fss cliflag.NamedFlagSets
 | 
						var fss cliflag.NamedFlagSets
 | 
				
			||||||
	s.AddFlags(&fss)
 | 
						s.AddFlags(&fss)
 | 
				
			||||||
	for _, f := range fss.FlagSets {
 | 
						for _, f := range fss.FlagSets {
 | 
				
			||||||
@@ -141,7 +139,7 @@ func TestAddFlags(t *testing.T) {
 | 
				
			|||||||
			JSONPatchMaxCopyBytes:        int64(3 * 1024 * 1024),
 | 
								JSONPatchMaxCopyBytes:        int64(3 * 1024 * 1024),
 | 
				
			||||||
			MaxRequestBodyBytes:          int64(3 * 1024 * 1024),
 | 
								MaxRequestBodyBytes:          int64(3 * 1024 * 1024),
 | 
				
			||||||
			ComponentGlobalsRegistry:     componentGlobalsRegistry,
 | 
								ComponentGlobalsRegistry:     componentGlobalsRegistry,
 | 
				
			||||||
			ComponentName:                featuregate.DefaultKubeComponent,
 | 
								ComponentName:                basecompatibility.DefaultKubeComponent,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Admission: &kubeoptions.AdmissionOptions{
 | 
							Admission: &kubeoptions.AdmissionOptions{
 | 
				
			||||||
			GenericAdmission: &apiserveroptions.AdmissionOptions{
 | 
								GenericAdmission: &apiserveroptions.AdmissionOptions{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@ import (
 | 
				
			|||||||
	kubeapiserveradmission "k8s.io/apiserver/pkg/admission"
 | 
						kubeapiserveradmission "k8s.io/apiserver/pkg/admission"
 | 
				
			||||||
	genericoptions "k8s.io/apiserver/pkg/server/options"
 | 
						genericoptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	basemetrics "k8s.io/component-base/metrics"
 | 
						basemetrics "k8s.io/component-base/metrics"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
						"k8s.io/kubernetes/pkg/features"
 | 
				
			||||||
@@ -202,7 +203,7 @@ func TestValidateOptions(t *testing.T) {
 | 
				
			|||||||
			name:         "validate master count equal 0",
 | 
								name:         "validate master count equal 0",
 | 
				
			||||||
			expectErrors: true,
 | 
								expectErrors: true,
 | 
				
			||||||
			options: &Options{
 | 
								options: &Options{
 | 
				
			||||||
				GenericServerRunOptions: &genericoptions.ServerRunOptions{ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry},
 | 
									GenericServerRunOptions: &genericoptions.ServerRunOptions{ComponentGlobalsRegistry: basecompatibility.NewComponentGlobalsRegistry()},
 | 
				
			||||||
				Etcd:                    &genericoptions.EtcdOptions{},
 | 
									Etcd:                    &genericoptions.EtcdOptions{},
 | 
				
			||||||
				SecureServing:           &genericoptions.SecureServingOptionsWithLoopback{},
 | 
									SecureServing:           &genericoptions.SecureServingOptionsWithLoopback{},
 | 
				
			||||||
				Audit:                   &genericoptions.AuditOptions{},
 | 
									Audit:                   &genericoptions.AuditOptions{},
 | 
				
			||||||
@@ -229,7 +230,7 @@ func TestValidateOptions(t *testing.T) {
 | 
				
			|||||||
			name:         "validate token request enable not attempted",
 | 
								name:         "validate token request enable not attempted",
 | 
				
			||||||
			expectErrors: true,
 | 
								expectErrors: true,
 | 
				
			||||||
			options: &Options{
 | 
								options: &Options{
 | 
				
			||||||
				GenericServerRunOptions: &genericoptions.ServerRunOptions{ComponentGlobalsRegistry: featuregate.DefaultComponentGlobalsRegistry},
 | 
									GenericServerRunOptions: &genericoptions.ServerRunOptions{ComponentGlobalsRegistry: basecompatibility.NewComponentGlobalsRegistry()},
 | 
				
			||||||
				Etcd:                    &genericoptions.EtcdOptions{},
 | 
									Etcd:                    &genericoptions.EtcdOptions{},
 | 
				
			||||||
				SecureServing:           &genericoptions.SecureServingOptionsWithLoopback{},
 | 
									SecureServing:           &genericoptions.SecureServingOptionsWithLoopback{},
 | 
				
			||||||
				Audit:                   &genericoptions.AuditOptions{},
 | 
									Audit:                   &genericoptions.AuditOptions{},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -161,7 +161,7 @@ func (c completedConfig) New(name string, delegationTarget genericapiserver.Dele
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentStatusz) {
 | 
						if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentStatusz) {
 | 
				
			||||||
		statusz.Install(s.GenericAPIServer.Handler.NonGoRestfulMux, name, statusz.NewRegistry())
 | 
							statusz.Install(s.GenericAPIServer.Handler.NonGoRestfulMux, name, statusz.NewRegistry(c.Generic.EffectiveVersion))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(apiserverfeatures.CoordinatedLeaderElection) {
 | 
						if utilfeature.DefaultFeatureGate.Enabled(apiserverfeatures.CoordinatedLeaderElection) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,6 +55,7 @@ import (
 | 
				
			|||||||
	"k8s.io/apiserver/pkg/server/resourceconfig"
 | 
						"k8s.io/apiserver/pkg/server/resourceconfig"
 | 
				
			||||||
	serverstorage "k8s.io/apiserver/pkg/server/storage"
 | 
						serverstorage "k8s.io/apiserver/pkg/server/storage"
 | 
				
			||||||
	etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing"
 | 
						etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/util/openapi"
 | 
						"k8s.io/apiserver/pkg/util/openapi"
 | 
				
			||||||
	"k8s.io/client-go/discovery"
 | 
						"k8s.io/client-go/discovery"
 | 
				
			||||||
	"k8s.io/client-go/informers"
 | 
						"k8s.io/client-go/informers"
 | 
				
			||||||
@@ -103,7 +104,7 @@ func setUp(t *testing.T) (*etcd3testing.EtcdTestServer, Config, *assert.Assertio
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config.ControlPlane.Generic.EffectiveVersion = utilversion.DefaultKubeEffectiveVersion()
 | 
						config.ControlPlane.Generic.EffectiveVersion = compatibility.DefaultKubeEffectiveVersionForTest()
 | 
				
			||||||
	storageFactoryConfig := kubeapiserver.NewStorageFactoryConfig()
 | 
						storageFactoryConfig := kubeapiserver.NewStorageFactoryConfig()
 | 
				
			||||||
	storageFactoryConfig.DefaultResourceEncoding.SetEffectiveVersion(config.ControlPlane.Generic.EffectiveVersion)
 | 
						storageFactoryConfig.DefaultResourceEncoding.SetEffectiveVersion(config.ControlPlane.Generic.EffectiveVersion)
 | 
				
			||||||
	storageConfig.StorageObjectCountTracker = config.ControlPlane.Generic.StorageObjectCountTracker
 | 
						storageConfig.StorageObjectCountTracker = config.ControlPlane.Generic.StorageObjectCountTracker
 | 
				
			||||||
@@ -241,7 +242,7 @@ func TestVersion(t *testing.T) {
 | 
				
			|||||||
		t.Errorf("unexpected error: %v", err)
 | 
							t.Errorf("unexpected error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	expectedInfo := utilversion.Get()
 | 
						expectedInfo := utilversion.Get()
 | 
				
			||||||
	kubeVersion := utilversion.DefaultKubeEffectiveVersion().BinaryVersion()
 | 
						kubeVersion := compatibility.DefaultKubeEffectiveVersionForTest().BinaryVersion()
 | 
				
			||||||
	expectedInfo.Major = fmt.Sprintf("%d", kubeVersion.Major())
 | 
						expectedInfo.Major = fmt.Sprintf("%d", kubeVersion.Major())
 | 
				
			||||||
	expectedInfo.Minor = fmt.Sprintf("%d", kubeVersion.Minor())
 | 
						expectedInfo.Minor = fmt.Sprintf("%d", kubeVersion.Minor())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,8 @@ import (
 | 
				
			|||||||
	"k8s.io/apiserver/pkg/server/resourceconfig"
 | 
						"k8s.io/apiserver/pkg/server/resourceconfig"
 | 
				
			||||||
	serverstorage "k8s.io/apiserver/pkg/server/storage"
 | 
						serverstorage "k8s.io/apiserver/pkg/server/storage"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/storage/storagebackend"
 | 
						"k8s.io/apiserver/pkg/storage/storagebackend"
 | 
				
			||||||
	version "k8s.io/component-base/version"
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/legacyscheme"
 | 
						"k8s.io/kubernetes/pkg/api/legacyscheme"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/apis/admissionregistration"
 | 
						"k8s.io/kubernetes/pkg/apis/admissionregistration"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/apis/apps"
 | 
						"k8s.io/kubernetes/pkg/apis/apps"
 | 
				
			||||||
@@ -61,6 +62,11 @@ func DefaultWatchCacheSizes() map[schema.GroupResource]int {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// NewStorageFactoryConfig returns a new StorageFactoryConfig set up with necessary resource overrides.
 | 
					// NewStorageFactoryConfig returns a new StorageFactoryConfig set up with necessary resource overrides.
 | 
				
			||||||
func NewStorageFactoryConfig() *StorageFactoryConfig {
 | 
					func NewStorageFactoryConfig() *StorageFactoryConfig {
 | 
				
			||||||
 | 
						return NewStorageFactoryConfigEffectiveVersion(compatibility.DefaultComponentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewStorageFactoryConfigEffectiveVersion returns a new StorageFactoryConfig set up with necessary resource overrides for a given EffectiveVersion.
 | 
				
			||||||
 | 
					func NewStorageFactoryConfigEffectiveVersion(effectiveVersion basecompatibility.EffectiveVersion) *StorageFactoryConfig {
 | 
				
			||||||
	resources := []schema.GroupVersionResource{
 | 
						resources := []schema.GroupVersionResource{
 | 
				
			||||||
		// If a resource has to be stored in a version that is not the
 | 
							// If a resource has to be stored in a version that is not the
 | 
				
			||||||
		// latest, then it can be listed here. Usually this is the case
 | 
							// latest, then it can be listed here. Usually this is the case
 | 
				
			||||||
@@ -87,7 +93,7 @@ func NewStorageFactoryConfig() *StorageFactoryConfig {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return &StorageFactoryConfig{
 | 
						return &StorageFactoryConfig{
 | 
				
			||||||
		Serializer:                legacyscheme.Codecs,
 | 
							Serializer:                legacyscheme.Codecs,
 | 
				
			||||||
		DefaultResourceEncoding:   serverstorage.NewDefaultResourceEncodingConfig(legacyscheme.Scheme),
 | 
							DefaultResourceEncoding:   serverstorage.NewDefaultResourceEncodingConfigForEffectiveVersion(legacyscheme.Scheme, effectiveVersion),
 | 
				
			||||||
		ResourceEncodingOverrides: resources,
 | 
							ResourceEncodingOverrides: resources,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -101,7 +107,6 @@ type StorageFactoryConfig struct {
 | 
				
			|||||||
	Serializer                runtime.StorageSerializer
 | 
						Serializer                runtime.StorageSerializer
 | 
				
			||||||
	ResourceEncodingOverrides []schema.GroupVersionResource
 | 
						ResourceEncodingOverrides []schema.GroupVersionResource
 | 
				
			||||||
	EtcdServersOverrides      []string
 | 
						EtcdServersOverrides      []string
 | 
				
			||||||
	CurrentVersion            version.EffectiveVersion
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Complete completes the StorageFactoryConfig with provided etcdOptions returning completedStorageFactoryConfig.
 | 
					// Complete completes the StorageFactoryConfig with provided etcdOptions returning completedStorageFactoryConfig.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,6 +59,7 @@ import (
 | 
				
			|||||||
	"k8s.io/apiserver/pkg/server/healthz"
 | 
						"k8s.io/apiserver/pkg/server/healthz"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/server/httplog"
 | 
						"k8s.io/apiserver/pkg/server/httplog"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/server/routes"
 | 
						"k8s.io/apiserver/pkg/server/routes"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/util/flushwriter"
 | 
						"k8s.io/apiserver/pkg/util/flushwriter"
 | 
				
			||||||
	"k8s.io/component-base/configz"
 | 
						"k8s.io/component-base/configz"
 | 
				
			||||||
@@ -565,7 +566,7 @@ func (s *Server) InstallDebuggingHandlers() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentStatusz) {
 | 
						if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentStatusz) {
 | 
				
			||||||
		s.addMetricsBucketMatcher("statusz")
 | 
							s.addMetricsBucketMatcher("statusz")
 | 
				
			||||||
		statusz.Install(s.restfulCont, ComponentKubelet, statusz.NewRegistry())
 | 
							statusz.Install(s.restfulCont, ComponentKubelet, statusz.NewRegistry(compatibility.DefaultBuildEffectiveVersion()))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// The /runningpods endpoint is used for testing only.
 | 
						// The /runningpods endpoint is used for testing only.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apiextensions-apiserver/pkg/cmd/server/options"
 | 
						"k8s.io/apiextensions-apiserver/pkg/cmd/server/options"
 | 
				
			||||||
	genericapiserver "k8s.io/apiserver/pkg/server"
 | 
						genericapiserver "k8s.io/apiserver/pkg/server"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewServerCommand(ctx context.Context, out, errOut io.Writer) *cobra.Command {
 | 
					func NewServerCommand(ctx context.Context, out, errOut io.Writer) *cobra.Command {
 | 
				
			||||||
@@ -34,7 +33,7 @@ func NewServerCommand(ctx context.Context, out, errOut io.Writer) *cobra.Command
 | 
				
			|||||||
		Short: "Launch an API extensions API server",
 | 
							Short: "Launch an API extensions API server",
 | 
				
			||||||
		Long:  "Launch an API extensions API server",
 | 
							Long:  "Launch an API extensions API server",
 | 
				
			||||||
		PersistentPreRunE: func(*cobra.Command, []string) error {
 | 
							PersistentPreRunE: func(*cobra.Command, []string) error {
 | 
				
			||||||
			return featuregate.DefaultComponentGlobalsRegistry.Set()
 | 
								return o.ServerRunOptions.ComponentGlobalsRegistry.Set()
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		RunE: func(c *cobra.Command, args []string) error {
 | 
							RunE: func(c *cobra.Command, args []string) error {
 | 
				
			||||||
			if err := o.Complete(); err != nil {
 | 
								if err := o.Complete(); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,18 +31,18 @@ import (
 | 
				
			|||||||
	extensionsapiserver "k8s.io/apiextensions-apiserver/pkg/apiserver"
 | 
						extensionsapiserver "k8s.io/apiextensions-apiserver/pkg/apiserver"
 | 
				
			||||||
	"k8s.io/apiextensions-apiserver/pkg/cmd/server/options"
 | 
						"k8s.io/apiextensions-apiserver/pkg/cmd/server/options"
 | 
				
			||||||
	generatedopenapi "k8s.io/apiextensions-apiserver/pkg/generated/openapi"
 | 
						generatedopenapi "k8s.io/apiextensions-apiserver/pkg/generated/openapi"
 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
 | 
						openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
 | 
				
			||||||
	genericapiserver "k8s.io/apiserver/pkg/server"
 | 
						genericapiserver "k8s.io/apiserver/pkg/server"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/storage/storagebackend"
 | 
						"k8s.io/apiserver/pkg/storage/storagebackend"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/util/openapi"
 | 
						"k8s.io/apiserver/pkg/util/openapi"
 | 
				
			||||||
	"k8s.io/client-go/kubernetes"
 | 
						"k8s.io/client-go/kubernetes"
 | 
				
			||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
 | 
						featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
				
			||||||
	logsapi "k8s.io/component-base/logs/api/v1"
 | 
						logsapi "k8s.io/component-base/logs/api/v1"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -124,15 +124,17 @@ func StartTestServer(t Logger, _ *TestServerInstanceOptions, customFlags []strin
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	fs := pflag.NewFlagSet("test", pflag.PanicOnError)
 | 
						fs := pflag.NewFlagSet("test", pflag.PanicOnError)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	featureGate := utilfeature.DefaultMutableFeatureGate
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Configure the effective version.
 | 
					 | 
				
			||||||
	effectiveVersion := utilversion.DefaultKubeEffectiveVersion()
 | 
					 | 
				
			||||||
	effectiveVersion.SetEmulationVersion(featureGate.EmulationVersion())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	featuregate.DefaultComponentGlobalsRegistry.Reset()
 | 
					 | 
				
			||||||
	utilruntime.Must(featuregate.DefaultComponentGlobalsRegistry.Register(featuregate.DefaultKubeComponent, effectiveVersion, featureGate))
 | 
					 | 
				
			||||||
	s := options.NewCustomResourceDefinitionsServerOptions(os.Stdout, os.Stderr)
 | 
						s := options.NewCustomResourceDefinitionsServerOptions(os.Stdout, os.Stderr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// set up new instance of ComponentGlobalsRegistry instead of using the DefaultComponentGlobalsRegistry to avoid contention in parallel tests.
 | 
				
			||||||
 | 
						featureGate := utilfeature.DefaultMutableFeatureGate.DeepCopy()
 | 
				
			||||||
 | 
						effectiveVersion := compatibility.DefaultKubeEffectiveVersionForTest()
 | 
				
			||||||
 | 
						effectiveVersion.SetEmulationVersion(featureGate.EmulationVersion())
 | 
				
			||||||
 | 
						componentGlobalsRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
 | 
						if err := componentGlobalsRegistry.Register(basecompatibility.DefaultKubeComponent, effectiveVersion, featureGate); err != nil {
 | 
				
			||||||
 | 
							return result, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						s.ServerRunOptions.ComponentGlobalsRegistry = componentGlobalsRegistry
 | 
				
			||||||
	s.AddFlags(fs)
 | 
						s.AddFlags(fs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s.RecommendedOptions.SecureServing.Listener, s.RecommendedOptions.SecureServing.BindPort, err = createLocalhostListenerOnFreePort()
 | 
						s.RecommendedOptions.SecureServing.Listener, s.RecommendedOptions.SecureServing.BindPort, err = createLocalhostListenerOnFreePort()
 | 
				
			||||||
@@ -155,8 +157,18 @@ func StartTestServer(t Logger, _ *TestServerInstanceOptions, customFlags []strin
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	fs.Parse(customFlags)
 | 
						fs.Parse(customFlags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := featuregate.DefaultComponentGlobalsRegistry.Set(); err != nil {
 | 
						if err := componentGlobalsRegistry.Set(); err != nil {
 | 
				
			||||||
		return result, err
 | 
							return result, fmt.Errorf("%w\nIf you are using SetFeatureGate*DuringTest, try using --emulated-version and --feature-gates flags instead", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// If the local ComponentGlobalsRegistry is changed by the flags,
 | 
				
			||||||
 | 
						// we need to copy the new feature values back to the DefaultFeatureGate because most feature checks still use the DefaultFeatureGate.
 | 
				
			||||||
 | 
						if !featureGate.EmulationVersion().EqualTo(utilfeature.DefaultMutableFeatureGate.EmulationVersion()) {
 | 
				
			||||||
 | 
							featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t.(featuregatetesting.TB), utilfeature.DefaultMutableFeatureGate, effectiveVersion.EmulationVersion())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for f := range utilfeature.DefaultMutableFeatureGate.GetAll() {
 | 
				
			||||||
 | 
							if featureGate.Enabled(f) != utilfeature.DefaultFeatureGate.Enabled(f) {
 | 
				
			||||||
 | 
								featuregatetesting.SetFeatureGateDuringTest(t.(featuregatetesting.TB), utilfeature.DefaultFeatureGate, f, featureGate.Enabled(f))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := s.Complete(); err != nil {
 | 
						if err := s.Complete(); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,6 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/watch"
 | 
						"k8s.io/apimachinery/pkg/watch"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
@@ -593,9 +592,7 @@ func TestFieldSelectorOpenAPI(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestFieldSelectorDropFields(t *testing.T) {
 | 
					func TestFieldSelectorDropFields(t *testing.T) {
 | 
				
			||||||
	_, ctx := ktesting.NewTestContext(t)
 | 
						_, ctx := ktesting.NewTestContext(t)
 | 
				
			||||||
	featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.31"))
 | 
						tearDown, apiExtensionClient, _, err := fixtures.StartDefaultServerWithClients(t, "--emulated-version=1.31", "--feature-gates=CustomResourceFieldSelectors=false")
 | 
				
			||||||
	featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, apiextensionsfeatures.CustomResourceFieldSelectors, false)
 | 
					 | 
				
			||||||
	tearDown, apiExtensionClient, _, err := fixtures.StartDefaultServerWithClients(t)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -675,9 +672,8 @@ func TestFieldSelectorDropFields(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestFieldSelectorDisablement(t *testing.T) {
 | 
					func TestFieldSelectorDisablement(t *testing.T) {
 | 
				
			||||||
	featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.31"))
 | 
					 | 
				
			||||||
	_, ctx := ktesting.NewTestContext(t)
 | 
						_, ctx := ktesting.NewTestContext(t)
 | 
				
			||||||
	tearDown, config, _, err := fixtures.StartDefaultServer(t)
 | 
						tearDown, config, _, err := fixtures.StartDefaultServer(t, "--emulated-version=1.31")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,6 @@ import (
 | 
				
			|||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	asn1util "k8s.io/apimachinery/pkg/apis/asn1"
 | 
						asn1util "k8s.io/apimachinery/pkg/apis/asn1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
					 | 
				
			||||||
	"k8s.io/apiserver/pkg/authentication/authenticator"
 | 
						"k8s.io/apiserver/pkg/authentication/authenticator"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/authentication/user"
 | 
						"k8s.io/apiserver/pkg/authentication/user"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/features"
 | 
						"k8s.io/apiserver/pkg/features"
 | 
				
			||||||
@@ -799,9 +798,6 @@ func TestX509(t *testing.T) {
 | 
				
			|||||||
			ExpectErr: false,
 | 
								ExpectErr: false,
 | 
				
			||||||
			setupFunc: func(t *testing.T) {
 | 
								setupFunc: func(t *testing.T) {
 | 
				
			||||||
				t.Helper()
 | 
									t.Helper()
 | 
				
			||||||
				// This statement can be removed once utilversion.DefaultKubeEffectiveVersion() is >= 1.33
 | 
					 | 
				
			||||||
				featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, feature.DefaultFeatureGate, version.MustParse("1.33"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"common name and empty UID with feature gate disabled": {
 | 
							"common name and empty UID with feature gate disabled": {
 | 
				
			||||||
@@ -822,8 +818,6 @@ func TestX509(t *testing.T) {
 | 
				
			|||||||
			ExpectErr: false,
 | 
								ExpectErr: false,
 | 
				
			||||||
			setupFunc: func(t *testing.T) {
 | 
								setupFunc: func(t *testing.T) {
 | 
				
			||||||
				t.Helper()
 | 
									t.Helper()
 | 
				
			||||||
				// This statement can be removed once utilversion.DefaultKubeEffectiveVersion() is >= 1.33
 | 
					 | 
				
			||||||
				featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, feature.DefaultFeatureGate, version.MustParse("1.33"))
 | 
					 | 
				
			||||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.AllowParsingUserUIDFromCertAuth, false)
 | 
									featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.AllowParsingUserUIDFromCertAuth, false)
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -836,9 +830,6 @@ func TestX509(t *testing.T) {
 | 
				
			|||||||
			ExpectErrMsg: regexp.MustCompile("UID cannot be an empty string"),
 | 
								ExpectErrMsg: regexp.MustCompile("UID cannot be an empty string"),
 | 
				
			||||||
			setupFunc: func(t *testing.T) {
 | 
								setupFunc: func(t *testing.T) {
 | 
				
			||||||
				t.Helper()
 | 
									t.Helper()
 | 
				
			||||||
				// This statement can be removed once utilversion.DefaultKubeEffectiveVersion() is >= 1.33
 | 
					 | 
				
			||||||
				featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, feature.DefaultFeatureGate, version.MustParse("1.33"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"ca with non-string UID": {
 | 
							"ca with non-string UID": {
 | 
				
			||||||
@@ -850,9 +841,6 @@ func TestX509(t *testing.T) {
 | 
				
			|||||||
			ExpectErrMsg: regexp.MustCompile("unable to parse UID into a string"),
 | 
								ExpectErrMsg: regexp.MustCompile("unable to parse UID into a string"),
 | 
				
			||||||
			setupFunc: func(t *testing.T) {
 | 
								setupFunc: func(t *testing.T) {
 | 
				
			||||||
				t.Helper()
 | 
									t.Helper()
 | 
				
			||||||
				// This statement can be removed once utilversion.DefaultKubeEffectiveVersion() is >= 1.33
 | 
					 | 
				
			||||||
				featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, feature.DefaultFeatureGate, version.MustParse("1.33"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"ca with multiple UIDs": {
 | 
							"ca with multiple UIDs": {
 | 
				
			||||||
@@ -866,9 +854,6 @@ func TestX509(t *testing.T) {
 | 
				
			|||||||
			ExpectErrMsg: regexp.MustCompile("expected 1 UID, but found multiple"),
 | 
								ExpectErrMsg: regexp.MustCompile("expected 1 UID, but found multiple"),
 | 
				
			||||||
			setupFunc: func(t *testing.T) {
 | 
								setupFunc: func(t *testing.T) {
 | 
				
			||||||
				t.Helper()
 | 
									t.Helper()
 | 
				
			||||||
				// This statement can be removed once utilversion.DefaultKubeEffectiveVersion() is >= 1.33
 | 
					 | 
				
			||||||
				featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, feature.DefaultFeatureGate, version.MustParse("1.33"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"ca with multiple organizations": {
 | 
							"ca with multiple organizations": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,9 +32,9 @@ import (
 | 
				
			|||||||
	celconfig "k8s.io/apiserver/pkg/apis/cel"
 | 
						celconfig "k8s.io/apiserver/pkg/apis/cel"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/cel/library"
 | 
						"k8s.io/apiserver/pkg/cel/library"
 | 
				
			||||||
	genericfeatures "k8s.io/apiserver/pkg/features"
 | 
						genericfeatures "k8s.io/apiserver/pkg/features"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DefaultCompatibilityVersion returns a default compatibility version for use with EnvSet
 | 
					// DefaultCompatibilityVersion returns a default compatibility version for use with EnvSet
 | 
				
			||||||
@@ -50,9 +50,9 @@ import (
 | 
				
			|||||||
// A default version number equal to the current Kubernetes major.minor version
 | 
					// A default version number equal to the current Kubernetes major.minor version
 | 
				
			||||||
// indicates fast forward CEL features that can be used when rollback is no longer needed.
 | 
					// indicates fast forward CEL features that can be used when rollback is no longer needed.
 | 
				
			||||||
func DefaultCompatibilityVersion() *version.Version {
 | 
					func DefaultCompatibilityVersion() *version.Version {
 | 
				
			||||||
	effectiveVer := featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent)
 | 
						effectiveVer := compatibility.DefaultComponentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent)
 | 
				
			||||||
	if effectiveVer == nil {
 | 
						if effectiveVer == nil {
 | 
				
			||||||
		effectiveVer = utilversion.DefaultKubeEffectiveVersion()
 | 
							effectiveVer = compatibility.DefaultBuildEffectiveVersion()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return effectiveVer.MinCompatibilityVersion()
 | 
						return effectiveVer.MinCompatibilityVersion()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,12 +73,12 @@ import (
 | 
				
			|||||||
	flowcontrolrequest "k8s.io/apiserver/pkg/util/flowcontrol/request"
 | 
						flowcontrolrequest "k8s.io/apiserver/pkg/util/flowcontrol/request"
 | 
				
			||||||
	"k8s.io/client-go/informers"
 | 
						"k8s.io/client-go/informers"
 | 
				
			||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	"k8s.io/component-base/logs"
 | 
						"k8s.io/component-base/logs"
 | 
				
			||||||
	"k8s.io/component-base/metrics/features"
 | 
						"k8s.io/component-base/metrics/features"
 | 
				
			||||||
	"k8s.io/component-base/metrics/prometheus/slis"
 | 
						"k8s.io/component-base/metrics/prometheus/slis"
 | 
				
			||||||
	"k8s.io/component-base/tracing"
 | 
						"k8s.io/component-base/tracing"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	"k8s.io/component-base/zpages/flagz"
 | 
						"k8s.io/component-base/zpages/flagz"
 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
	openapicommon "k8s.io/kube-openapi/pkg/common"
 | 
						openapicommon "k8s.io/kube-openapi/pkg/common"
 | 
				
			||||||
@@ -153,7 +153,7 @@ type Config struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// EffectiveVersion determines which apis and features are available
 | 
						// EffectiveVersion determines which apis and features are available
 | 
				
			||||||
	// based on when the api/feature lifecyle.
 | 
						// based on when the api/feature lifecyle.
 | 
				
			||||||
	EffectiveVersion utilversion.EffectiveVersion
 | 
						EffectiveVersion basecompatibility.EffectiveVersion
 | 
				
			||||||
	// FeatureGate is a way to plumb feature gate through if you have them.
 | 
						// FeatureGate is a way to plumb feature gate through if you have them.
 | 
				
			||||||
	FeatureGate featuregate.FeatureGate
 | 
						FeatureGate featuregate.FeatureGate
 | 
				
			||||||
	// AuditBackend is where audit events are sent to.
 | 
						// AuditBackend is where audit events are sent to.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,9 +47,9 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/informers"
 | 
						"k8s.io/client-go/informers"
 | 
				
			||||||
	"k8s.io/client-go/kubernetes/fake"
 | 
						"k8s.io/client-go/kubernetes/fake"
 | 
				
			||||||
	"k8s.io/client-go/rest"
 | 
						"k8s.io/client-go/rest"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
						featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
				
			||||||
	"k8s.io/component-base/tracing"
 | 
						"k8s.io/component-base/tracing"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	"k8s.io/klog/v2/ktesting"
 | 
						"k8s.io/klog/v2/ktesting"
 | 
				
			||||||
	netutils "k8s.io/utils/net"
 | 
						netutils "k8s.io/utils/net"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -124,7 +124,7 @@ func TestNewWithDelegate(t *testing.T) {
 | 
				
			|||||||
	delegateConfig.PublicAddress = netutils.ParseIPSloppy("192.168.10.4")
 | 
						delegateConfig.PublicAddress = netutils.ParseIPSloppy("192.168.10.4")
 | 
				
			||||||
	delegateConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
 | 
						delegateConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
 | 
				
			||||||
	delegateConfig.LoopbackClientConfig = &rest.Config{}
 | 
						delegateConfig.LoopbackClientConfig = &rest.Config{}
 | 
				
			||||||
	delegateConfig.EffectiveVersion = utilversion.NewEffectiveVersion("")
 | 
						delegateConfig.EffectiveVersion = basecompatibility.NewEffectiveVersionFromString("", "", "")
 | 
				
			||||||
	clientset := fake.NewSimpleClientset()
 | 
						clientset := fake.NewSimpleClientset()
 | 
				
			||||||
	if clientset == nil {
 | 
						if clientset == nil {
 | 
				
			||||||
		t.Fatal("unable to create fake client set")
 | 
							t.Fatal("unable to create fake client set")
 | 
				
			||||||
@@ -157,7 +157,7 @@ func TestNewWithDelegate(t *testing.T) {
 | 
				
			|||||||
	wrappingConfig.PublicAddress = netutils.ParseIPSloppy("192.168.10.4")
 | 
						wrappingConfig.PublicAddress = netutils.ParseIPSloppy("192.168.10.4")
 | 
				
			||||||
	wrappingConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
 | 
						wrappingConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
 | 
				
			||||||
	wrappingConfig.LoopbackClientConfig = &rest.Config{}
 | 
						wrappingConfig.LoopbackClientConfig = &rest.Config{}
 | 
				
			||||||
	wrappingConfig.EffectiveVersion = utilversion.NewEffectiveVersion("")
 | 
						wrappingConfig.EffectiveVersion = basecompatibility.NewEffectiveVersionFromString("", "", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wrappingConfig.HealthzChecks = append(wrappingConfig.HealthzChecks, healthz.NamedCheck("wrapping-health", func(r *http.Request) error {
 | 
						wrappingConfig.HealthzChecks = append(wrappingConfig.HealthzChecks, healthz.NamedCheck("wrapping-health", func(r *http.Request) error {
 | 
				
			||||||
		return fmt.Errorf("wrapping failed healthcheck")
 | 
							return fmt.Errorf("wrapping failed healthcheck")
 | 
				
			||||||
@@ -434,7 +434,7 @@ func TestNewFeatureGatedSerializer(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	})))
 | 
						})))
 | 
				
			||||||
	config.ExternalAddress = "192.168.10.4:443"
 | 
						config.ExternalAddress = "192.168.10.4:443"
 | 
				
			||||||
	config.EffectiveVersion = utilversion.NewEffectiveVersion("")
 | 
						config.EffectiveVersion = basecompatibility.NewEffectiveVersionFromString("", "", "")
 | 
				
			||||||
	config.LoopbackClientConfig = &rest.Config{}
 | 
						config.LoopbackClientConfig = &rest.Config{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err := config.Complete(nil).New("test", NewEmptyDelegate()); err != nil {
 | 
						if _, err := config.Complete(nil).New("test", NewEmptyDelegate()); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,8 +54,8 @@ import (
 | 
				
			|||||||
	"k8s.io/apiserver/pkg/storageversion"
 | 
						"k8s.io/apiserver/pkg/storageversion"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
	openapibuilder3 "k8s.io/kube-openapi/pkg/builder3"
 | 
						openapibuilder3 "k8s.io/kube-openapi/pkg/builder3"
 | 
				
			||||||
	openapicommon "k8s.io/kube-openapi/pkg/common"
 | 
						openapicommon "k8s.io/kube-openapi/pkg/common"
 | 
				
			||||||
@@ -244,7 +244,7 @@ type GenericAPIServer struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// EffectiveVersion determines which apis and features are available
 | 
						// EffectiveVersion determines which apis and features are available
 | 
				
			||||||
	// based on when the api/feature lifecyle.
 | 
						// based on when the api/feature lifecyle.
 | 
				
			||||||
	EffectiveVersion utilversion.EffectiveVersion
 | 
						EffectiveVersion basecompatibility.EffectiveVersion
 | 
				
			||||||
	// FeatureGate is a way to plumb feature gate through if you have them.
 | 
						// FeatureGate is a way to plumb feature gate through if you have them.
 | 
				
			||||||
	FeatureGate featuregate.FeatureGate
 | 
						FeatureGate featuregate.FeatureGate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,7 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/runtime/serializer"
 | 
						"k8s.io/apimachinery/pkg/runtime/serializer"
 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
 | 
						utilversion "k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/version"
 | 
						"k8s.io/apimachinery/pkg/version"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/apis/example"
 | 
						"k8s.io/apiserver/pkg/apis/example"
 | 
				
			||||||
@@ -52,7 +53,7 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/informers"
 | 
						"k8s.io/client-go/informers"
 | 
				
			||||||
	"k8s.io/client-go/kubernetes/fake"
 | 
						"k8s.io/client-go/kubernetes/fake"
 | 
				
			||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/klog/v2/ktesting"
 | 
						"k8s.io/klog/v2/ktesting"
 | 
				
			||||||
	kubeopenapi "k8s.io/kube-openapi/pkg/common"
 | 
						kubeopenapi "k8s.io/kube-openapi/pkg/common"
 | 
				
			||||||
	"k8s.io/kube-openapi/pkg/validation/spec"
 | 
						"k8s.io/kube-openapi/pkg/validation/spec"
 | 
				
			||||||
@@ -138,7 +139,7 @@ func setUp(t *testing.T) (Config, *assert.Assertions) {
 | 
				
			|||||||
	if clientset == nil {
 | 
						if clientset == nil {
 | 
				
			||||||
		t.Fatal("unable to create fake client set")
 | 
							t.Fatal("unable to create fake client set")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	config.EffectiveVersion = utilversion.NewEffectiveVersion("")
 | 
						config.EffectiveVersion = basecompatibility.NewEffectiveVersionFromString("", "", "")
 | 
				
			||||||
	config.OpenAPIConfig = DefaultOpenAPIConfig(testGetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(runtime.NewScheme()))
 | 
						config.OpenAPIConfig = DefaultOpenAPIConfig(testGetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(runtime.NewScheme()))
 | 
				
			||||||
	config.OpenAPIConfig.Info.Version = "unversioned"
 | 
						config.OpenAPIConfig.Info.Version = "unversioned"
 | 
				
			||||||
	config.OpenAPIV3Config = DefaultOpenAPIV3Config(testGetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(runtime.NewScheme()))
 | 
						config.OpenAPIV3Config = DefaultOpenAPIV3Config(testGetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(runtime.NewScheme()))
 | 
				
			||||||
@@ -460,8 +461,8 @@ func TestNotRestRoutesHaveAuth(t *testing.T) {
 | 
				
			|||||||
	config.EnableProfiling = true
 | 
						config.EnableProfiling = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kubeVersion := fakeVersion()
 | 
						kubeVersion := fakeVersion()
 | 
				
			||||||
	effectiveVersion := utilversion.NewEffectiveVersion(kubeVersion.String())
 | 
						binaryVersion := utilversion.MustParse(kubeVersion.String())
 | 
				
			||||||
	effectiveVersion.Set(effectiveVersion.BinaryVersion().WithInfo(kubeVersion), effectiveVersion.EmulationVersion(), effectiveVersion.MinCompatibilityVersion())
 | 
						effectiveVersion := basecompatibility.NewEffectiveVersion(binaryVersion, false, binaryVersion, binaryVersion.SubtractMinor(1))
 | 
				
			||||||
	config.EffectiveVersion = effectiveVersion
 | 
						config.EffectiveVersion = effectiveVersion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s, err := config.Complete(nil).New("test", NewEmptyDelegate())
 | 
						s, err := config.Complete(nil).New("test", NewEmptyDelegate())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,9 +27,9 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/util/errors"
 | 
						"k8s.io/apimachinery/pkg/util/errors"
 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/server"
 | 
						"k8s.io/apiserver/pkg/server"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/spf13/pflag"
 | 
						"github.com/spf13/pflag"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -95,22 +95,22 @@ type ServerRunOptions struct {
 | 
				
			|||||||
	ShutdownWatchTerminationGracePeriod time.Duration
 | 
						ShutdownWatchTerminationGracePeriod time.Duration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ComponentGlobalsRegistry is the registry where the effective versions and feature gates for all components are stored.
 | 
						// ComponentGlobalsRegistry is the registry where the effective versions and feature gates for all components are stored.
 | 
				
			||||||
	ComponentGlobalsRegistry featuregate.ComponentGlobalsRegistry
 | 
						ComponentGlobalsRegistry basecompatibility.ComponentGlobalsRegistry
 | 
				
			||||||
	// ComponentName is name under which the server's global variabled are registered in the ComponentGlobalsRegistry.
 | 
						// ComponentName is name under which the server's global variabled are registered in the ComponentGlobalsRegistry.
 | 
				
			||||||
	ComponentName string
 | 
						ComponentName string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewServerRunOptions() *ServerRunOptions {
 | 
					func NewServerRunOptions() *ServerRunOptions {
 | 
				
			||||||
	if featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent) == nil {
 | 
						if compatibility.DefaultComponentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent) == nil {
 | 
				
			||||||
		featureGate := utilfeature.DefaultMutableFeatureGate
 | 
							featureGate := utilfeature.DefaultMutableFeatureGate
 | 
				
			||||||
		effectiveVersion := utilversion.DefaultKubeEffectiveVersion()
 | 
							effectiveVersion := compatibility.DefaultBuildEffectiveVersion()
 | 
				
			||||||
		utilruntime.Must(featuregate.DefaultComponentGlobalsRegistry.Register(featuregate.DefaultKubeComponent, effectiveVersion, featureGate))
 | 
							utilruntime.Must(compatibility.DefaultComponentGlobalsRegistry.Register(basecompatibility.DefaultKubeComponent, effectiveVersion, featureGate))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NewServerRunOptionsForComponent(featuregate.DefaultKubeComponent, featuregate.DefaultComponentGlobalsRegistry)
 | 
						return NewServerRunOptionsForComponent(basecompatibility.DefaultKubeComponent, compatibility.DefaultComponentGlobalsRegistry)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewServerRunOptionsForComponent(componentName string, componentGlobalsRegistry featuregate.ComponentGlobalsRegistry) *ServerRunOptions {
 | 
					func NewServerRunOptionsForComponent(componentName string, componentGlobalsRegistry basecompatibility.ComponentGlobalsRegistry) *ServerRunOptions {
 | 
				
			||||||
	defaults := server.NewConfig(serializer.CodecFactory{})
 | 
						defaults := server.NewConfig(serializer.CodecFactory{})
 | 
				
			||||||
	return &ServerRunOptions{
 | 
						return &ServerRunOptions{
 | 
				
			||||||
		MaxRequestsInFlight:                 defaults.MaxRequestsInFlight,
 | 
							MaxRequestsInFlight:                 defaults.MaxRequestsInFlight,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,15 +26,15 @@ import (
 | 
				
			|||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	netutils "k8s.io/utils/net"
 | 
						netutils "k8s.io/utils/net"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestServerRunOptionsValidate(t *testing.T) {
 | 
					func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			||||||
	testRegistry := featuregate.NewComponentGlobalsRegistry()
 | 
						defaultComponentGlobalsRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
 | 
						testRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
	featureGate := utilfeature.DefaultFeatureGate.DeepCopy()
 | 
						featureGate := utilfeature.DefaultFeatureGate.DeepCopy()
 | 
				
			||||||
	effectiveVersion := utilversion.NewEffectiveVersion("1.35")
 | 
						effectiveVersion := basecompatibility.NewEffectiveVersionFromString("1.35", "1.32", "1.32")
 | 
				
			||||||
	effectiveVersion.SetEmulationVersion(version.MajorMinor(1, 31))
 | 
						effectiveVersion.SetEmulationVersion(version.MajorMinor(1, 31))
 | 
				
			||||||
	testComponent := "test"
 | 
						testComponent := "test"
 | 
				
			||||||
	utilruntime.Must(testRegistry.Register(testComponent, effectiveVersion, featureGate))
 | 
						utilruntime.Must(testRegistry.Register(testComponent, effectiveVersion, featureGate))
 | 
				
			||||||
@@ -55,7 +55,7 @@ func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			|||||||
				MinRequestTimeout:           1800,
 | 
									MinRequestTimeout:           1800,
 | 
				
			||||||
				JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
									JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
				
			||||||
				MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
									MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
				
			||||||
				ComponentGlobalsRegistry:    featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:    defaultComponentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectErr: "--max-requests-inflight can not be negative value",
 | 
								expectErr: "--max-requests-inflight can not be negative value",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -70,7 +70,7 @@ func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			|||||||
				MinRequestTimeout:           1800,
 | 
									MinRequestTimeout:           1800,
 | 
				
			||||||
				JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
									JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
				
			||||||
				MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
									MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
				
			||||||
				ComponentGlobalsRegistry:    featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:    defaultComponentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectErr: "--max-mutating-requests-inflight can not be negative value",
 | 
								expectErr: "--max-mutating-requests-inflight can not be negative value",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -85,7 +85,7 @@ func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			|||||||
				MinRequestTimeout:           1800,
 | 
									MinRequestTimeout:           1800,
 | 
				
			||||||
				JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
									JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
				
			||||||
				MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
									MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
				
			||||||
				ComponentGlobalsRegistry:    featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:    defaultComponentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectErr: "--request-timeout can not be negative value",
 | 
								expectErr: "--request-timeout can not be negative value",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -100,7 +100,7 @@ func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			|||||||
				MinRequestTimeout:           -1800,
 | 
									MinRequestTimeout:           -1800,
 | 
				
			||||||
				JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
									JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
				
			||||||
				MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
									MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
				
			||||||
				ComponentGlobalsRegistry:    featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:    defaultComponentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectErr: "--min-request-timeout can not be negative value",
 | 
								expectErr: "--min-request-timeout can not be negative value",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -115,7 +115,7 @@ func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			|||||||
				MinRequestTimeout:           1800,
 | 
									MinRequestTimeout:           1800,
 | 
				
			||||||
				JSONPatchMaxCopyBytes:       -10 * 1024 * 1024,
 | 
									JSONPatchMaxCopyBytes:       -10 * 1024 * 1024,
 | 
				
			||||||
				MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
									MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
				
			||||||
				ComponentGlobalsRegistry:    featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:    defaultComponentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectErr: "ServerRunOptions.JSONPatchMaxCopyBytes can not be negative value",
 | 
								expectErr: "ServerRunOptions.JSONPatchMaxCopyBytes can not be negative value",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -130,7 +130,7 @@ func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			|||||||
				MinRequestTimeout:           1800,
 | 
									MinRequestTimeout:           1800,
 | 
				
			||||||
				JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
									JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
				
			||||||
				MaxRequestBodyBytes:         -10 * 1024 * 1024,
 | 
									MaxRequestBodyBytes:         -10 * 1024 * 1024,
 | 
				
			||||||
				ComponentGlobalsRegistry:    featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:    defaultComponentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectErr: "ServerRunOptions.MaxRequestBodyBytes can not be negative value",
 | 
								expectErr: "ServerRunOptions.MaxRequestBodyBytes can not be negative value",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -146,7 +146,7 @@ func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			|||||||
				JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
									JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
				
			||||||
				MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
									MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
				
			||||||
				LivezGracePeriod:            -time.Second,
 | 
									LivezGracePeriod:            -time.Second,
 | 
				
			||||||
				ComponentGlobalsRegistry:    featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:    defaultComponentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectErr: "--livez-grace-period can not be a negative value",
 | 
								expectErr: "--livez-grace-period can not be a negative value",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -162,7 +162,7 @@ func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			|||||||
				JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
									JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
				
			||||||
				MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
									MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
				
			||||||
				ShutdownDelayDuration:       -time.Second,
 | 
									ShutdownDelayDuration:       -time.Second,
 | 
				
			||||||
				ComponentGlobalsRegistry:    featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:    defaultComponentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectErr: "--shutdown-delay-duration can not be negative value",
 | 
								expectErr: "--shutdown-delay-duration can not be negative value",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -178,7 +178,7 @@ func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			|||||||
				MinRequestTimeout:           1800,
 | 
									MinRequestTimeout:           1800,
 | 
				
			||||||
				JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
									JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
				
			||||||
				MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
									MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
				
			||||||
				ComponentGlobalsRegistry:    featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:    defaultComponentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			expectErr: "--strict-transport-security-directives invalid, allowed values: max-age=expireTime, includeSubDomains, preload. see https://tools.ietf.org/html/rfc6797#section-6.1 for more information",
 | 
								expectErr: "--strict-transport-security-directives invalid, allowed values: max-age=expireTime, includeSubDomains, preload. see https://tools.ietf.org/html/rfc6797#section-6.1 for more information",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -211,7 +211,7 @@ func TestServerRunOptionsValidate(t *testing.T) {
 | 
				
			|||||||
				MinRequestTimeout:           1800,
 | 
									MinRequestTimeout:           1800,
 | 
				
			||||||
				JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
									JSONPatchMaxCopyBytes:       10 * 1024 * 1024,
 | 
				
			||||||
				MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
									MaxRequestBodyBytes:         10 * 1024 * 1024,
 | 
				
			||||||
				ComponentGlobalsRegistry:    featuregate.DefaultComponentGlobalsRegistry,
 | 
									ComponentGlobalsRegistry:    defaultComponentGlobalsRegistry,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/discovery"
 | 
						"k8s.io/client-go/discovery"
 | 
				
			||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
	cliflag "k8s.io/component-base/cli/flag"
 | 
						cliflag "k8s.io/component-base/cli/flag"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/klog/v2/ktesting"
 | 
						"k8s.io/klog/v2/ktesting"
 | 
				
			||||||
	netutils "k8s.io/utils/net"
 | 
						netutils "k8s.io/utils/net"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -278,7 +278,7 @@ func TestServerRunWithSNI(t *testing.T) {
 | 
				
			|||||||
			// launch server
 | 
								// launch server
 | 
				
			||||||
			config := setUp(t)
 | 
								config := setUp(t)
 | 
				
			||||||
			v := fakeVersion()
 | 
								v := fakeVersion()
 | 
				
			||||||
			config.EffectiveVersion = utilversion.NewEffectiveVersion(v.String())
 | 
								config.EffectiveVersion = basecompatibility.NewEffectiveVersionFromString(v.String(), "", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			config.EnableIndex = true
 | 
								config.EnableIndex = true
 | 
				
			||||||
			secureOptions := (&SecureServingOptions{
 | 
								secureOptions := (&SecureServingOptions{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,8 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
	apimachineryversion "k8s.io/apimachinery/pkg/util/version"
 | 
						apimachineryversion "k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	version "k8s.io/component-base/version"
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ResourceEncodingConfig interface {
 | 
					type ResourceEncodingConfig interface {
 | 
				
			||||||
@@ -43,7 +44,7 @@ type DefaultResourceEncodingConfig struct {
 | 
				
			|||||||
	// resources records the overriding encoding configs for individual resources.
 | 
						// resources records the overriding encoding configs for individual resources.
 | 
				
			||||||
	resources        map[schema.GroupResource]*OverridingResourceEncoding
 | 
						resources        map[schema.GroupResource]*OverridingResourceEncoding
 | 
				
			||||||
	scheme           *runtime.Scheme
 | 
						scheme           *runtime.Scheme
 | 
				
			||||||
	effectiveVersion version.EffectiveVersion
 | 
						effectiveVersion basecompatibility.EffectiveVersion
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type OverridingResourceEncoding struct {
 | 
					type OverridingResourceEncoding struct {
 | 
				
			||||||
@@ -54,7 +55,11 @@ type OverridingResourceEncoding struct {
 | 
				
			|||||||
var _ ResourceEncodingConfig = &DefaultResourceEncodingConfig{}
 | 
					var _ ResourceEncodingConfig = &DefaultResourceEncodingConfig{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewDefaultResourceEncodingConfig(scheme *runtime.Scheme) *DefaultResourceEncodingConfig {
 | 
					func NewDefaultResourceEncodingConfig(scheme *runtime.Scheme) *DefaultResourceEncodingConfig {
 | 
				
			||||||
	return &DefaultResourceEncodingConfig{resources: map[schema.GroupResource]*OverridingResourceEncoding{}, scheme: scheme, effectiveVersion: version.DefaultKubeEffectiveVersion()}
 | 
						return NewDefaultResourceEncodingConfigForEffectiveVersion(scheme, compatibility.DefaultComponentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewDefaultResourceEncodingConfigForEffectiveVersion(scheme *runtime.Scheme, effectiveVersion basecompatibility.EffectiveVersion) *DefaultResourceEncodingConfig {
 | 
				
			||||||
 | 
						return &DefaultResourceEncodingConfig{resources: map[schema.GroupResource]*OverridingResourceEncoding{}, scheme: scheme, effectiveVersion: effectiveVersion}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (o *DefaultResourceEncodingConfig) SetResourceEncoding(resourceBeingStored schema.GroupResource, externalEncodingVersion, internalVersion schema.GroupVersion) {
 | 
					func (o *DefaultResourceEncodingConfig) SetResourceEncoding(resourceBeingStored schema.GroupResource, externalEncodingVersion, internalVersion schema.GroupVersion) {
 | 
				
			||||||
@@ -64,7 +69,7 @@ func (o *DefaultResourceEncodingConfig) SetResourceEncoding(resourceBeingStored
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (o *DefaultResourceEncodingConfig) SetEffectiveVersion(effectiveVersion version.EffectiveVersion) {
 | 
					func (o *DefaultResourceEncodingConfig) SetEffectiveVersion(effectiveVersion basecompatibility.EffectiveVersion) {
 | 
				
			||||||
	o.effectiveVersion = effectiveVersion
 | 
						o.effectiveVersion = effectiveVersion
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -121,7 +126,7 @@ type replacementInterface interface {
 | 
				
			|||||||
	APILifecycleReplacement() schema.GroupVersionKind
 | 
						APILifecycleReplacement() schema.GroupVersionKind
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func emulatedStorageVersion(binaryVersionOfResource schema.GroupVersion, example runtime.Object, effectiveVersion version.EffectiveVersion, scheme *runtime.Scheme) (schema.GroupVersion, error) {
 | 
					func emulatedStorageVersion(binaryVersionOfResource schema.GroupVersion, example runtime.Object, effectiveVersion basecompatibility.EffectiveVersion, scheme *runtime.Scheme) (schema.GroupVersion, error) {
 | 
				
			||||||
	if example == nil || effectiveVersion == nil {
 | 
						if example == nil || effectiveVersion == nil {
 | 
				
			||||||
		return binaryVersionOfResource, nil
 | 
							return binaryVersionOfResource, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -172,7 +177,7 @@ func emulatedStorageVersion(binaryVersionOfResource schema.GroupVersion, example
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// If it was introduced after current compatibility version, don't use it
 | 
							// If it was introduced after current compatibility version, don't use it
 | 
				
			||||||
		// skip the introduced check for test when currentVersion is 0.0 to test all apis
 | 
							// skip the introduced check for test when current compatibility version is 0.0 to test all apis
 | 
				
			||||||
		if introduced, hasIntroduced := exampleOfGVK.(introducedInterface); hasIntroduced && (compatibilityVersion.Major() > 0 || compatibilityVersion.Minor() > 0) {
 | 
							if introduced, hasIntroduced := exampleOfGVK.(introducedInterface); hasIntroduced && (compatibilityVersion.Major() > 0 || compatibilityVersion.Minor() > 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Skip versions that have a replacement.
 | 
								// Skip versions that have a replacement.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,7 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/test"
 | 
						"k8s.io/apimachinery/pkg/test"
 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	utilversion "k8s.io/apimachinery/pkg/util/version"
 | 
						utilversion "k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	"k8s.io/component-base/version"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestEmulatedStorageVersion(t *testing.T) {
 | 
					func TestEmulatedStorageVersion(t *testing.T) {
 | 
				
			||||||
@@ -33,21 +33,21 @@ func TestEmulatedStorageVersion(t *testing.T) {
 | 
				
			|||||||
		name             string
 | 
							name             string
 | 
				
			||||||
		scheme           *runtime.Scheme
 | 
							scheme           *runtime.Scheme
 | 
				
			||||||
		binaryVersion    schema.GroupVersion
 | 
							binaryVersion    schema.GroupVersion
 | 
				
			||||||
		effectiveVersion version.EffectiveVersion
 | 
							effectiveVersion basecompatibility.EffectiveVersion
 | 
				
			||||||
		want             schema.GroupVersion
 | 
							want             schema.GroupVersion
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name:             "pick compatible",
 | 
								name:             "pick compatible",
 | 
				
			||||||
			scheme:           AlphaBetaScheme(utilversion.MustParse("1.31"), utilversion.MustParse("1.32")),
 | 
								scheme:           AlphaBetaScheme(utilversion.MustParse("1.31"), utilversion.MustParse("1.32")),
 | 
				
			||||||
			binaryVersion:    v1beta1,
 | 
								binaryVersion:    v1beta1,
 | 
				
			||||||
			effectiveVersion: version.NewEffectiveVersion("1.32"),
 | 
								effectiveVersion: basecompatibility.NewEffectiveVersionFromString("1.32", "", ""),
 | 
				
			||||||
			want:             v1alpha1,
 | 
								want:             v1alpha1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name:             "alpha has been replaced, pick binary version",
 | 
								name:             "alpha has been replaced, pick binary version",
 | 
				
			||||||
			scheme:           AlphaReplacedBetaScheme(utilversion.MustParse("1.31"), utilversion.MustParse("1.32")),
 | 
								scheme:           AlphaReplacedBetaScheme(utilversion.MustParse("1.31"), utilversion.MustParse("1.32")),
 | 
				
			||||||
			binaryVersion:    v1beta1,
 | 
								binaryVersion:    v1beta1,
 | 
				
			||||||
			effectiveVersion: version.NewEffectiveVersion("1.32"),
 | 
								effectiveVersion: basecompatibility.NewEffectiveVersionFromString("1.32", "", ""),
 | 
				
			||||||
			want:             v1beta1,
 | 
								want:             v1beta1,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ import (
 | 
				
			|||||||
	"k8s.io/apiserver/pkg/apis/example2"
 | 
						"k8s.io/apiserver/pkg/apis/example2"
 | 
				
			||||||
	example2install "k8s.io/apiserver/pkg/apis/example2/install"
 | 
						example2install "k8s.io/apiserver/pkg/apis/example2/install"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/storage/storagebackend"
 | 
						"k8s.io/apiserver/pkg/storage/storagebackend"
 | 
				
			||||||
	version "k8s.io/component-base/version"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -569,8 +569,7 @@ func TestStorageFactoryCompatibilityVersion(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		gvk := gvks[0]
 | 
							gvk := gvks[0]
 | 
				
			||||||
		t.Run(gvk.GroupKind().String()+"@"+tc.effectiveVersion, func(t *testing.T) {
 | 
							t.Run(gvk.GroupKind().String()+"@"+tc.effectiveVersion, func(t *testing.T) {
 | 
				
			||||||
			config := NewDefaultResourceEncodingConfig(sch)
 | 
								config := NewDefaultResourceEncodingConfigForEffectiveVersion(sch, basecompatibility.NewEffectiveVersionFromString(tc.effectiveVersion, "", ""))
 | 
				
			||||||
			config.SetEffectiveVersion(version.NewEffectiveVersion(tc.effectiveVersion))
 | 
					 | 
				
			||||||
			f := NewDefaultStorageFactory(
 | 
								f := NewDefaultStorageFactory(
 | 
				
			||||||
				storagebackend.Config{},
 | 
									storagebackend.Config{},
 | 
				
			||||||
				"",
 | 
									"",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2025 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DefaultComponentGlobalsRegistry is the global var to store the effective versions and feature gates for all components for easy access.
 | 
				
			||||||
 | 
					// Example usage:
 | 
				
			||||||
 | 
					// // register the component effective version and feature gate first
 | 
				
			||||||
 | 
					// wardleEffectiveVersion := basecompatibility.NewEffectiveVersion("1.2")
 | 
				
			||||||
 | 
					// wardleFeatureGate := featuregate.NewFeatureGate()
 | 
				
			||||||
 | 
					// utilruntime.Must(compatibility.DefaultComponentGlobalsRegistry.Register(apiserver.WardleComponentName, wardleEffectiveVersion, wardleFeatureGate, false))
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	cmd := &cobra.Command{
 | 
				
			||||||
 | 
					//	 ...
 | 
				
			||||||
 | 
					//		// call DefaultComponentGlobalsRegistry.Set() in PersistentPreRunE to ensure the feature gates are set based on emulation version right after parsing the flags.
 | 
				
			||||||
 | 
					//		PersistentPreRunE: func(*cobra.Command, []string) error {
 | 
				
			||||||
 | 
					//			if err := compatibility.DefaultComponentGlobalsRegistry.Set(); err != nil {
 | 
				
			||||||
 | 
					//				return err
 | 
				
			||||||
 | 
					//			}
 | 
				
			||||||
 | 
					//	 ...
 | 
				
			||||||
 | 
					//		},
 | 
				
			||||||
 | 
					//		RunE: func(c *cobra.Command, args []string) error {
 | 
				
			||||||
 | 
					//			// call compatibility.DefaultComponentGlobalsRegistry.Validate() somewhere
 | 
				
			||||||
 | 
					//		},
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// flags := cmd.Flags()
 | 
				
			||||||
 | 
					// // add flags
 | 
				
			||||||
 | 
					// compatibility.DefaultComponentGlobalsRegistry.AddFlags(flags)
 | 
				
			||||||
 | 
					var DefaultComponentGlobalsRegistry basecompatibility.ComponentGlobalsRegistry = basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						utilruntime.Must(DefaultComponentGlobalsRegistry.Register(basecompatibility.DefaultKubeComponent, DefaultBuildEffectiveVersion(), utilfeature.DefaultMutableFeatureGate))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2025 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
 | 
						baseversion "k8s.io/component-base/version"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// minimumKubeEmulationVersion is the first release emulation version is introduced,
 | 
				
			||||||
 | 
					// so the emulation version cannot go lower than that.
 | 
				
			||||||
 | 
					var minimumKubeEmulationVersion *version.Version = version.MajorMinor(1, 31)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DefaultBuildEffectiveVersion returns the MutableEffectiveVersion based on the
 | 
				
			||||||
 | 
					// current build information.
 | 
				
			||||||
 | 
					func DefaultBuildEffectiveVersion() basecompatibility.MutableEffectiveVersion {
 | 
				
			||||||
 | 
						binaryVersion := defaultBuildBinaryVersion()
 | 
				
			||||||
 | 
						useDefaultBuildBinaryVersion := true
 | 
				
			||||||
 | 
						// fall back to the hard coded kube version only when the git tag is not available for local unit tests.
 | 
				
			||||||
 | 
						if binaryVersion.Major() == 0 && binaryVersion.Minor() == 0 {
 | 
				
			||||||
 | 
							useDefaultBuildBinaryVersion = false
 | 
				
			||||||
 | 
							binaryVersion = version.MustParse(baseversion.DefaultKubeBinaryVersion)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						versionFloor := kubeEffectiveVersionFloors(binaryVersion)
 | 
				
			||||||
 | 
						return basecompatibility.NewEffectiveVersion(binaryVersion, useDefaultBuildBinaryVersion, versionFloor, versionFloor)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func kubeEffectiveVersionFloors(binaryVersion *version.Version) *version.Version {
 | 
				
			||||||
 | 
						// both emulationVersion and minCompatibilityVersion can be set to binaryVersion - 3
 | 
				
			||||||
 | 
						versionFloor := binaryVersion.WithPatch(0).SubtractMinor(3)
 | 
				
			||||||
 | 
						if versionFloor.LessThan(minimumKubeEmulationVersion) {
 | 
				
			||||||
 | 
							versionFloor = minimumKubeEmulationVersion
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return versionFloor
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DefaultKubeEffectiveVersionForTest returns the MutableEffectiveVersion based on the
 | 
				
			||||||
 | 
					// latest K8s release hardcoded in DefaultKubeBinaryVersion.
 | 
				
			||||||
 | 
					// DefaultKubeBinaryVersion is hard coded because defaultBuildBinaryVersion would return 0.0 when test is run without a git tag.
 | 
				
			||||||
 | 
					// We do not enforce the N-3..N emulation version range in tests so that the tests would not automatically fail when there is a version bump.
 | 
				
			||||||
 | 
					// Only used in tests.
 | 
				
			||||||
 | 
					func DefaultKubeEffectiveVersionForTest() basecompatibility.MutableEffectiveVersion {
 | 
				
			||||||
 | 
						binaryVersion := version.MustParse(baseversion.DefaultKubeBinaryVersion).WithInfo(baseversion.Get())
 | 
				
			||||||
 | 
						return basecompatibility.NewEffectiveVersion(binaryVersion, false, version.MustParse("0.0"), version.MustParse("0.0"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func defaultBuildBinaryVersion() *version.Version {
 | 
				
			||||||
 | 
						verInfo := baseversion.Get()
 | 
				
			||||||
 | 
						return version.MustParse(verInfo.String()).WithInfo(verInfo)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2025 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestValidateKubeEffectiveVersion(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							name                    string
 | 
				
			||||||
 | 
							emulationVersion        string
 | 
				
			||||||
 | 
							minCompatibilityVersion string
 | 
				
			||||||
 | 
							expectErr               bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                    "valid versions",
 | 
				
			||||||
 | 
								emulationVersion:        "v1.32.0",
 | 
				
			||||||
 | 
								minCompatibilityVersion: "v1.31.0",
 | 
				
			||||||
 | 
								expectErr:               false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                    "emulationVersion too low",
 | 
				
			||||||
 | 
								emulationVersion:        "v1.30.0",
 | 
				
			||||||
 | 
								minCompatibilityVersion: "v1.31.0",
 | 
				
			||||||
 | 
								expectErr:               true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                    "minCompatibilityVersion too low",
 | 
				
			||||||
 | 
								emulationVersion:        "v1.31.0",
 | 
				
			||||||
 | 
								minCompatibilityVersion: "v1.30.0",
 | 
				
			||||||
 | 
								expectErr:               true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                    "both versions too low",
 | 
				
			||||||
 | 
								emulationVersion:        "v1.30.0",
 | 
				
			||||||
 | 
								minCompatibilityVersion: "v1.29.0",
 | 
				
			||||||
 | 
								expectErr:               true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							t.Run(test.name, func(t *testing.T) {
 | 
				
			||||||
 | 
								binaryVersion := version.MustParseGeneric("1.33")
 | 
				
			||||||
 | 
								versionFloor := kubeEffectiveVersionFloors(binaryVersion)
 | 
				
			||||||
 | 
								effective := basecompatibility.NewEffectiveVersion(binaryVersion, false, versionFloor, versionFloor)
 | 
				
			||||||
 | 
								effective.SetEmulationVersion(version.MustParseGeneric(test.emulationVersion))
 | 
				
			||||||
 | 
								effective.SetMinCompatibilityVersion(version.MustParseGeneric(test.minCompatibilityVersion))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								err := effective.Validate()
 | 
				
			||||||
 | 
								if test.expectErr && err == nil {
 | 
				
			||||||
 | 
									t.Error("expected error, but got nil")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if !test.expectErr && err != nil {
 | 
				
			||||||
 | 
									t.Errorf("unexpected error: %v", err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								staging/src/k8s.io/component-base/compatibility/OWNERS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								staging/src/k8s.io/component-base/compatibility/OWNERS
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					# See the OWNERS docs at https://go.k8s.io/owners
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Currently assigned this directory to sig-api-machinery since this is
 | 
				
			||||||
 | 
					# an interface to the version definition in "k8s.io/apiserver/pkg/util/compatibility".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					approvers:
 | 
				
			||||||
 | 
					  - sig-api-machinery-api-approvers
 | 
				
			||||||
 | 
					reviewers:
 | 
				
			||||||
 | 
					  - sig-api-machinery-api-reviewers
 | 
				
			||||||
 | 
					  - siyuanfoundation
 | 
				
			||||||
 | 
					labels:
 | 
				
			||||||
 | 
					  - sig/api-machinery
 | 
				
			||||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package featuregate
 | 
					package compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
@@ -26,38 +26,12 @@ import (
 | 
				
			|||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	cliflag "k8s.io/component-base/cli/flag"
 | 
						cliflag "k8s.io/component-base/cli/flag"
 | 
				
			||||||
	baseversion "k8s.io/component-base/version"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DefaultComponentGlobalsRegistry is the global var to store the effective versions and feature gates for all components for easy access.
 | 
					 | 
				
			||||||
// Example usage:
 | 
					 | 
				
			||||||
// // register the component effective version and feature gate first
 | 
					 | 
				
			||||||
// _, _ = utilversion.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister(utilversion.DefaultKubeComponent, utilversion.DefaultKubeEffectiveVersion(), utilfeature.DefaultMutableFeatureGate)
 | 
					 | 
				
			||||||
// wardleEffectiveVersion := utilversion.NewEffectiveVersion("1.2")
 | 
					 | 
				
			||||||
// wardleFeatureGate := featuregate.NewFeatureGate()
 | 
					 | 
				
			||||||
// utilruntime.Must(utilversion.DefaultComponentGlobalsRegistry.Register(apiserver.WardleComponentName, wardleEffectiveVersion, wardleFeatureGate, false))
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//	cmd := &cobra.Command{
 | 
					 | 
				
			||||||
//	 ...
 | 
					 | 
				
			||||||
//		// call DefaultComponentGlobalsRegistry.Set() in PersistentPreRunE
 | 
					 | 
				
			||||||
//		PersistentPreRunE: func(*cobra.Command, []string) error {
 | 
					 | 
				
			||||||
//			if err := utilversion.DefaultComponentGlobalsRegistry.Set(); err != nil {
 | 
					 | 
				
			||||||
//				return err
 | 
					 | 
				
			||||||
//			}
 | 
					 | 
				
			||||||
//	 ...
 | 
					 | 
				
			||||||
//		},
 | 
					 | 
				
			||||||
//		RunE: func(c *cobra.Command, args []string) error {
 | 
					 | 
				
			||||||
//			// call utilversion.DefaultComponentGlobalsRegistry.Validate() somewhere
 | 
					 | 
				
			||||||
//		},
 | 
					 | 
				
			||||||
//	}
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// flags := cmd.Flags()
 | 
					 | 
				
			||||||
// // add flags
 | 
					 | 
				
			||||||
// utilversion.DefaultComponentGlobalsRegistry.AddFlags(flags)
 | 
					 | 
				
			||||||
var DefaultComponentGlobalsRegistry ComponentGlobalsRegistry = NewComponentGlobalsRegistry()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
 | 
						// DefaultKubeComponent is the component name for k8s control plane components.
 | 
				
			||||||
	DefaultKubeComponent = "kube"
 | 
						DefaultKubeComponent = "kube"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	klogLevel = 2
 | 
						klogLevel = 2
 | 
				
			||||||
@@ -65,10 +39,10 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type VersionMapping func(from *version.Version) *version.Version
 | 
					type VersionMapping func(from *version.Version) *version.Version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ComponentGlobals stores the global variables for a component for easy access.
 | 
					// ComponentGlobals stores the global variables for a component for easy access, including feature gate and effective version.
 | 
				
			||||||
type ComponentGlobals struct {
 | 
					type ComponentGlobals struct {
 | 
				
			||||||
	effectiveVersion baseversion.MutableEffectiveVersion
 | 
						effectiveVersion MutableEffectiveVersion
 | 
				
			||||||
	featureGate      MutableVersionedFeatureGate
 | 
						featureGate      featuregate.MutableVersionedFeatureGate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// emulationVersionMapping contains the mapping from the emulation version of this component
 | 
						// emulationVersionMapping contains the mapping from the emulation version of this component
 | 
				
			||||||
	// to the emulation version of another component.
 | 
						// to the emulation version of another component.
 | 
				
			||||||
@@ -84,22 +58,24 @@ type ComponentGlobals struct {
 | 
				
			|||||||
	dependentMinCompatibilityVersion bool
 | 
						dependentMinCompatibilityVersion bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ComponentGlobalsRegistry stores the global variables for different components for easy access, including feature gate and effective version of each component.
 | 
				
			||||||
type ComponentGlobalsRegistry interface {
 | 
					type ComponentGlobalsRegistry interface {
 | 
				
			||||||
	// EffectiveVersionFor returns the EffectiveVersion registered under the component.
 | 
						// EffectiveVersionFor returns the EffectiveVersion registered under the component.
 | 
				
			||||||
	// Returns nil if the component is not registered.
 | 
						// Returns nil if the component is not registered.
 | 
				
			||||||
	EffectiveVersionFor(component string) baseversion.EffectiveVersion
 | 
						EffectiveVersionFor(component string) EffectiveVersion
 | 
				
			||||||
	// FeatureGateFor returns the FeatureGate registered under the component.
 | 
						// FeatureGateFor returns the FeatureGate registered under the component.
 | 
				
			||||||
	// Returns nil if the component is not registered.
 | 
						// Returns nil if the component is not registered.
 | 
				
			||||||
	FeatureGateFor(component string) FeatureGate
 | 
						FeatureGateFor(component string) featuregate.FeatureGate
 | 
				
			||||||
	// Register registers the EffectiveVersion and FeatureGate for a component.
 | 
						// Register registers the EffectiveVersion and FeatureGate for a component.
 | 
				
			||||||
	// returns error if the component is already registered.
 | 
						// returns error if the component is already registered.
 | 
				
			||||||
	Register(component string, effectiveVersion baseversion.MutableEffectiveVersion, featureGate MutableVersionedFeatureGate) error
 | 
						Register(component string, effectiveVersion MutableEffectiveVersion, featureGate featuregate.MutableVersionedFeatureGate) error
 | 
				
			||||||
	// ComponentGlobalsOrRegister would return the registered global variables for the component if it already exists in the registry.
 | 
						// ComponentGlobalsOrRegister would return the registered global variables for the component if it already exists in the registry.
 | 
				
			||||||
	// Otherwise, the provided variables would be registered under the component, and the same variables would be returned.
 | 
						// Otherwise, the provided variables would be registered under the component, and the same variables would be returned.
 | 
				
			||||||
	ComponentGlobalsOrRegister(component string, effectiveVersion baseversion.MutableEffectiveVersion, featureGate MutableVersionedFeatureGate) (baseversion.MutableEffectiveVersion, MutableVersionedFeatureGate)
 | 
						ComponentGlobalsOrRegister(component string, effectiveVersion MutableEffectiveVersion, featureGate featuregate.MutableVersionedFeatureGate) (MutableEffectiveVersion, featuregate.MutableVersionedFeatureGate)
 | 
				
			||||||
	// AddFlags adds flags of "--emulated-version" and "--feature-gates"
 | 
						// AddFlags adds flags of "--emulated-version" and "--feature-gates"
 | 
				
			||||||
	AddFlags(fs *pflag.FlagSet)
 | 
						AddFlags(fs *pflag.FlagSet)
 | 
				
			||||||
	// Set sets the flags for all global variables for all components registered.
 | 
						// Set sets the flags for all global variables for all components registered.
 | 
				
			||||||
 | 
						// A component's feature gate and effective version would not be updated until Set() is called.
 | 
				
			||||||
	Set() error
 | 
						Set() error
 | 
				
			||||||
	// SetFallback calls Set() if it has never been called.
 | 
						// SetFallback calls Set() if it has never been called.
 | 
				
			||||||
	SetFallback() error
 | 
						SetFallback() error
 | 
				
			||||||
@@ -118,9 +94,13 @@ type ComponentGlobalsRegistry interface {
 | 
				
			|||||||
type componentGlobalsRegistry struct {
 | 
					type componentGlobalsRegistry struct {
 | 
				
			||||||
	componentGlobals map[string]*ComponentGlobals
 | 
						componentGlobals map[string]*ComponentGlobals
 | 
				
			||||||
	mutex            sync.RWMutex
 | 
						mutex            sync.RWMutex
 | 
				
			||||||
	// list of component name to emulation version set from the flag.
 | 
						// emulationVersionConfig stores the list of component name to emulation version set from the flag.
 | 
				
			||||||
 | 
						// When the `--emulated-version` flag is parsed, it would not take effect until Set() is called,
 | 
				
			||||||
 | 
						// because the emulation version needs to be set before the feature gate is set.
 | 
				
			||||||
	emulationVersionConfig []string
 | 
						emulationVersionConfig []string
 | 
				
			||||||
	// map of component name to the list of feature gates set from the flag.
 | 
						// featureGatesConfig stores the map of component name to the list of feature gates set from the flag.
 | 
				
			||||||
 | 
						// When the `--feature-gates` flag is parsed, it would not take effect until Set() is called,
 | 
				
			||||||
 | 
						// because the emulation version needs to be set before the feature gate is set.
 | 
				
			||||||
	featureGatesConfig map[string][]string
 | 
						featureGatesConfig map[string][]string
 | 
				
			||||||
	// set stores if the Set() function for the registry is already called.
 | 
						// set stores if the Set() function for the registry is already called.
 | 
				
			||||||
	set bool
 | 
						set bool
 | 
				
			||||||
@@ -143,7 +123,7 @@ func (r *componentGlobalsRegistry) Reset() {
 | 
				
			|||||||
	r.set = false
 | 
						r.set = false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *componentGlobalsRegistry) EffectiveVersionFor(component string) baseversion.EffectiveVersion {
 | 
					func (r *componentGlobalsRegistry) EffectiveVersionFor(component string) EffectiveVersion {
 | 
				
			||||||
	r.mutex.RLock()
 | 
						r.mutex.RLock()
 | 
				
			||||||
	defer r.mutex.RUnlock()
 | 
						defer r.mutex.RUnlock()
 | 
				
			||||||
	globals, ok := r.componentGlobals[component]
 | 
						globals, ok := r.componentGlobals[component]
 | 
				
			||||||
@@ -153,7 +133,7 @@ func (r *componentGlobalsRegistry) EffectiveVersionFor(component string) basever
 | 
				
			|||||||
	return globals.effectiveVersion
 | 
						return globals.effectiveVersion
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *componentGlobalsRegistry) FeatureGateFor(component string) FeatureGate {
 | 
					func (r *componentGlobalsRegistry) FeatureGateFor(component string) featuregate.FeatureGate {
 | 
				
			||||||
	r.mutex.RLock()
 | 
						r.mutex.RLock()
 | 
				
			||||||
	defer r.mutex.RUnlock()
 | 
						defer r.mutex.RUnlock()
 | 
				
			||||||
	globals, ok := r.componentGlobals[component]
 | 
						globals, ok := r.componentGlobals[component]
 | 
				
			||||||
@@ -163,7 +143,7 @@ func (r *componentGlobalsRegistry) FeatureGateFor(component string) FeatureGate
 | 
				
			|||||||
	return globals.featureGate
 | 
						return globals.featureGate
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *componentGlobalsRegistry) unsafeRegister(component string, effectiveVersion baseversion.MutableEffectiveVersion, featureGate MutableVersionedFeatureGate) error {
 | 
					func (r *componentGlobalsRegistry) unsafeRegister(component string, effectiveVersion MutableEffectiveVersion, featureGate featuregate.MutableVersionedFeatureGate) error {
 | 
				
			||||||
	if _, ok := r.componentGlobals[component]; ok {
 | 
						if _, ok := r.componentGlobals[component]; ok {
 | 
				
			||||||
		return fmt.Errorf("component globals of %s already registered", component)
 | 
							return fmt.Errorf("component globals of %s already registered", component)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -182,7 +162,7 @@ func (r *componentGlobalsRegistry) unsafeRegister(component string, effectiveVer
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *componentGlobalsRegistry) Register(component string, effectiveVersion baseversion.MutableEffectiveVersion, featureGate MutableVersionedFeatureGate) error {
 | 
					func (r *componentGlobalsRegistry) Register(component string, effectiveVersion MutableEffectiveVersion, featureGate featuregate.MutableVersionedFeatureGate) error {
 | 
				
			||||||
	if effectiveVersion == nil {
 | 
						if effectiveVersion == nil {
 | 
				
			||||||
		return fmt.Errorf("cannot register nil effectiveVersion")
 | 
							return fmt.Errorf("cannot register nil effectiveVersion")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -191,7 +171,7 @@ func (r *componentGlobalsRegistry) Register(component string, effectiveVersion b
 | 
				
			|||||||
	return r.unsafeRegister(component, effectiveVersion, featureGate)
 | 
						return r.unsafeRegister(component, effectiveVersion, featureGate)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *componentGlobalsRegistry) ComponentGlobalsOrRegister(component string, effectiveVersion baseversion.MutableEffectiveVersion, featureGate MutableVersionedFeatureGate) (baseversion.MutableEffectiveVersion, MutableVersionedFeatureGate) {
 | 
					func (r *componentGlobalsRegistry) ComponentGlobalsOrRegister(component string, effectiveVersion MutableEffectiveVersion, featureGate featuregate.MutableVersionedFeatureGate) (MutableEffectiveVersion, featuregate.MutableVersionedFeatureGate) {
 | 
				
			||||||
	r.mutex.Lock()
 | 
						r.mutex.Lock()
 | 
				
			||||||
	defer r.mutex.Unlock()
 | 
						defer r.mutex.Unlock()
 | 
				
			||||||
	globals, ok := r.componentGlobals[component]
 | 
						globals, ok := r.componentGlobals[component]
 | 
				
			||||||
@@ -219,22 +199,16 @@ func (r *componentGlobalsRegistry) unsafeKnownFeatures() []string {
 | 
				
			|||||||
func (r *componentGlobalsRegistry) unsafeVersionFlagOptions(isEmulation bool) []string {
 | 
					func (r *componentGlobalsRegistry) unsafeVersionFlagOptions(isEmulation bool) []string {
 | 
				
			||||||
	var vs []string
 | 
						var vs []string
 | 
				
			||||||
	for component, globals := range r.componentGlobals {
 | 
						for component, globals := range r.componentGlobals {
 | 
				
			||||||
		binaryVer := globals.effectiveVersion.BinaryVersion()
 | 
					 | 
				
			||||||
		if isEmulation {
 | 
							if isEmulation {
 | 
				
			||||||
			if globals.dependentEmulationVersion {
 | 
								if globals.dependentEmulationVersion {
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// emulated version could be between binaryMajor.{binaryMinor} and binaryMajor.{binaryMinor}
 | 
								vs = append(vs, fmt.Sprintf("%s=%s", component, globals.effectiveVersion.AllowedEmulationVersionRange()))
 | 
				
			||||||
			// TODO: change to binaryMajor.{binaryMinor-1} and binaryMajor.{binaryMinor} in 1.32
 | 
					 | 
				
			||||||
			vs = append(vs, fmt.Sprintf("%s=%s..%s (default=%s)", component,
 | 
					 | 
				
			||||||
				binaryVer.SubtractMinor(0).String(), binaryVer.String(), globals.effectiveVersion.EmulationVersion().String()))
 | 
					 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			if globals.dependentMinCompatibilityVersion {
 | 
								if globals.dependentMinCompatibilityVersion {
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// min compatibility version could be between binaryMajor.{binaryMinor-1} and binaryMajor.{binaryMinor}
 | 
								vs = append(vs, fmt.Sprintf("%s=%s", component, globals.effectiveVersion.AllowedMinCompatibilityVersionRange()))
 | 
				
			||||||
			vs = append(vs, fmt.Sprintf("%s=%s..%s (default=%s)", component,
 | 
					 | 
				
			||||||
				binaryVer.SubtractMinor(1).String(), binaryVer.String(), globals.effectiveVersion.MinCompatibilityVersion().String()))
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sort.Strings(vs)
 | 
						sort.Strings(vs)
 | 
				
			||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
Copyright 2024 The Kubernetes Authors.
 | 
					Copyright 2025 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
you may not use this file except in compliance with the License.
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package featuregate
 | 
					package compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
@@ -25,7 +25,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	baseversion "k8s.io/component-base/version"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@@ -34,8 +34,8 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestEffectiveVersionRegistry(t *testing.T) {
 | 
					func TestEffectiveVersionRegistry(t *testing.T) {
 | 
				
			||||||
	r := NewComponentGlobalsRegistry()
 | 
						r := NewComponentGlobalsRegistry()
 | 
				
			||||||
	ver1 := baseversion.NewEffectiveVersion("1.31")
 | 
						ver1 := NewEffectiveVersionFromString("1.31", "", "")
 | 
				
			||||||
	ver2 := baseversion.NewEffectiveVersion("1.28")
 | 
						ver2 := NewEffectiveVersionFromString("1.28", "", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if r.EffectiveVersionFor(testComponent) != nil {
 | 
						if r.EffectiveVersionFor(testComponent) != nil {
 | 
				
			||||||
		t.Fatalf("expected nil EffectiveVersion initially")
 | 
							t.Fatalf("expected nil EffectiveVersion initially")
 | 
				
			||||||
@@ -57,40 +57,40 @@ func TestEffectiveVersionRegistry(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func testRegistry(t *testing.T) *componentGlobalsRegistry {
 | 
					func testRegistry(t *testing.T) *componentGlobalsRegistry {
 | 
				
			||||||
	r := NewComponentGlobalsRegistry()
 | 
						r := NewComponentGlobalsRegistry()
 | 
				
			||||||
	verKube := baseversion.NewEffectiveVersion("1.31")
 | 
						verKube := NewEffectiveVersionFromString("1.31", "1.31", "1.30")
 | 
				
			||||||
	fgKube := NewVersionedFeatureGate(version.MustParse("0.0"))
 | 
						fgKube := featuregate.NewVersionedFeatureGate(version.MustParse("0.0"))
 | 
				
			||||||
	err := fgKube.AddVersioned(map[Feature]VersionedSpecs{
 | 
						err := fgKube.AddVersioned(map[featuregate.Feature]featuregate.VersionedSpecs{
 | 
				
			||||||
		"kubeA": {
 | 
							"kubeA": {
 | 
				
			||||||
			{Version: version.MustParse("1.27"), Default: false, PreRelease: Alpha},
 | 
								{Version: version.MustParse("1.27"), Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
			{Version: version.MustParse("1.28"), Default: false, PreRelease: Beta},
 | 
								{Version: version.MustParse("1.28"), Default: false, PreRelease: featuregate.Beta},
 | 
				
			||||||
			{Version: version.MustParse("1.31"), Default: true, LockToDefault: true, PreRelease: GA},
 | 
								{Version: version.MustParse("1.31"), Default: true, LockToDefault: true, PreRelease: featuregate.GA},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"kubeB": {
 | 
							"kubeB": {
 | 
				
			||||||
			{Version: version.MustParse("1.30"), Default: false, PreRelease: Alpha},
 | 
								{Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"commonC": {
 | 
							"commonC": {
 | 
				
			||||||
			{Version: version.MustParse("1.27"), Default: false, PreRelease: Alpha},
 | 
								{Version: version.MustParse("1.27"), Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
			{Version: version.MustParse("1.29"), Default: true, PreRelease: Beta},
 | 
								{Version: version.MustParse("1.29"), Default: true, PreRelease: featuregate.Beta},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	verTest := baseversion.NewEffectiveVersion("2.8")
 | 
						verTest := NewEffectiveVersionFromString("2.8", "2.8", "2.7")
 | 
				
			||||||
	fgTest := NewVersionedFeatureGate(version.MustParse("0.0"))
 | 
						fgTest := featuregate.NewVersionedFeatureGate(version.MustParse("0.0"))
 | 
				
			||||||
	err = fgTest.AddVersioned(map[Feature]VersionedSpecs{
 | 
						err = fgTest.AddVersioned(map[featuregate.Feature]featuregate.VersionedSpecs{
 | 
				
			||||||
		"testA": {
 | 
							"testA": {
 | 
				
			||||||
			{Version: version.MustParse("2.7"), Default: false, PreRelease: Alpha},
 | 
								{Version: version.MustParse("2.7"), Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
			{Version: version.MustParse("2.8"), Default: false, PreRelease: Beta},
 | 
								{Version: version.MustParse("2.8"), Default: false, PreRelease: featuregate.Beta},
 | 
				
			||||||
			{Version: version.MustParse("2.10"), Default: true, PreRelease: GA},
 | 
								{Version: version.MustParse("2.10"), Default: true, PreRelease: featuregate.GA},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"testB": {
 | 
							"testB": {
 | 
				
			||||||
			{Version: version.MustParse("2.9"), Default: false, PreRelease: Alpha},
 | 
								{Version: version.MustParse("2.9"), Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"commonC": {
 | 
							"commonC": {
 | 
				
			||||||
			{Version: version.MustParse("2.7"), Default: false, PreRelease: Alpha},
 | 
								{Version: version.MustParse("2.7"), Default: false, PreRelease: featuregate.Alpha},
 | 
				
			||||||
			{Version: version.MustParse("2.9"), Default: true, PreRelease: Beta},
 | 
								{Version: version.MustParse("2.9"), Default: true, PreRelease: featuregate.Beta},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -154,8 +154,8 @@ func TestFlags(t *testing.T) {
 | 
				
			|||||||
		parseError                   string
 | 
							parseError                   string
 | 
				
			||||||
		expectedKubeEmulationVersion string
 | 
							expectedKubeEmulationVersion string
 | 
				
			||||||
		expectedTestEmulationVersion string
 | 
							expectedTestEmulationVersion string
 | 
				
			||||||
		expectedKubeFeatureValues    map[Feature]bool
 | 
							expectedKubeFeatureValues    map[featuregate.Feature]bool
 | 
				
			||||||
		expectedTestFeatureValues    map[Feature]bool
 | 
							expectedTestFeatureValues    map[featuregate.Feature]bool
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name:                         "setting kube emulation version",
 | 
								name:                         "setting kube emulation version",
 | 
				
			||||||
@@ -214,8 +214,8 @@ func TestFlags(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			expectedKubeEmulationVersion: "1.31",
 | 
								expectedKubeEmulationVersion: "1.31",
 | 
				
			||||||
			expectedTestEmulationVersion: "2.7",
 | 
								expectedTestEmulationVersion: "2.7",
 | 
				
			||||||
			expectedKubeFeatureValues:    map[Feature]bool{"kubeA": true, "kubeB": false, "commonC": true},
 | 
								expectedKubeFeatureValues:    map[featuregate.Feature]bool{"kubeA": true, "kubeB": false, "commonC": true},
 | 
				
			||||||
			expectedTestFeatureValues:    map[Feature]bool{"testA": true, "testB": false, "commonC": false},
 | 
								expectedTestFeatureValues:    map[featuregate.Feature]bool{"testA": true, "testB": false, "commonC": false},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "setting future test feature flag",
 | 
								name: "setting future test feature flag",
 | 
				
			||||||
@@ -235,8 +235,8 @@ func TestFlags(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			expectedKubeEmulationVersion: "1.30",
 | 
								expectedKubeEmulationVersion: "1.30",
 | 
				
			||||||
			expectedTestEmulationVersion: "2.7",
 | 
								expectedTestEmulationVersion: "2.7",
 | 
				
			||||||
			expectedKubeFeatureValues:    map[Feature]bool{"kubeA": false, "kubeB": true, "commonC": false},
 | 
								expectedKubeFeatureValues:    map[featuregate.Feature]bool{"kubeA": false, "kubeB": true, "commonC": false},
 | 
				
			||||||
			expectedTestFeatureValues:    map[Feature]bool{"testA": false, "testB": false, "commonC": true},
 | 
								expectedTestFeatureValues:    map[featuregate.Feature]bool{"testA": false, "testB": false, "commonC": true},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "setting kube feature flag with different prefix",
 | 
								name: "setting kube feature flag with different prefix",
 | 
				
			||||||
@@ -313,9 +313,9 @@ func TestFlags(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestVersionMapping(t *testing.T) {
 | 
					func TestVersionMapping(t *testing.T) {
 | 
				
			||||||
	r := NewComponentGlobalsRegistry()
 | 
						r := NewComponentGlobalsRegistry()
 | 
				
			||||||
	ver1 := baseversion.NewEffectiveVersion("0.58")
 | 
						ver1 := NewEffectiveVersionFromString("0.58", "", "")
 | 
				
			||||||
	ver2 := baseversion.NewEffectiveVersion("1.28")
 | 
						ver2 := NewEffectiveVersionFromString("1.28", "", "")
 | 
				
			||||||
	ver3 := baseversion.NewEffectiveVersion("2.10")
 | 
						ver3 := NewEffectiveVersionFromString("2.10", "", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	utilruntime.Must(r.Register("test1", ver1, nil))
 | 
						utilruntime.Must(r.Register("test1", ver1, nil))
 | 
				
			||||||
	utilruntime.Must(r.Register("test2", ver2, nil))
 | 
						utilruntime.Must(r.Register("test2", ver2, nil))
 | 
				
			||||||
@@ -355,9 +355,9 @@ func TestVersionMapping(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestVersionMappingWithMultipleDependency(t *testing.T) {
 | 
					func TestVersionMappingWithMultipleDependency(t *testing.T) {
 | 
				
			||||||
	r := NewComponentGlobalsRegistry()
 | 
						r := NewComponentGlobalsRegistry()
 | 
				
			||||||
	ver1 := baseversion.NewEffectiveVersion("0.58")
 | 
						ver1 := NewEffectiveVersionFromString("0.58", "", "")
 | 
				
			||||||
	ver2 := baseversion.NewEffectiveVersion("1.28")
 | 
						ver2 := NewEffectiveVersionFromString("1.28", "", "")
 | 
				
			||||||
	ver3 := baseversion.NewEffectiveVersion("2.10")
 | 
						ver3 := NewEffectiveVersionFromString("2.10", "", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	utilruntime.Must(r.Register("test1", ver1, nil))
 | 
						utilruntime.Must(r.Register("test1", ver1, nil))
 | 
				
			||||||
	utilruntime.Must(r.Register("test2", ver2, nil))
 | 
						utilruntime.Must(r.Register("test2", ver2, nil))
 | 
				
			||||||
@@ -382,9 +382,9 @@ func TestVersionMappingWithMultipleDependency(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestVersionMappingWithCyclicDependency(t *testing.T) {
 | 
					func TestVersionMappingWithCyclicDependency(t *testing.T) {
 | 
				
			||||||
	r := NewComponentGlobalsRegistry()
 | 
						r := NewComponentGlobalsRegistry()
 | 
				
			||||||
	ver1 := baseversion.NewEffectiveVersion("0.58")
 | 
						ver1 := NewEffectiveVersionFromString("0.58", "", "")
 | 
				
			||||||
	ver2 := baseversion.NewEffectiveVersion("1.28")
 | 
						ver2 := NewEffectiveVersionFromString("1.28", "", "")
 | 
				
			||||||
	ver3 := baseversion.NewEffectiveVersion("2.10")
 | 
						ver3 := NewEffectiveVersionFromString("2.10", "", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	utilruntime.Must(r.Register("test1", ver1, nil))
 | 
						utilruntime.Must(r.Register("test1", ver1, nil))
 | 
				
			||||||
	utilruntime.Must(r.Register("test2", ver2, nil))
 | 
						utilruntime.Must(r.Register("test2", ver2, nil))
 | 
				
			||||||
							
								
								
									
										213
									
								
								staging/src/k8s.io/component-base/compatibility/version.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								staging/src/k8s.io/component-base/compatibility/version.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,213 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2025 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"sync/atomic"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
 | 
						baseversion "k8s.io/component-base/version"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EffectiveVersion stores all the version information of a component.
 | 
				
			||||||
 | 
					type EffectiveVersion interface {
 | 
				
			||||||
 | 
						// BinaryVersion is the binary version of a component. Tied to a particular binary release.
 | 
				
			||||||
 | 
						BinaryVersion() *version.Version
 | 
				
			||||||
 | 
						// EmulationVersion is the version a component emulate its capabilities (APIs, features, ...) of.
 | 
				
			||||||
 | 
						// If EmulationVersion is set to be different from BinaryVersion, the component will emulate the behavior of this version instead of the underlying binary version.
 | 
				
			||||||
 | 
						EmulationVersion() *version.Version
 | 
				
			||||||
 | 
						// MinCompatibilityVersion is the minimum version a component is compatible with (in terms of storage versions, validation rules, ...).
 | 
				
			||||||
 | 
						MinCompatibilityVersion() *version.Version
 | 
				
			||||||
 | 
						EqualTo(other EffectiveVersion) bool
 | 
				
			||||||
 | 
						String() string
 | 
				
			||||||
 | 
						Validate() []error
 | 
				
			||||||
 | 
						// AllowedEmulationVersionRange returns the string of the allowed range of emulation version.
 | 
				
			||||||
 | 
						// Used only for docs/help.
 | 
				
			||||||
 | 
						AllowedEmulationVersionRange() string
 | 
				
			||||||
 | 
						// AllowedMinCompatibilityVersionRange returns the string of the allowed range of min compatibility version.
 | 
				
			||||||
 | 
						// Used only for docs/help.
 | 
				
			||||||
 | 
						AllowedMinCompatibilityVersionRange() string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MutableEffectiveVersion interface {
 | 
				
			||||||
 | 
						EffectiveVersion
 | 
				
			||||||
 | 
						SetEmulationVersion(emulationVersion *version.Version)
 | 
				
			||||||
 | 
						SetMinCompatibilityVersion(minCompatibilityVersion *version.Version)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type effectiveVersion struct {
 | 
				
			||||||
 | 
						// When true, BinaryVersion() returns the current binary version
 | 
				
			||||||
 | 
						useDefaultBuildBinaryVersion atomic.Bool
 | 
				
			||||||
 | 
						// Holds the last binary version stored in Set()
 | 
				
			||||||
 | 
						binaryVersion atomic.Pointer[version.Version]
 | 
				
			||||||
 | 
						// If the emulationVersion is set by the users, it could only contain major and minor versions.
 | 
				
			||||||
 | 
						// In tests, emulationVersion could be the same as the binary version, or set directly,
 | 
				
			||||||
 | 
						// which can have "alpha" as pre-release to continue serving expired apis while we clean up the test.
 | 
				
			||||||
 | 
						emulationVersion atomic.Pointer[version.Version]
 | 
				
			||||||
 | 
						// minCompatibilityVersion could only contain major and minor versions.
 | 
				
			||||||
 | 
						minCompatibilityVersion atomic.Pointer[version.Version]
 | 
				
			||||||
 | 
						// emulationVersionFloor is the minimum emulationVersion allowed. No limit if nil.
 | 
				
			||||||
 | 
						emulationVersionFloor *version.Version
 | 
				
			||||||
 | 
						// minCompatibilityVersionFloor is the minimum minCompatibilityVersionFloor allowed. No limit if nil.
 | 
				
			||||||
 | 
						minCompatibilityVersionFloor *version.Version
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *effectiveVersion) BinaryVersion() *version.Version {
 | 
				
			||||||
 | 
						if m.useDefaultBuildBinaryVersion.Load() {
 | 
				
			||||||
 | 
							return defaultBuildBinaryVersion()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return m.binaryVersion.Load()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *effectiveVersion) EmulationVersion() *version.Version {
 | 
				
			||||||
 | 
						ver := m.emulationVersion.Load()
 | 
				
			||||||
 | 
						if ver != nil {
 | 
				
			||||||
 | 
							// Emulation version can have "alpha" as pre-release to continue serving expired apis while we clean up the test.
 | 
				
			||||||
 | 
							// The pre-release should not be accessible to the users.
 | 
				
			||||||
 | 
							return ver.WithPreRelease(m.BinaryVersion().PreRelease())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ver
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *effectiveVersion) MinCompatibilityVersion() *version.Version {
 | 
				
			||||||
 | 
						return m.minCompatibilityVersion.Load()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *effectiveVersion) EqualTo(other EffectiveVersion) bool {
 | 
				
			||||||
 | 
						return m.BinaryVersion().EqualTo(other.BinaryVersion()) && m.EmulationVersion().EqualTo(other.EmulationVersion()) && m.MinCompatibilityVersion().EqualTo(other.MinCompatibilityVersion())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *effectiveVersion) String() string {
 | 
				
			||||||
 | 
						if m == nil {
 | 
				
			||||||
 | 
							return "<nil>"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return fmt.Sprintf("{BinaryVersion: %s, EmulationVersion: %s, MinCompatibilityVersion: %s}",
 | 
				
			||||||
 | 
							m.BinaryVersion().String(), m.EmulationVersion().String(), m.MinCompatibilityVersion().String())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func majorMinor(ver *version.Version) *version.Version {
 | 
				
			||||||
 | 
						if ver == nil {
 | 
				
			||||||
 | 
							return ver
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return version.MajorMinor(ver.Major(), ver.Minor())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *effectiveVersion) SetEmulationVersion(emulationVersion *version.Version) {
 | 
				
			||||||
 | 
						m.emulationVersion.Store(majorMinor(emulationVersion))
 | 
				
			||||||
 | 
						// set the default minCompatibilityVersion to be emulationVersion - 1 if possible
 | 
				
			||||||
 | 
						minCompatibilityVersion := majorMinor(emulationVersion.SubtractMinor(1))
 | 
				
			||||||
 | 
						if minCompatibilityVersion.LessThan(m.minCompatibilityVersionFloor) {
 | 
				
			||||||
 | 
							minCompatibilityVersion = m.minCompatibilityVersionFloor
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						m.minCompatibilityVersion.Store(minCompatibilityVersion)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetMinCompatibilityVersion should be called after SetEmulationVersion
 | 
				
			||||||
 | 
					func (m *effectiveVersion) SetMinCompatibilityVersion(minCompatibilityVersion *version.Version) {
 | 
				
			||||||
 | 
						m.minCompatibilityVersion.Store(majorMinor(minCompatibilityVersion))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *effectiveVersion) AllowedEmulationVersionRange() string {
 | 
				
			||||||
 | 
						binaryVersion := m.BinaryVersion()
 | 
				
			||||||
 | 
						if binaryVersion == nil {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Consider patch version to be 0.
 | 
				
			||||||
 | 
						binaryVersion = version.MajorMinor(binaryVersion.Major(), binaryVersion.Minor())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						floor := m.emulationVersionFloor
 | 
				
			||||||
 | 
						if floor == nil {
 | 
				
			||||||
 | 
							floor = version.MajorMinor(0, 0)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return fmt.Sprintf("%s..%s (default=%s)", floor.String(), binaryVersion.String(), m.EmulationVersion().String())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *effectiveVersion) AllowedMinCompatibilityVersionRange() string {
 | 
				
			||||||
 | 
						binaryVersion := m.BinaryVersion()
 | 
				
			||||||
 | 
						if binaryVersion == nil {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Consider patch version to be 0.
 | 
				
			||||||
 | 
						binaryVersion = version.MajorMinor(binaryVersion.Major(), binaryVersion.Minor())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						floor := m.minCompatibilityVersionFloor
 | 
				
			||||||
 | 
						if floor == nil {
 | 
				
			||||||
 | 
							floor = version.MajorMinor(0, 0)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return fmt.Sprintf("%s..%s (default=%s)", floor.String(), binaryVersion.String(), m.MinCompatibilityVersion().String())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *effectiveVersion) Validate() []error {
 | 
				
			||||||
 | 
						var errs []error
 | 
				
			||||||
 | 
						// Validate only checks the major and minor versions.
 | 
				
			||||||
 | 
						binaryVersion := m.BinaryVersion().WithPatch(0)
 | 
				
			||||||
 | 
						emulationVersion := m.emulationVersion.Load()
 | 
				
			||||||
 | 
						minCompatibilityVersion := m.minCompatibilityVersion.Load()
 | 
				
			||||||
 | 
						// emulationVersion can only be between emulationVersionFloor and binaryVersion
 | 
				
			||||||
 | 
						if emulationVersion.GreaterThan(binaryVersion) || emulationVersion.LessThan(m.emulationVersionFloor) {
 | 
				
			||||||
 | 
							errs = append(errs, fmt.Errorf("emulation version %s is not between [%s, %s]", emulationVersion.String(), m.emulationVersionFloor.String(), binaryVersion.String()))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// minCompatibilityVersion can only be between minCompatibilityVersionFloor and emulationVersion
 | 
				
			||||||
 | 
						if minCompatibilityVersion.GreaterThan(emulationVersion) || minCompatibilityVersion.LessThan(m.minCompatibilityVersionFloor) {
 | 
				
			||||||
 | 
							errs = append(errs, fmt.Errorf("minCompatibilityVersion version %s is not between [%s, %s]", minCompatibilityVersion.String(), m.minCompatibilityVersionFloor.String(), emulationVersion.String()))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return errs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewEffectiveVersion creates a MutableEffectiveVersion from the binaryVersion.
 | 
				
			||||||
 | 
					// If useDefaultBuildBinaryVersion is true, the call of BinaryVersion() will always return the current binary version.
 | 
				
			||||||
 | 
					// NewEffectiveVersion(binaryVersion, true) should only be used if the binary version is dynamic.
 | 
				
			||||||
 | 
					// Otherwise, use NewEffectiveVersion(binaryVersion, false) or NewEffectiveVersionFromString.
 | 
				
			||||||
 | 
					func NewEffectiveVersion(binaryVersion *version.Version, useDefaultBuildBinaryVersion bool, emulationVersionFloor, minCompatibilityVersionFloor *version.Version) MutableEffectiveVersion {
 | 
				
			||||||
 | 
						effective := &effectiveVersion{
 | 
				
			||||||
 | 
							emulationVersionFloor:        emulationVersionFloor,
 | 
				
			||||||
 | 
							minCompatibilityVersionFloor: minCompatibilityVersionFloor,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						compatVersion := binaryVersion.SubtractMinor(1)
 | 
				
			||||||
 | 
						effective.binaryVersion.Store(binaryVersion)
 | 
				
			||||||
 | 
						effective.useDefaultBuildBinaryVersion.Store(useDefaultBuildBinaryVersion)
 | 
				
			||||||
 | 
						effective.SetEmulationVersion(binaryVersion)
 | 
				
			||||||
 | 
						effective.SetMinCompatibilityVersion(compatVersion)
 | 
				
			||||||
 | 
						return effective
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewEffectiveVersionFromString creates a MutableEffectiveVersion from the binaryVersion string.
 | 
				
			||||||
 | 
					func NewEffectiveVersionFromString(binaryVer, emulationVerFloor, minCompatibilityVerFloor string) MutableEffectiveVersion {
 | 
				
			||||||
 | 
						if binaryVer == "" {
 | 
				
			||||||
 | 
							return &effectiveVersion{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						binaryVersion := version.MustParse(binaryVer)
 | 
				
			||||||
 | 
						emulationVersionFloor := version.MajorMinor(0, 0)
 | 
				
			||||||
 | 
						if emulationVerFloor != "" {
 | 
				
			||||||
 | 
							emulationVersionFloor = version.MustParse(emulationVerFloor)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						minCompatibilityVersionFloor := version.MajorMinor(0, 0)
 | 
				
			||||||
 | 
						if minCompatibilityVerFloor != "" {
 | 
				
			||||||
 | 
							minCompatibilityVersionFloor = version.MustParse(minCompatibilityVerFloor)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NewEffectiveVersion(binaryVersion, false, emulationVersionFloor, minCompatibilityVersionFloor)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func defaultBuildBinaryVersion() *version.Version {
 | 
				
			||||||
 | 
						verInfo := baseversion.Get()
 | 
				
			||||||
 | 
						return version.MustParse(verInfo.String()).WithInfo(verInfo)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										148
									
								
								staging/src/k8s.io/component-base/compatibility/version_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								staging/src/k8s.io/component-base/compatibility/version_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2024 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestValidate(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							name                         string
 | 
				
			||||||
 | 
							binaryVersion                string
 | 
				
			||||||
 | 
							emulationVersion             string
 | 
				
			||||||
 | 
							minCompatibilityVersion      string
 | 
				
			||||||
 | 
							emulationVersionFloor        string
 | 
				
			||||||
 | 
							minCompatibilityVersionFloor string
 | 
				
			||||||
 | 
							expectErrors                 bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                    "patch version diff ok",
 | 
				
			||||||
 | 
								binaryVersion:           "v1.32.1",
 | 
				
			||||||
 | 
								emulationVersion:        "v1.32.2",
 | 
				
			||||||
 | 
								minCompatibilityVersion: "v1.32.5",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                    "emulation version greater than binary not ok",
 | 
				
			||||||
 | 
								binaryVersion:           "v1.32.2",
 | 
				
			||||||
 | 
								emulationVersion:        "v1.33.0",
 | 
				
			||||||
 | 
								minCompatibilityVersion: "v1.31.0",
 | 
				
			||||||
 | 
								expectErrors:            true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                    "min compatibility version greater than emulation version not ok",
 | 
				
			||||||
 | 
								binaryVersion:           "v1.32.2",
 | 
				
			||||||
 | 
								emulationVersion:        "v1.31.0",
 | 
				
			||||||
 | 
								minCompatibilityVersion: "v1.32.0",
 | 
				
			||||||
 | 
								expectErrors:            true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                         "between floor and binary ok",
 | 
				
			||||||
 | 
								binaryVersion:                "v1.32.1",
 | 
				
			||||||
 | 
								emulationVersion:             "v1.31.0",
 | 
				
			||||||
 | 
								minCompatibilityVersion:      "v1.30.0",
 | 
				
			||||||
 | 
								emulationVersionFloor:        "v1.31.0",
 | 
				
			||||||
 | 
								minCompatibilityVersionFloor: "v1.30.0",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                         "emulation version less than floor not ok",
 | 
				
			||||||
 | 
								binaryVersion:                "v1.32.1",
 | 
				
			||||||
 | 
								emulationVersion:             "v1.30.0",
 | 
				
			||||||
 | 
								minCompatibilityVersion:      "v1.30.0",
 | 
				
			||||||
 | 
								emulationVersionFloor:        "v1.31.0",
 | 
				
			||||||
 | 
								minCompatibilityVersionFloor: "v1.30.0",
 | 
				
			||||||
 | 
								expectErrors:                 true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                         "min compatibility version less than floor not ok",
 | 
				
			||||||
 | 
								binaryVersion:                "v1.32.1",
 | 
				
			||||||
 | 
								emulationVersion:             "v1.31.0",
 | 
				
			||||||
 | 
								minCompatibilityVersion:      "v1.29.0",
 | 
				
			||||||
 | 
								emulationVersionFloor:        "v1.31.0",
 | 
				
			||||||
 | 
								minCompatibilityVersionFloor: "v1.30.0",
 | 
				
			||||||
 | 
								expectErrors:                 true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							t.Run(test.name, func(t *testing.T) {
 | 
				
			||||||
 | 
								effective := NewEffectiveVersionFromString(test.binaryVersion, test.emulationVersionFloor, test.minCompatibilityVersionFloor)
 | 
				
			||||||
 | 
								emulationVersion := version.MustParseGeneric(test.emulationVersion)
 | 
				
			||||||
 | 
								minCompatibilityVersion := version.MustParseGeneric(test.minCompatibilityVersion)
 | 
				
			||||||
 | 
								effective.SetEmulationVersion(emulationVersion)
 | 
				
			||||||
 | 
								effective.SetMinCompatibilityVersion(minCompatibilityVersion)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								errs := effective.Validate()
 | 
				
			||||||
 | 
								if len(errs) > 0 && !test.expectErrors {
 | 
				
			||||||
 | 
									t.Errorf("expected no errors, errors found %+v", errs)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if len(errs) == 0 && test.expectErrors {
 | 
				
			||||||
 | 
									t.Errorf("expected errors, no errors found")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSetEmulationVersion(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							name                          string
 | 
				
			||||||
 | 
							binaryVersion                 string
 | 
				
			||||||
 | 
							emulationVersion              string
 | 
				
			||||||
 | 
							expectMinCompatibilityVersion string
 | 
				
			||||||
 | 
							emulationVersionFloor         string
 | 
				
			||||||
 | 
							minCompatibilityVersionFloor  string
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                          "minCompatibilityVersion default to 1 minor less than emulationVersion",
 | 
				
			||||||
 | 
								binaryVersion:                 "v1.34",
 | 
				
			||||||
 | 
								emulationVersion:              "v1.32",
 | 
				
			||||||
 | 
								expectMinCompatibilityVersion: "v1.31",
 | 
				
			||||||
 | 
								emulationVersionFloor:         "v1.31",
 | 
				
			||||||
 | 
								minCompatibilityVersionFloor:  "v1.31",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:                          "minCompatibilityVersion default to emulationVersion when hitting the floor",
 | 
				
			||||||
 | 
								binaryVersion:                 "v1.34",
 | 
				
			||||||
 | 
								emulationVersion:              "v1.31",
 | 
				
			||||||
 | 
								expectMinCompatibilityVersion: "v1.31",
 | 
				
			||||||
 | 
								emulationVersionFloor:         "v1.31",
 | 
				
			||||||
 | 
								minCompatibilityVersionFloor:  "v1.31",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							t.Run(test.name, func(t *testing.T) {
 | 
				
			||||||
 | 
								effective := NewEffectiveVersionFromString(test.binaryVersion, test.emulationVersionFloor, test.minCompatibilityVersionFloor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								emulationVersion := version.MustParseGeneric(test.emulationVersion)
 | 
				
			||||||
 | 
								effective.SetEmulationVersion(emulationVersion)
 | 
				
			||||||
 | 
								errs := effective.Validate()
 | 
				
			||||||
 | 
								if len(errs) > 0 {
 | 
				
			||||||
 | 
									t.Fatalf("expected no Validate errors, errors found %+v", errs)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								expectMinCompatibilityVersion := version.MustParseGeneric(test.expectMinCompatibilityVersion)
 | 
				
			||||||
 | 
								if !effective.MinCompatibilityVersion().EqualTo(expectMinCompatibilityVersion) {
 | 
				
			||||||
 | 
									t.Errorf("expected minCompatibilityVersion %s, got %s", expectMinCompatibilityVersion.String(), effective.MinCompatibilityVersion().String())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -19,43 +19,10 @@ package version
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"sync/atomic"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
					 | 
				
			||||||
	apimachineryversion "k8s.io/apimachinery/pkg/version"
 | 
						apimachineryversion "k8s.io/apimachinery/pkg/version"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var minimumKubeEmulationVersion *version.Version = version.MajorMinor(1, 31)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type EffectiveVersion interface {
 | 
					 | 
				
			||||||
	BinaryVersion() *version.Version
 | 
					 | 
				
			||||||
	EmulationVersion() *version.Version
 | 
					 | 
				
			||||||
	MinCompatibilityVersion() *version.Version
 | 
					 | 
				
			||||||
	EqualTo(other EffectiveVersion) bool
 | 
					 | 
				
			||||||
	String() string
 | 
					 | 
				
			||||||
	Validate() []error
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type MutableEffectiveVersion interface {
 | 
					 | 
				
			||||||
	EffectiveVersion
 | 
					 | 
				
			||||||
	Set(binaryVersion, emulationVersion, minCompatibilityVersion *version.Version)
 | 
					 | 
				
			||||||
	SetEmulationVersion(emulationVersion *version.Version)
 | 
					 | 
				
			||||||
	SetMinCompatibilityVersion(minCompatibilityVersion *version.Version)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type effectiveVersion struct {
 | 
					 | 
				
			||||||
	// When true, BinaryVersion() returns the current binary version
 | 
					 | 
				
			||||||
	useDefaultBuildBinaryVersion atomic.Bool
 | 
					 | 
				
			||||||
	// Holds the last binary version stored in Set()
 | 
					 | 
				
			||||||
	binaryVersion atomic.Pointer[version.Version]
 | 
					 | 
				
			||||||
	// If the emulationVersion is set by the users, it could only contain major and minor versions.
 | 
					 | 
				
			||||||
	// In tests, emulationVersion could be the same as the binary version, or set directly,
 | 
					 | 
				
			||||||
	// which can have "alpha" as pre-release to continue serving expired apis while we clean up the test.
 | 
					 | 
				
			||||||
	emulationVersion atomic.Pointer[version.Version]
 | 
					 | 
				
			||||||
	// minCompatibilityVersion could only contain major and minor versions.
 | 
					 | 
				
			||||||
	minCompatibilityVersion atomic.Pointer[version.Version]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Get returns the overall codebase version. It's for detecting
 | 
					// Get returns the overall codebase version. It's for detecting
 | 
				
			||||||
// what code a binary was built from.
 | 
					// what code a binary was built from.
 | 
				
			||||||
func Get() apimachineryversion.Info {
 | 
					func Get() apimachineryversion.Info {
 | 
				
			||||||
@@ -73,134 +40,3 @@ func Get() apimachineryversion.Info {
 | 
				
			|||||||
		Platform:     fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
 | 
							Platform:     fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func (m *effectiveVersion) BinaryVersion() *version.Version {
 | 
					 | 
				
			||||||
	if m.useDefaultBuildBinaryVersion.Load() {
 | 
					 | 
				
			||||||
		return defaultBuildBinaryVersion()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return m.binaryVersion.Load()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (m *effectiveVersion) EmulationVersion() *version.Version {
 | 
					 | 
				
			||||||
	ver := m.emulationVersion.Load()
 | 
					 | 
				
			||||||
	if ver != nil {
 | 
					 | 
				
			||||||
		// Emulation version can have "alpha" as pre-release to continue serving expired apis while we clean up the test.
 | 
					 | 
				
			||||||
		// The pre-release should not be accessible to the users.
 | 
					 | 
				
			||||||
		return ver.WithPreRelease(m.BinaryVersion().PreRelease())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ver
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (m *effectiveVersion) MinCompatibilityVersion() *version.Version {
 | 
					 | 
				
			||||||
	return m.minCompatibilityVersion.Load()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (m *effectiveVersion) EqualTo(other EffectiveVersion) bool {
 | 
					 | 
				
			||||||
	return m.BinaryVersion().EqualTo(other.BinaryVersion()) && m.EmulationVersion().EqualTo(other.EmulationVersion()) && m.MinCompatibilityVersion().EqualTo(other.MinCompatibilityVersion())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (m *effectiveVersion) String() string {
 | 
					 | 
				
			||||||
	if m == nil {
 | 
					 | 
				
			||||||
		return "<nil>"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return fmt.Sprintf("{BinaryVersion: %s, EmulationVersion: %s, MinCompatibilityVersion: %s}",
 | 
					 | 
				
			||||||
		m.BinaryVersion().String(), m.EmulationVersion().String(), m.MinCompatibilityVersion().String())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func majorMinor(ver *version.Version) *version.Version {
 | 
					 | 
				
			||||||
	if ver == nil {
 | 
					 | 
				
			||||||
		return ver
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return version.MajorMinor(ver.Major(), ver.Minor())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (m *effectiveVersion) Set(binaryVersion, emulationVersion, minCompatibilityVersion *version.Version) {
 | 
					 | 
				
			||||||
	m.binaryVersion.Store(binaryVersion)
 | 
					 | 
				
			||||||
	m.useDefaultBuildBinaryVersion.Store(false)
 | 
					 | 
				
			||||||
	m.emulationVersion.Store(majorMinor(emulationVersion))
 | 
					 | 
				
			||||||
	m.minCompatibilityVersion.Store(majorMinor(minCompatibilityVersion))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (m *effectiveVersion) SetEmulationVersion(emulationVersion *version.Version) {
 | 
					 | 
				
			||||||
	m.emulationVersion.Store(majorMinor(emulationVersion))
 | 
					 | 
				
			||||||
	// set the default minCompatibilityVersion to be emulationVersion - 1
 | 
					 | 
				
			||||||
	m.minCompatibilityVersion.Store(majorMinor(emulationVersion.SubtractMinor(1)))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// SetMinCompatibilityVersion should be called after SetEmulationVersion
 | 
					 | 
				
			||||||
func (m *effectiveVersion) SetMinCompatibilityVersion(minCompatibilityVersion *version.Version) {
 | 
					 | 
				
			||||||
	m.minCompatibilityVersion.Store(majorMinor(minCompatibilityVersion))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (m *effectiveVersion) Validate() []error {
 | 
					 | 
				
			||||||
	var errs []error
 | 
					 | 
				
			||||||
	// Validate only checks the major and minor versions.
 | 
					 | 
				
			||||||
	binaryVersion := m.BinaryVersion().WithPatch(0)
 | 
					 | 
				
			||||||
	emulationVersion := m.emulationVersion.Load()
 | 
					 | 
				
			||||||
	minCompatibilityVersion := m.minCompatibilityVersion.Load()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// emulationVersion can only be 1.{binaryMinor-3}...1.{binaryMinor}
 | 
					 | 
				
			||||||
	maxEmuVer := binaryVersion
 | 
					 | 
				
			||||||
	minEmuVer := binaryVersion.SubtractMinor(3)
 | 
					 | 
				
			||||||
	if emulationVersion.GreaterThan(maxEmuVer) || emulationVersion.LessThan(minEmuVer) {
 | 
					 | 
				
			||||||
		errs = append(errs, fmt.Errorf("emulation version %s is not between [%s, %s]", emulationVersion.String(), minEmuVer.String(), maxEmuVer.String()))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// minCompatibilityVersion can only be 1.{binaryMinor-3} to 1.{binaryMinor}
 | 
					 | 
				
			||||||
	maxCompVer := emulationVersion
 | 
					 | 
				
			||||||
	minCompVer := binaryVersion.SubtractMinor(4)
 | 
					 | 
				
			||||||
	if minCompatibilityVersion.GreaterThan(maxCompVer) || minCompatibilityVersion.LessThan(minCompVer) {
 | 
					 | 
				
			||||||
		errs = append(errs, fmt.Errorf("minCompatibilityVersion version %s is not between [%s, %s]", minCompatibilityVersion.String(), minCompVer.String(), maxCompVer.String()))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return errs
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newEffectiveVersion(binaryVersion *version.Version, useDefaultBuildBinaryVersion bool) MutableEffectiveVersion {
 | 
					 | 
				
			||||||
	effective := &effectiveVersion{}
 | 
					 | 
				
			||||||
	compatVersion := binaryVersion.SubtractMinor(1)
 | 
					 | 
				
			||||||
	effective.Set(binaryVersion, binaryVersion, compatVersion)
 | 
					 | 
				
			||||||
	effective.useDefaultBuildBinaryVersion.Store(useDefaultBuildBinaryVersion)
 | 
					 | 
				
			||||||
	return effective
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewEffectiveVersion(binaryVer string) MutableEffectiveVersion {
 | 
					 | 
				
			||||||
	if binaryVer == "" {
 | 
					 | 
				
			||||||
		return &effectiveVersion{}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	binaryVersion := version.MustParse(binaryVer)
 | 
					 | 
				
			||||||
	return newEffectiveVersion(binaryVersion, false)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func defaultBuildBinaryVersion() *version.Version {
 | 
					 | 
				
			||||||
	verInfo := Get()
 | 
					 | 
				
			||||||
	return version.MustParse(verInfo.String()).WithInfo(verInfo)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// DefaultBuildEffectiveVersion returns the MutableEffectiveVersion based on the
 | 
					 | 
				
			||||||
// current build information.
 | 
					 | 
				
			||||||
func DefaultBuildEffectiveVersion() MutableEffectiveVersion {
 | 
					 | 
				
			||||||
	binaryVersion := defaultBuildBinaryVersion()
 | 
					 | 
				
			||||||
	if binaryVersion.Major() == 0 && binaryVersion.Minor() == 0 {
 | 
					 | 
				
			||||||
		return DefaultKubeEffectiveVersion()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return newEffectiveVersion(binaryVersion, true)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// DefaultKubeEffectiveVersion returns the MutableEffectiveVersion based on the
 | 
					 | 
				
			||||||
// latest K8s release.
 | 
					 | 
				
			||||||
func DefaultKubeEffectiveVersion() MutableEffectiveVersion {
 | 
					 | 
				
			||||||
	binaryVersion := version.MustParse(DefaultKubeBinaryVersion).WithInfo(Get())
 | 
					 | 
				
			||||||
	return newEffectiveVersion(binaryVersion, false)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ValidateKubeEffectiveVersion validates the EmulationVersion is at least 1.31 and MinCompatibilityVersion
 | 
					 | 
				
			||||||
// is at least 1.30 for kube components.
 | 
					 | 
				
			||||||
func ValidateKubeEffectiveVersion(effectiveVersion EffectiveVersion) error {
 | 
					 | 
				
			||||||
	if !effectiveVersion.EmulationVersion().AtLeast(minimumKubeEmulationVersion) {
 | 
					 | 
				
			||||||
		return fmt.Errorf("emulation version needs to be greater or equal to 1.31, got %s", effectiveVersion.EmulationVersion().String())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !effectiveVersion.MinCompatibilityVersion().AtLeast(minimumKubeEmulationVersion.SubtractMinor(1)) {
 | 
					 | 
				
			||||||
		return fmt.Errorf("minCompatibilityVersion version needs to be greater or equal to 1.30, got %s", effectiveVersion.MinCompatibilityVersion().String())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,185 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
Copyright 2024 The Kubernetes Authors.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
					 | 
				
			||||||
you may not use this file except in compliance with the License.
 | 
					 | 
				
			||||||
You may obtain a copy of the License at
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Unless required by applicable law or agreed to in writing, software
 | 
					 | 
				
			||||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
					 | 
				
			||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					 | 
				
			||||||
See the License for the specific language governing permissions and
 | 
					 | 
				
			||||||
limitations under the License.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package version
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestValidate(t *testing.T) {
 | 
					 | 
				
			||||||
	tests := []struct {
 | 
					 | 
				
			||||||
		name                    string
 | 
					 | 
				
			||||||
		binaryVersion           string
 | 
					 | 
				
			||||||
		emulationVersion        string
 | 
					 | 
				
			||||||
		minCompatibilityVersion string
 | 
					 | 
				
			||||||
		expectErrors            bool
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "patch version diff ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.32.2",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.32.1",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.31.5",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "emulation version one minor lower than binary ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.32.2",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.31.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.31.0",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "emulation version two minor lower than binary ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.33.2",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.31.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.31.0",
 | 
					 | 
				
			||||||
			expectErrors:            false,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "emulation version three minor lower than binary ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.35.0",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.32.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.32.0",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "emulation version four minor lower than binary not ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.36.0",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.32.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.32.0",
 | 
					 | 
				
			||||||
			expectErrors:            true,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "emulation version one minor higher than binary not ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.32.2",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.33.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.31.0",
 | 
					 | 
				
			||||||
			expectErrors:            true,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "emulation version two minor higher than binary not ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.32.2",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.34.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.31.0",
 | 
					 | 
				
			||||||
			expectErrors:            true,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "compatibility version same as binary ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.32.2",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.32.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.32.0",
 | 
					 | 
				
			||||||
			expectErrors:            false,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "compatibility version two minor lower than binary ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.32.2",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.32.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.30.0",
 | 
					 | 
				
			||||||
			expectErrors:            false,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "compatibility version three minor lower than binary ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.34.2",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.33.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.31.0",
 | 
					 | 
				
			||||||
			expectErrors:            false,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "compatibility version one minor higher than binary not ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.32.2",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.32.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.33.0",
 | 
					 | 
				
			||||||
			expectErrors:            true,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "emulation version lower than compatibility version not ok",
 | 
					 | 
				
			||||||
			binaryVersion:           "v1.34.2",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.32.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.33.0",
 | 
					 | 
				
			||||||
			expectErrors:            true,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, test := range tests {
 | 
					 | 
				
			||||||
		t.Run(test.name, func(t *testing.T) {
 | 
					 | 
				
			||||||
			binaryVersion := version.MustParseGeneric(test.binaryVersion)
 | 
					 | 
				
			||||||
			effective := &effectiveVersion{}
 | 
					 | 
				
			||||||
			emulationVersion := version.MustParseGeneric(test.emulationVersion)
 | 
					 | 
				
			||||||
			minCompatibilityVersion := version.MustParseGeneric(test.minCompatibilityVersion)
 | 
					 | 
				
			||||||
			effective.Set(binaryVersion, emulationVersion, minCompatibilityVersion)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			errs := effective.Validate()
 | 
					 | 
				
			||||||
			if len(errs) > 0 && !test.expectErrors {
 | 
					 | 
				
			||||||
				t.Errorf("expected no errors, errors found %+v", errs)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if len(errs) == 0 && test.expectErrors {
 | 
					 | 
				
			||||||
				t.Errorf("expected errors, no errors found")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestValidateKubeEffectiveVersion(t *testing.T) {
 | 
					 | 
				
			||||||
	tests := []struct {
 | 
					 | 
				
			||||||
		name                    string
 | 
					 | 
				
			||||||
		emulationVersion        string
 | 
					 | 
				
			||||||
		minCompatibilityVersion string
 | 
					 | 
				
			||||||
		expectErr               bool
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "valid versions",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.31.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.31.0",
 | 
					 | 
				
			||||||
			expectErr:               false,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "emulationVersion too low",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.30.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.31.0",
 | 
					 | 
				
			||||||
			expectErr:               true,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "minCompatibilityVersion too low",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.31.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.29.0",
 | 
					 | 
				
			||||||
			expectErr:               true,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			name:                    "both versions too low",
 | 
					 | 
				
			||||||
			emulationVersion:        "v1.30.0",
 | 
					 | 
				
			||||||
			minCompatibilityVersion: "v1.30.0",
 | 
					 | 
				
			||||||
			expectErr:               true,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, test := range tests {
 | 
					 | 
				
			||||||
		t.Run(test.name, func(t *testing.T) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			effective := NewEffectiveVersion("1.32")
 | 
					 | 
				
			||||||
			effective.SetEmulationVersion(version.MustParseGeneric(test.emulationVersion))
 | 
					 | 
				
			||||||
			effective.SetMinCompatibilityVersion(version.MustParseGeneric(test.minCompatibilityVersion))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			err := ValidateKubeEffectiveVersion(effective)
 | 
					 | 
				
			||||||
			if test.expectErr && err == nil {
 | 
					 | 
				
			||||||
				t.Error("expected error, but got nil")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if !test.expectErr && err != nil {
 | 
					 | 
				
			||||||
				t.Errorf("unexpected error: %v", err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -20,9 +20,9 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
					 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/component-base/compatibility"
 | 
				
			||||||
	compbasemetrics "k8s.io/component-base/metrics"
 | 
						compbasemetrics "k8s.io/component-base/metrics"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
						utilversion "k8s.io/component-base/version"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -34,9 +34,12 @@ type statuszRegistry interface {
 | 
				
			|||||||
	emulationVersion() *version.Version
 | 
						emulationVersion() *version.Version
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type registry struct{}
 | 
					type registry struct {
 | 
				
			||||||
 | 
						// componentGlobalsRegistry compatibility.ComponentGlobalsRegistry
 | 
				
			||||||
 | 
						effectiveVersion compatibility.EffectiveVersion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (registry) processStartTime() time.Time {
 | 
					func (*registry) processStartTime() time.Time {
 | 
				
			||||||
	start, err := compbasemetrics.GetProcessStart()
 | 
						start, err := compbasemetrics.GetProcessStart()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		klog.Errorf("Could not get process start time, %v", err)
 | 
							klog.Errorf("Could not get process start time, %v", err)
 | 
				
			||||||
@@ -45,23 +48,20 @@ func (registry) processStartTime() time.Time {
 | 
				
			|||||||
	return time.Unix(int64(start), 0)
 | 
						return time.Unix(int64(start), 0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (registry) goVersion() string {
 | 
					func (*registry) goVersion() string {
 | 
				
			||||||
	return utilversion.Get().GoVersion
 | 
						return utilversion.Get().GoVersion
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (registry) binaryVersion() *version.Version {
 | 
					func (r *registry) binaryVersion() *version.Version {
 | 
				
			||||||
	effectiveVer := featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent)
 | 
						if r.effectiveVersion != nil {
 | 
				
			||||||
	if effectiveVer != nil {
 | 
							return r.effectiveVersion.BinaryVersion()
 | 
				
			||||||
		return effectiveVer.BinaryVersion()
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return version.MustParse(utilversion.Get().String())
 | 
				
			||||||
	return utilversion.DefaultKubeEffectiveVersion().BinaryVersion()
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (registry) emulationVersion() *version.Version {
 | 
					func (r *registry) emulationVersion() *version.Version {
 | 
				
			||||||
	effectiveVer := featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(featuregate.DefaultKubeComponent)
 | 
						if r.effectiveVersion != nil {
 | 
				
			||||||
	if effectiveVer != nil {
 | 
							return r.effectiveVersion.EmulationVersion()
 | 
				
			||||||
		return effectiveVer.EmulationVersion()
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,14 +20,12 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/compatibility"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
						utilversion "k8s.io/component-base/version"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBinaryVersion(t *testing.T) {
 | 
					func TestBinaryVersion(t *testing.T) {
 | 
				
			||||||
	componentGlobalsRegistry := featuregate.DefaultComponentGlobalsRegistry
 | 
					 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		name                    string
 | 
							name                    string
 | 
				
			||||||
		setFakeEffectiveVersion bool
 | 
							setFakeEffectiveVersion bool
 | 
				
			||||||
@@ -42,20 +40,18 @@ func TestBinaryVersion(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name:              "binaryVersion without effective version",
 | 
								name:              "binaryVersion without effective version",
 | 
				
			||||||
			wantBinaryVersion: utilversion.DefaultKubeEffectiveVersion().BinaryVersion(),
 | 
								wantBinaryVersion: version.MustParse(utilversion.Get().String()),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, tt := range tests {
 | 
						for _, tt := range tests {
 | 
				
			||||||
		componentGlobalsRegistry.Reset()
 | 
					 | 
				
			||||||
		t.Run(tt.name, func(t *testing.T) {
 | 
							t.Run(tt.name, func(t *testing.T) {
 | 
				
			||||||
 | 
								registry := ®istry{}
 | 
				
			||||||
			if tt.setFakeEffectiveVersion {
 | 
								if tt.setFakeEffectiveVersion {
 | 
				
			||||||
				verKube := utilversion.NewEffectiveVersion(tt.fakeVersion)
 | 
									verKube := compatibility.NewEffectiveVersionFromString(tt.fakeVersion, "", "")
 | 
				
			||||||
				fg := featuregate.NewVersionedFeatureGate(version.MustParse(tt.fakeVersion))
 | 
									registry.effectiveVersion = verKube
 | 
				
			||||||
				utilruntime.Must(componentGlobalsRegistry.Register(featuregate.DefaultKubeComponent, verKube, fg))
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			registry := ®istry{}
 | 
					 | 
				
			||||||
			got := registry.binaryVersion()
 | 
								got := registry.binaryVersion()
 | 
				
			||||||
			assert.Equal(t, tt.wantBinaryVersion, got)
 | 
								assert.Equal(t, tt.wantBinaryVersion, got)
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
@@ -63,7 +59,6 @@ func TestBinaryVersion(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestEmulationVersion(t *testing.T) {
 | 
					func TestEmulationVersion(t *testing.T) {
 | 
				
			||||||
	componentGlobalsRegistry := featuregate.DefaultComponentGlobalsRegistry
 | 
					 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		name                    string
 | 
							name                    string
 | 
				
			||||||
		setFakeEffectiveVersion bool
 | 
							setFakeEffectiveVersion bool
 | 
				
			||||||
@@ -83,16 +78,14 @@ func TestEmulationVersion(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, tt := range tests {
 | 
						for _, tt := range tests {
 | 
				
			||||||
		componentGlobalsRegistry.Reset()
 | 
					 | 
				
			||||||
		t.Run(tt.name, func(t *testing.T) {
 | 
							t.Run(tt.name, func(t *testing.T) {
 | 
				
			||||||
 | 
								registry := ®istry{}
 | 
				
			||||||
			if tt.setFakeEffectiveVersion {
 | 
								if tt.setFakeEffectiveVersion {
 | 
				
			||||||
				verKube := utilversion.NewEffectiveVersion("0.0.0")
 | 
									verKube := compatibility.NewEffectiveVersionFromString("0.0.0", "", "")
 | 
				
			||||||
				verKube.SetEmulationVersion(version.MustParse(tt.fakeEmulVer))
 | 
									verKube.SetEmulationVersion(version.MustParse(tt.fakeEmulVer))
 | 
				
			||||||
				fg := featuregate.NewVersionedFeatureGate(version.MustParse(tt.fakeEmulVer))
 | 
									registry.effectiveVersion = verKube
 | 
				
			||||||
				utilruntime.Must(componentGlobalsRegistry.Register(featuregate.DefaultKubeComponent, verKube, fg))
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			registry := ®istry{}
 | 
					 | 
				
			||||||
			got := registry.emulationVersion()
 | 
								got := registry.emulationVersion()
 | 
				
			||||||
			if tt.wantEmul != nil && got != nil {
 | 
								if tt.wantEmul != nil && got != nil {
 | 
				
			||||||
				assert.Equal(t, tt.wantEmul.Major(), got.Major())
 | 
									assert.Equal(t, tt.wantEmul.Major(), got.Major())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/zpages/httputil"
 | 
						"k8s.io/component-base/zpages/httputil"
 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -62,8 +63,8 @@ type mux interface {
 | 
				
			|||||||
	Handle(path string, handler http.Handler)
 | 
						Handle(path string, handler http.Handler)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewRegistry() statuszRegistry {
 | 
					func NewRegistry(effectiveVersion compatibility.EffectiveVersion) statuszRegistry {
 | 
				
			||||||
	return registry{}
 | 
						return ®istry{effectiveVersion: effectiveVersion}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Install(m mux, componentName string, reg statuszRegistry) {
 | 
					func Install(m mux, componentName string, reg statuszRegistry) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,6 @@ require (
 | 
				
			|||||||
	github.com/google/gofuzz v1.2.0 // indirect
 | 
						github.com/google/gofuzz v1.2.0 // indirect
 | 
				
			||||||
	github.com/google/uuid v1.6.0 // indirect
 | 
						github.com/google/uuid v1.6.0 // indirect
 | 
				
			||||||
	github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
 | 
						github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
 | 
				
			||||||
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 | 
					 | 
				
			||||||
	github.com/josharian/intern v1.0.0 // indirect
 | 
						github.com/josharian/intern v1.0.0 // indirect
 | 
				
			||||||
	github.com/json-iterator/go v1.1.12 // indirect
 | 
						github.com/json-iterator/go v1.1.12 // indirect
 | 
				
			||||||
	github.com/mailru/easyjson v0.7.7 // indirect
 | 
						github.com/mailru/easyjson v0.7.7 // indirect
 | 
				
			||||||
@@ -57,7 +56,6 @@ require (
 | 
				
			|||||||
	github.com/prometheus/client_model v0.6.1 // indirect
 | 
						github.com/prometheus/client_model v0.6.1 // indirect
 | 
				
			||||||
	github.com/prometheus/common v0.55.0 // indirect
 | 
						github.com/prometheus/common v0.55.0 // indirect
 | 
				
			||||||
	github.com/prometheus/procfs v0.15.1 // indirect
 | 
						github.com/prometheus/procfs v0.15.1 // indirect
 | 
				
			||||||
	github.com/spf13/cobra v1.8.1 // indirect
 | 
					 | 
				
			||||||
	github.com/spf13/pflag v1.0.5 // indirect
 | 
						github.com/spf13/pflag v1.0.5 // indirect
 | 
				
			||||||
	github.com/x448/float16 v0.8.4 // indirect
 | 
						github.com/x448/float16 v0.8.4 // indirect
 | 
				
			||||||
	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
 | 
						go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								staging/src/k8s.io/cri-client/go.sum
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								staging/src/k8s.io/cri-client/go.sum
									
									
									
										generated
									
									
									
								
							@@ -18,7 +18,6 @@ github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91
 | 
				
			|||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 | 
					github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 | 
				
			||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 | 
					github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 | 
				
			||||||
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
 | 
					github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
 | 
				
			||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 | 
					 | 
				
			||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 | 
					github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
					github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
				
			||||||
@@ -70,7 +69,6 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
 | 
				
			|||||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 | 
					github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 | 
				
			||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
 | 
					github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
 | 
				
			||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
 | 
					github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
 | 
				
			||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 | 
					 | 
				
			||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 | 
					github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 | 
				
			||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 | 
					github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 | 
				
			||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 | 
					github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 | 
				
			||||||
@@ -117,9 +115,7 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG
 | 
				
			|||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 | 
					github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 | 
				
			||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 | 
					github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 | 
				
			||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
 | 
					github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
 | 
				
			||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 | 
					 | 
				
			||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 | 
					github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 | 
				
			||||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
 | 
					 | 
				
			||||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
 | 
					github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
 | 
				
			||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 | 
					github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 | 
				
			||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 | 
					github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,6 @@ import (
 | 
				
			|||||||
	genericapiserver "k8s.io/apiserver/pkg/server"
 | 
						genericapiserver "k8s.io/apiserver/pkg/server"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/server/filters"
 | 
						"k8s.io/apiserver/pkg/server/filters"
 | 
				
			||||||
	genericoptions "k8s.io/apiserver/pkg/server/options"
 | 
						genericoptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
					 | 
				
			||||||
	"k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1"
 | 
						"k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1"
 | 
				
			||||||
	"k8s.io/kube-aggregator/pkg/apiserver"
 | 
						"k8s.io/kube-aggregator/pkg/apiserver"
 | 
				
			||||||
	aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
 | 
						aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
 | 
				
			||||||
@@ -63,7 +62,7 @@ func NewCommandStartAggregator(ctx context.Context, defaults *AggregatorOptions)
 | 
				
			|||||||
		Short: "Launch a API aggregator and proxy server",
 | 
							Short: "Launch a API aggregator and proxy server",
 | 
				
			||||||
		Long:  "Launch a API aggregator and proxy server",
 | 
							Long:  "Launch a API aggregator and proxy server",
 | 
				
			||||||
		PersistentPreRunE: func(*cobra.Command, []string) error {
 | 
							PersistentPreRunE: func(*cobra.Command, []string) error {
 | 
				
			||||||
			return featuregate.DefaultComponentGlobalsRegistry.Set()
 | 
								return o.ServerRunOptions.ComponentGlobalsRegistry.Set()
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		RunE: func(c *cobra.Command, args []string) error {
 | 
							RunE: func(c *cobra.Command, args []string) error {
 | 
				
			||||||
			if err := o.Complete(); err != nil {
 | 
								if err := o.Complete(); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,9 +33,11 @@ import (
 | 
				
			|||||||
	"k8s.io/apiserver/pkg/endpoints/openapi"
 | 
						"k8s.io/apiserver/pkg/endpoints/openapi"
 | 
				
			||||||
	genericapiserver "k8s.io/apiserver/pkg/server"
 | 
						genericapiserver "k8s.io/apiserver/pkg/server"
 | 
				
			||||||
	genericoptions "k8s.io/apiserver/pkg/server/options"
 | 
						genericoptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
						baseversion "k8s.io/component-base/version"
 | 
				
			||||||
	"k8s.io/sample-apiserver/pkg/admission/plugin/banflunder"
 | 
						"k8s.io/sample-apiserver/pkg/admission/plugin/banflunder"
 | 
				
			||||||
	"k8s.io/sample-apiserver/pkg/admission/wardleinitializer"
 | 
						"k8s.io/sample-apiserver/pkg/admission/wardleinitializer"
 | 
				
			||||||
	"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1"
 | 
						"k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1"
 | 
				
			||||||
@@ -51,6 +53,8 @@ const defaultEtcdPathPrefix = "/registry/wardle.example.com"
 | 
				
			|||||||
// WardleServerOptions contains state for master/api server
 | 
					// WardleServerOptions contains state for master/api server
 | 
				
			||||||
type WardleServerOptions struct {
 | 
					type WardleServerOptions struct {
 | 
				
			||||||
	RecommendedOptions *genericoptions.RecommendedOptions
 | 
						RecommendedOptions *genericoptions.RecommendedOptions
 | 
				
			||||||
 | 
						// ComponentGlobalsRegistry is the registry where the effective versions and feature gates for all components are stored.
 | 
				
			||||||
 | 
						ComponentGlobalsRegistry basecompatibility.ComponentGlobalsRegistry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SharedInformerFactory informers.SharedInformerFactory
 | 
						SharedInformerFactory informers.SharedInformerFactory
 | 
				
			||||||
	StdOut                io.Writer
 | 
						StdOut                io.Writer
 | 
				
			||||||
@@ -63,7 +67,7 @@ func WardleVersionToKubeVersion(ver *version.Version) *version.Version {
 | 
				
			|||||||
	if ver.Major() != 1 {
 | 
						if ver.Major() != 1 {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	kubeVer := utilversion.DefaultKubeEffectiveVersion().BinaryVersion()
 | 
						kubeVer := version.MustParse(baseversion.DefaultKubeBinaryVersion)
 | 
				
			||||||
	// "1.2" maps to kubeVer
 | 
						// "1.2" maps to kubeVer
 | 
				
			||||||
	offset := int(ver.Minor()) - 2
 | 
						offset := int(ver.Minor()) - 2
 | 
				
			||||||
	mappedVer := kubeVer.OffsetMinor(offset)
 | 
						mappedVer := kubeVer.OffsetMinor(offset)
 | 
				
			||||||
@@ -80,6 +84,7 @@ func NewWardleServerOptions(out, errOut io.Writer) *WardleServerOptions {
 | 
				
			|||||||
			defaultEtcdPathPrefix,
 | 
								defaultEtcdPathPrefix,
 | 
				
			||||||
			apiserver.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion),
 | 
								apiserver.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion),
 | 
				
			||||||
		),
 | 
							),
 | 
				
			||||||
 | 
							ComponentGlobalsRegistry: compatibility.DefaultComponentGlobalsRegistry,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		StdOut: out,
 | 
							StdOut: out,
 | 
				
			||||||
		StdErr: errOut,
 | 
							StdErr: errOut,
 | 
				
			||||||
@@ -99,7 +104,7 @@ func NewCommandStartWardleServer(ctx context.Context, defaults *WardleServerOpti
 | 
				
			|||||||
			if skipDefaultComponentGlobalsRegistrySet {
 | 
								if skipDefaultComponentGlobalsRegistrySet {
 | 
				
			||||||
				return nil
 | 
									return nil
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return featuregate.DefaultComponentGlobalsRegistry.Set()
 | 
								return defaults.ComponentGlobalsRegistry.Set()
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		RunE: func(c *cobra.Command, args []string) error {
 | 
							RunE: func(c *cobra.Command, args []string) error {
 | 
				
			||||||
			if err := o.Complete(); err != nil {
 | 
								if err := o.Complete(); err != nil {
 | 
				
			||||||
@@ -135,8 +140,8 @@ func NewCommandStartWardleServer(ctx context.Context, defaults *WardleServerOpti
 | 
				
			|||||||
	// Register the "Wardle" component with the global component registry,
 | 
						// Register the "Wardle" component with the global component registry,
 | 
				
			||||||
	// associating it with its effective version and feature gate configuration.
 | 
						// associating it with its effective version and feature gate configuration.
 | 
				
			||||||
	// Will skip if the component has been registered, like in the integration test.
 | 
						// Will skip if the component has been registered, like in the integration test.
 | 
				
			||||||
	_, wardleFeatureGate := featuregate.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister(
 | 
						_, wardleFeatureGate := defaults.ComponentGlobalsRegistry.ComponentGlobalsOrRegister(
 | 
				
			||||||
		apiserver.WardleComponentName, utilversion.NewEffectiveVersion(defaultWardleVersion),
 | 
							apiserver.WardleComponentName, basecompatibility.NewEffectiveVersionFromString(defaultWardleVersion, "", ""),
 | 
				
			||||||
		featuregate.NewVersionedFeatureGate(version.MustParse(defaultWardleVersion)))
 | 
							featuregate.NewVersionedFeatureGate(version.MustParse(defaultWardleVersion)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Add versioned feature specifications for the "BanFlunder" feature.
 | 
						// Add versioned feature specifications for the "BanFlunder" feature.
 | 
				
			||||||
@@ -150,14 +155,14 @@ func NewCommandStartWardleServer(ctx context.Context, defaults *WardleServerOpti
 | 
				
			|||||||
	}))
 | 
						}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Register the default kube component if not already present in the global registry.
 | 
						// Register the default kube component if not already present in the global registry.
 | 
				
			||||||
	_, _ = featuregate.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister(featuregate.DefaultKubeComponent,
 | 
						_, _ = defaults.ComponentGlobalsRegistry.ComponentGlobalsOrRegister(basecompatibility.DefaultKubeComponent,
 | 
				
			||||||
		utilversion.NewEffectiveVersion(utilversion.DefaultKubeBinaryVersion), utilfeature.DefaultMutableFeatureGate)
 | 
							basecompatibility.NewEffectiveVersionFromString(baseversion.DefaultKubeBinaryVersion, "", ""), utilfeature.DefaultMutableFeatureGate)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set the emulation version mapping from the "Wardle" component to the kube component.
 | 
						// Set the emulation version mapping from the "Wardle" component to the kube component.
 | 
				
			||||||
	// This ensures that the emulation version of the latter is determined by the emulation version of the former.
 | 
						// This ensures that the emulation version of the latter is determined by the emulation version of the former.
 | 
				
			||||||
	utilruntime.Must(featuregate.DefaultComponentGlobalsRegistry.SetEmulationVersionMapping(apiserver.WardleComponentName, featuregate.DefaultKubeComponent, WardleVersionToKubeVersion))
 | 
						utilruntime.Must(defaults.ComponentGlobalsRegistry.SetEmulationVersionMapping(apiserver.WardleComponentName, basecompatibility.DefaultKubeComponent, WardleVersionToKubeVersion))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	featuregate.DefaultComponentGlobalsRegistry.AddFlags(flags)
 | 
						defaults.ComponentGlobalsRegistry.AddFlags(flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cmd
 | 
						return cmd
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -166,13 +171,13 @@ func NewCommandStartWardleServer(ctx context.Context, defaults *WardleServerOpti
 | 
				
			|||||||
func (o WardleServerOptions) Validate(args []string) error {
 | 
					func (o WardleServerOptions) Validate(args []string) error {
 | 
				
			||||||
	errors := []error{}
 | 
						errors := []error{}
 | 
				
			||||||
	errors = append(errors, o.RecommendedOptions.Validate()...)
 | 
						errors = append(errors, o.RecommendedOptions.Validate()...)
 | 
				
			||||||
	errors = append(errors, featuregate.DefaultComponentGlobalsRegistry.Validate()...)
 | 
						errors = append(errors, o.ComponentGlobalsRegistry.Validate()...)
 | 
				
			||||||
	return utilerrors.NewAggregate(errors)
 | 
						return utilerrors.NewAggregate(errors)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Complete fills in fields required to have valid data
 | 
					// Complete fills in fields required to have valid data
 | 
				
			||||||
func (o *WardleServerOptions) Complete() error {
 | 
					func (o *WardleServerOptions) Complete() error {
 | 
				
			||||||
	if featuregate.DefaultComponentGlobalsRegistry.FeatureGateFor(apiserver.WardleComponentName).Enabled("BanFlunder") {
 | 
						if o.ComponentGlobalsRegistry.FeatureGateFor(apiserver.WardleComponentName).Enabled("BanFlunder") {
 | 
				
			||||||
		// register admission plugins
 | 
							// register admission plugins
 | 
				
			||||||
		banflunder.Register(o.RecommendedOptions.Admission.Plugins)
 | 
							banflunder.Register(o.RecommendedOptions.Admission.Plugins)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -209,8 +214,8 @@ func (o *WardleServerOptions) Config() (*apiserver.Config, error) {
 | 
				
			|||||||
	serverConfig.OpenAPIV3Config.Info.Title = "Wardle"
 | 
						serverConfig.OpenAPIV3Config.Info.Title = "Wardle"
 | 
				
			||||||
	serverConfig.OpenAPIV3Config.Info.Version = "0.1"
 | 
						serverConfig.OpenAPIV3Config.Info.Version = "0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	serverConfig.FeatureGate = featuregate.DefaultComponentGlobalsRegistry.FeatureGateFor(featuregate.DefaultKubeComponent)
 | 
						serverConfig.FeatureGate = o.ComponentGlobalsRegistry.FeatureGateFor(basecompatibility.DefaultKubeComponent)
 | 
				
			||||||
	serverConfig.EffectiveVersion = featuregate.DefaultComponentGlobalsRegistry.EffectiveVersionFor(apiserver.WardleComponentName)
 | 
						serverConfig.EffectiveVersion = o.ComponentGlobalsRegistry.EffectiveVersionFor(apiserver.WardleComponentName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil {
 | 
						if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,13 +20,13 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestWardleEmulationVersionToKubeEmulationVersion(t *testing.T) {
 | 
					func TestWardleEmulationVersionToKubeEmulationVersion(t *testing.T) {
 | 
				
			||||||
	defaultKubeEffectiveVersion := utilversion.DefaultKubeEffectiveVersion()
 | 
						defaultKubeEffectiveVersion := compatibility.DefaultKubeEffectiveVersionForTest()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	testCases := []struct {
 | 
						testCases := []struct {
 | 
				
			||||||
		desc                     string
 | 
							desc                     string
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,6 @@ import (
 | 
				
			|||||||
	"crypto/x509"
 | 
						"crypto/x509"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
					 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/http/httptest"
 | 
						"net/http/httptest"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
@@ -634,9 +633,9 @@ func TestMatchConditionsWithoutStrictCostEnforcement(t *testing.T) {
 | 
				
			|||||||
	for _, testcase := range testcases {
 | 
						for _, testcase := range testcases {
 | 
				
			||||||
		t.Run(testcase.name, func(t *testing.T) {
 | 
							t.Run(testcase.name, func(t *testing.T) {
 | 
				
			||||||
			upCh := recorder.Reset()
 | 
								upCh := recorder.Reset()
 | 
				
			||||||
			featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.31"))
 | 
								server, err := apiservertesting.StartTestServer(t, nil, []string{
 | 
				
			||||||
			featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.StrictCostEnforcementForWebhooks, false)
 | 
									"--emulated-version", "1.31",
 | 
				
			||||||
			server, err := apiservertesting.StartTestServer(t, &apiservertesting.TestServerInstanceOptions{EmulationVersion: "1.31"}, []string{
 | 
									"--feature-gates", "StrictCostEnforcementForWebhooks=false",
 | 
				
			||||||
				"--disable-admission-plugins=ServiceAccount",
 | 
									"--disable-admission-plugins=ServiceAccount",
 | 
				
			||||||
			}, framework.SharedEtcd())
 | 
								}, framework.SharedEtcd())
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,10 +56,12 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/types"
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	utiljson "k8s.io/apimachinery/pkg/util/json"
 | 
						utiljson "k8s.io/apimachinery/pkg/util/json"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/uuid"
 | 
						"k8s.io/apimachinery/pkg/util/uuid"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/watch"
 | 
						"k8s.io/apimachinery/pkg/watch"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/endpoints/handlers"
 | 
						"k8s.io/apiserver/pkg/endpoints/handlers"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/storage/storagebackend"
 | 
						"k8s.io/apiserver/pkg/storage/storagebackend"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	"k8s.io/client-go/discovery/cached/memory"
 | 
						"k8s.io/client-go/discovery/cached/memory"
 | 
				
			||||||
	"k8s.io/client-go/dynamic"
 | 
						"k8s.io/client-go/dynamic"
 | 
				
			||||||
@@ -70,7 +72,6 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/restmapper"
 | 
						"k8s.io/client-go/restmapper"
 | 
				
			||||||
	"k8s.io/client-go/tools/pager"
 | 
						"k8s.io/client-go/tools/pager"
 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
						featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	"k8s.io/klog/v2"
 | 
						"k8s.io/klog/v2"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
 | 
						"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
 | 
				
			||||||
	kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
 | 
						kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
 | 
				
			||||||
@@ -3198,8 +3199,7 @@ func TestEmulatedStorageVersion(t *testing.T) {
 | 
				
			|||||||
	for emulatedVersion, cases := range groupedCases {
 | 
						for emulatedVersion, cases := range groupedCases {
 | 
				
			||||||
		t.Run(emulatedVersion, func(t *testing.T) {
 | 
							t.Run(emulatedVersion, func(t *testing.T) {
 | 
				
			||||||
			server := kubeapiservertesting.StartTestServerOrDie(
 | 
								server := kubeapiservertesting.StartTestServerOrDie(
 | 
				
			||||||
				t, &kubeapiservertesting.TestServerInstanceOptions{BinaryVersion: emulatedVersion},
 | 
									t, nil, []string{"--emulated-version=kube=" + emulatedVersion, `--storage-media-type=application/json`}, framework.SharedEtcd())
 | 
				
			||||||
				[]string{"--emulated-version=kube=" + emulatedVersion, `--storage-media-type=application/json`}, framework.SharedEtcd())
 | 
					 | 
				
			||||||
			defer server.TearDownFn()
 | 
								defer server.TearDownFn()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			client := clientset.NewForConfigOrDie(server.ClientConfig)
 | 
								client := clientset.NewForConfigOrDie(server.ClientConfig)
 | 
				
			||||||
@@ -3302,7 +3302,7 @@ func TestAllowedEmulationVersions(t *testing.T) {
 | 
				
			|||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name:             "default",
 | 
								name:             "default",
 | 
				
			||||||
			emulationVersion: utilversion.DefaultKubeEffectiveVersion().EmulationVersion().String(),
 | 
								emulationVersion: compatibility.DefaultKubeEffectiveVersionForTest().EmulationVersion().String(),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3337,6 +3337,7 @@ func TestAllowedEmulationVersions(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestEnableEmulationVersion(t *testing.T) {
 | 
					func TestEnableEmulationVersion(t *testing.T) {
 | 
				
			||||||
 | 
						featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.32"))
 | 
				
			||||||
	server := kubeapiservertesting.StartTestServerOrDie(t,
 | 
						server := kubeapiservertesting.StartTestServerOrDie(t,
 | 
				
			||||||
		&kubeapiservertesting.TestServerInstanceOptions{BinaryVersion: "1.32"},
 | 
							&kubeapiservertesting.TestServerInstanceOptions{BinaryVersion: "1.32"},
 | 
				
			||||||
		[]string{"--emulated-version=kube=1.31"}, framework.SharedEtcd())
 | 
							[]string{"--emulated-version=kube=1.31"}, framework.SharedEtcd())
 | 
				
			||||||
@@ -3398,6 +3399,7 @@ func TestEnableEmulationVersion(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDisableEmulationVersion(t *testing.T) {
 | 
					func TestDisableEmulationVersion(t *testing.T) {
 | 
				
			||||||
 | 
						featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.32"))
 | 
				
			||||||
	server := kubeapiservertesting.StartTestServerOrDie(t,
 | 
						server := kubeapiservertesting.StartTestServerOrDie(t,
 | 
				
			||||||
		&kubeapiservertesting.TestServerInstanceOptions{BinaryVersion: "1.32"},
 | 
							&kubeapiservertesting.TestServerInstanceOptions{BinaryVersion: "1.32"},
 | 
				
			||||||
		[]string{}, framework.SharedEtcd())
 | 
							[]string{}, framework.SharedEtcd())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,6 @@ import (
 | 
				
			|||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
					 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/http/httptest"
 | 
						"net/http/httptest"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
@@ -2235,9 +2234,9 @@ func Test_CostLimitForValidation(t *testing.T) {
 | 
				
			|||||||
func Test_CostLimitForValidationWithFeatureDisabled(t *testing.T) {
 | 
					func Test_CostLimitForValidationWithFeatureDisabled(t *testing.T) {
 | 
				
			||||||
	resetPolicyRefreshInterval := generic.SetPolicyRefreshIntervalForTests(policyRefreshInterval)
 | 
						resetPolicyRefreshInterval := generic.SetPolicyRefreshIntervalForTests(policyRefreshInterval)
 | 
				
			||||||
	defer resetPolicyRefreshInterval()
 | 
						defer resetPolicyRefreshInterval()
 | 
				
			||||||
	featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.31"))
 | 
						server, err := apiservertesting.StartTestServer(t, nil, []string{
 | 
				
			||||||
	featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.StrictCostEnforcementForVAP, false)
 | 
							"--emulated-version", "1.31",
 | 
				
			||||||
	server, err := apiservertesting.StartTestServer(t, &apiservertesting.TestServerInstanceOptions{EmulationVersion: "1.31"}, []string{
 | 
							"--feature-gates", "StrictCostEnforcementForVAP=false",
 | 
				
			||||||
		"--enable-admission-plugins", "ValidatingAdmissionPolicy",
 | 
							"--enable-admission-plugins", "ValidatingAdmissionPolicy",
 | 
				
			||||||
	}, framework.SharedEtcd())
 | 
						}, framework.SharedEtcd())
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,6 +47,7 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/watch"
 | 
						"k8s.io/apimachinery/pkg/watch"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/features"
 | 
						"k8s.io/apiserver/pkg/features"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	appsv1ac "k8s.io/client-go/applyconfigurations/apps/v1"
 | 
						appsv1ac "k8s.io/client-go/applyconfigurations/apps/v1"
 | 
				
			||||||
	autoscalingv1ac "k8s.io/client-go/applyconfigurations/autoscaling/v1"
 | 
						autoscalingv1ac "k8s.io/client-go/applyconfigurations/autoscaling/v1"
 | 
				
			||||||
@@ -83,7 +84,7 @@ func TestClient(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("unexpected error: %v", err)
 | 
							t.Fatalf("unexpected error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	expectedInfo := utilversion.Get()
 | 
						expectedInfo := utilversion.Get()
 | 
				
			||||||
	kubeVersion := utilversion.DefaultKubeEffectiveVersion().BinaryVersion()
 | 
						kubeVersion := compatibility.DefaultKubeEffectiveVersionForTest().BinaryVersion()
 | 
				
			||||||
	expectedInfo.Major = fmt.Sprintf("%d", kubeVersion.Major())
 | 
						expectedInfo.Major = fmt.Sprintf("%d", kubeVersion.Major())
 | 
				
			||||||
	expectedInfo.Minor = fmt.Sprintf("%d", kubeVersion.Minor())
 | 
						expectedInfo.Minor = fmt.Sprintf("%d", kubeVersion.Minor())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,6 @@ import (
 | 
				
			|||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
					 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -117,7 +116,7 @@ func newTransformTest(tb testing.TB, transformerConfigYAML string, reload bool,
 | 
				
			|||||||
		return nil, fmt.Errorf("failed to read config file: %w", err)
 | 
							return nil, fmt.Errorf("failed to read config file: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if e.kubeAPIServer, err = startTestServerLocked(
 | 
						if e.kubeAPIServer, err = kubeapiservertesting.StartTestServer(
 | 
				
			||||||
		tb, nil,
 | 
							tb, nil,
 | 
				
			||||||
		e.getEncryptionOptions(reload), e.storageConfig); err != nil {
 | 
							e.getEncryptionOptions(reload), e.storageConfig); err != nil {
 | 
				
			||||||
		e.cleanUp()
 | 
							e.cleanUp()
 | 
				
			||||||
@@ -148,15 +147,6 @@ func newTransformTest(tb testing.TB, transformerConfigYAML string, reload bool,
 | 
				
			|||||||
	return &e, nil
 | 
						return &e, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var startTestServerLock sync.Mutex
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// startTestServerLocked prevents parallel calls to kubeapiservertesting.StartTestServer because it messes with global state.
 | 
					 | 
				
			||||||
func startTestServerLocked(t ktesting.TB, instanceOptions *kubeapiservertesting.TestServerInstanceOptions, customFlags []string, storageConfig *storagebackend.Config) (result kubeapiservertesting.TestServer, err error) {
 | 
					 | 
				
			||||||
	startTestServerLock.Lock()
 | 
					 | 
				
			||||||
	defer startTestServerLock.Unlock()
 | 
					 | 
				
			||||||
	return kubeapiservertesting.StartTestServer(t, instanceOptions, customFlags, storageConfig)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (e *transformTest) cleanUp() {
 | 
					func (e *transformTest) cleanUp() {
 | 
				
			||||||
	if e.configDir != "" {
 | 
						if e.configDir != "" {
 | 
				
			||||||
		os.RemoveAll(e.configDir)
 | 
							os.RemoveAll(e.configDir)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@ import (
 | 
				
			|||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
						"k8s.io/apimachinery/pkg/util/version"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
						utilversion "k8s.io/component-base/version"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/kubernetes/test/utils/image"
 | 
						"k8s.io/kubernetes/test/utils/image"
 | 
				
			||||||
@@ -34,9 +35,9 @@ import (
 | 
				
			|||||||
// Tests aiming for full coverage of versions should test fixtures of all supported versions.
 | 
					// Tests aiming for full coverage of versions should test fixtures of all supported versions.
 | 
				
			||||||
func GetSupportedEmulatedVersions() []string {
 | 
					func GetSupportedEmulatedVersions() []string {
 | 
				
			||||||
	return []string{
 | 
						return []string{
 | 
				
			||||||
		utilversion.DefaultKubeEffectiveVersion().BinaryVersion().SubtractMinor(2).String(),
 | 
							compatibility.DefaultKubeEffectiveVersionForTest().BinaryVersion().SubtractMinor(2).String(),
 | 
				
			||||||
		utilversion.DefaultKubeEffectiveVersion().BinaryVersion().SubtractMinor(1).String(),
 | 
							compatibility.DefaultKubeEffectiveVersionForTest().BinaryVersion().SubtractMinor(1).String(),
 | 
				
			||||||
		utilversion.DefaultKubeEffectiveVersion().BinaryVersion().String(),
 | 
							compatibility.DefaultKubeEffectiveVersionForTest().BinaryVersion().String(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -104,7 +104,6 @@ func testEtcdStoragePathWithVersion(t *testing.T, v string) {
 | 
				
			|||||||
		// only understand v1beta1.
 | 
							// only understand v1beta1.
 | 
				
			||||||
		featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.MultiCIDRServiceAllocator, false)
 | 
							featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.MultiCIDRServiceAllocator, false)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	registerEffectiveEmulationVersion(t)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apiServer := StartRealAPIServerOrDie(t, func(opts *options.ServerRunOptions) {
 | 
						apiServer := StartRealAPIServerOrDie(t, func(opts *options.ServerRunOptions) {
 | 
				
			||||||
		// Disable alphas when emulating previous versions.
 | 
							// Disable alphas when emulating previous versions.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,9 +36,9 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
 | 
						utilerrors "k8s.io/apimachinery/pkg/util/errors"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/json"
 | 
						"k8s.io/apimachinery/pkg/util/json"
 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
						genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/util/feature"
 | 
						"k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	cacheddiscovery "k8s.io/client-go/discovery/cached/memory"
 | 
						cacheddiscovery "k8s.io/client-go/discovery/cached/memory"
 | 
				
			||||||
	"k8s.io/client-go/dynamic"
 | 
						"k8s.io/client-go/dynamic"
 | 
				
			||||||
@@ -46,9 +46,8 @@ import (
 | 
				
			|||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
	"k8s.io/client-go/restmapper"
 | 
						"k8s.io/client-go/restmapper"
 | 
				
			||||||
	utiltesting "k8s.io/client-go/util/testing"
 | 
						utiltesting "k8s.io/client-go/util/testing"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
						featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kube-apiserver/app"
 | 
						"k8s.io/kubernetes/cmd/kube-apiserver/app"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
 | 
						"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
 | 
				
			||||||
	"k8s.io/kubernetes/test/integration"
 | 
						"k8s.io/kubernetes/test/integration"
 | 
				
			||||||
@@ -67,17 +66,6 @@ AwEHoUQDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPLX2i8uIp/C/ASqiIGUeeKQtX0
 | 
				
			|||||||
/IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg==
 | 
					/IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg==
 | 
				
			||||||
-----END EC PRIVATE KEY-----`
 | 
					-----END EC PRIVATE KEY-----`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func registerEffectiveEmulationVersion(t *testing.T) {
 | 
					 | 
				
			||||||
	featureGate := feature.DefaultMutableFeatureGate
 | 
					 | 
				
			||||||
	featureGate.AddMetrics()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	effectiveVersion := utilversion.DefaultKubeEffectiveVersion()
 | 
					 | 
				
			||||||
	effectiveVersion.SetEmulationVersion(featureGate.EmulationVersion())
 | 
					 | 
				
			||||||
	featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, featureGate, effectiveVersion.EmulationVersion())
 | 
					 | 
				
			||||||
	featuregate.DefaultComponentGlobalsRegistry.Reset()
 | 
					 | 
				
			||||||
	utilruntime.Must(featuregate.DefaultComponentGlobalsRegistry.Register(featuregate.DefaultKubeComponent, effectiveVersion, featureGate))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// StartRealAPIServerOrDie starts an API server that is appropriate for use in tests that require one of every resource
 | 
					// StartRealAPIServerOrDie starts an API server that is appropriate for use in tests that require one of every resource
 | 
				
			||||||
func StartRealAPIServerOrDie(t *testing.T, configFuncs ...func(*options.ServerRunOptions)) *APIServer {
 | 
					func StartRealAPIServerOrDie(t *testing.T, configFuncs ...func(*options.ServerRunOptions)) *APIServer {
 | 
				
			||||||
	tCtx := ktesting.Init(t)
 | 
						tCtx := ktesting.Init(t)
 | 
				
			||||||
@@ -108,6 +96,17 @@ func StartRealAPIServerOrDie(t *testing.T, configFuncs ...func(*options.ServerRu
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts := options.NewServerRunOptions()
 | 
						opts := options.NewServerRunOptions()
 | 
				
			||||||
 | 
						// If EmulationVersion of DefaultFeatureGate is set during test, we need to propagate it to the apiserver ComponentGlobalsRegistry.
 | 
				
			||||||
 | 
						featureGate := feature.DefaultMutableFeatureGate.DeepCopy()
 | 
				
			||||||
 | 
						effectiveVersion := compatibility.DefaultKubeEffectiveVersionForTest()
 | 
				
			||||||
 | 
						effectiveVersion.SetEmulationVersion(featureGate.EmulationVersion())
 | 
				
			||||||
 | 
						// set up new instance of ComponentGlobalsRegistry instead of using the DefaultComponentGlobalsRegistry to avoid contention in parallel tests.
 | 
				
			||||||
 | 
						componentGlobalsRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
 | 
						if err := componentGlobalsRegistry.Register(basecompatibility.DefaultKubeComponent, effectiveVersion, featureGate); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						opts.GenericServerRunOptions.ComponentGlobalsRegistry = componentGlobalsRegistry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts.Options.SecureServing.Listener = listener
 | 
						opts.Options.SecureServing.Listener = listener
 | 
				
			||||||
	opts.Options.SecureServing.ServerCert.CertDirectory = certDir
 | 
						opts.Options.SecureServing.ServerCert.CertDirectory = certDir
 | 
				
			||||||
	opts.Options.ServiceAccountSigningKeyFile = saSigningKeyFile.Name()
 | 
						opts.Options.ServiceAccountSigningKeyFile = saSigningKeyFile.Name()
 | 
				
			||||||
@@ -123,6 +122,19 @@ func StartRealAPIServerOrDie(t *testing.T, configFuncs ...func(*options.ServerRu
 | 
				
			|||||||
	for _, f := range configFuncs {
 | 
						for _, f := range configFuncs {
 | 
				
			||||||
		f(opts)
 | 
							f(opts)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If the local ComponentGlobalsRegistry is changed by configFuncs,
 | 
				
			||||||
 | 
						// we need to copy the new feature values back to the DefaultFeatureGate because most feature checks still use the DefaultFeatureGate.
 | 
				
			||||||
 | 
						if !featureGate.EmulationVersion().EqualTo(feature.DefaultMutableFeatureGate.EmulationVersion()) {
 | 
				
			||||||
 | 
							featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, feature.DefaultMutableFeatureGate, effectiveVersion.EmulationVersion())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for f := range feature.DefaultMutableFeatureGate.GetAll() {
 | 
				
			||||||
 | 
							if featureGate.Enabled(f) != feature.DefaultFeatureGate.Enabled(f) {
 | 
				
			||||||
 | 
								featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, f, featureGate.Enabled(f))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						feature.DefaultMutableFeatureGate.AddMetrics()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	completedOptions, err := opts.Complete(tCtx)
 | 
						completedOptions, err := opts.Complete(tCtx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,9 +55,9 @@ import (
 | 
				
			|||||||
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
 | 
						clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
 | 
				
			||||||
	"k8s.io/client-go/transport"
 | 
						"k8s.io/client-go/transport"
 | 
				
			||||||
	"k8s.io/client-go/util/cert"
 | 
						"k8s.io/client-go/util/cert"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
						"k8s.io/component-base/featuregate"
 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
						featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
				
			||||||
	utilversion "k8s.io/component-base/version"
 | 
					 | 
				
			||||||
	apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
 | 
						apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
 | 
				
			||||||
	aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
 | 
						aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kube-apiserver/app"
 | 
						"k8s.io/kubernetes/cmd/kube-apiserver/app"
 | 
				
			||||||
@@ -282,11 +282,8 @@ func testFrontProxyConfig(t *testing.T, withUID bool) {
 | 
				
			|||||||
		extraKASFlags = []string{"--requestheader-uid-headers=x-remote-uid"}
 | 
							extraKASFlags = []string{"--requestheader-uid-headers=x-remote-uid"}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// each wardle binary is bundled with a specific kube binary.
 | 
					 | 
				
			||||||
	kubeBinaryVersion := sampleserver.WardleVersionToKubeVersion(version.MustParse(wardleBinaryVersion)).String()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// start up the KAS and prepare the options for the wardle API server
 | 
						// start up the KAS and prepare the options for the wardle API server
 | 
				
			||||||
	testKAS, wardleOptions, wardlePort := prepareAggregatedWardleAPIServer(ctx, t, testNamespace, kubeBinaryVersion, wardleBinaryVersion, extraKASFlags, withUID)
 | 
						testKAS, wardleOptions, wardlePort := prepareAggregatedWardleAPIServer(ctx, t, testNamespace, wardleBinaryVersion, extraKASFlags, withUID)
 | 
				
			||||||
	kubeConfig := getKubeConfig(testKAS)
 | 
						kubeConfig := getKubeConfig(testKAS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// create the SA that we will use to query the aggregated API
 | 
						// create the SA that we will use to query the aggregated API
 | 
				
			||||||
@@ -402,10 +399,7 @@ func testAggregatedAPIServer(t *testing.T, setWardleFeatureGate, banFlunder bool
 | 
				
			|||||||
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
 | 
						ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
 | 
				
			||||||
	t.Cleanup(cancel)
 | 
						t.Cleanup(cancel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// each wardle binary is bundled with a specific kube binary.
 | 
						testKAS, wardleOptions, wardlePort := prepareAggregatedWardleAPIServer(ctx, t, testNamespace, wardleBinaryVersion, nil, false)
 | 
				
			||||||
	kubeBinaryVersion := sampleserver.WardleVersionToKubeVersion(version.MustParse(wardleBinaryVersion)).String()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	testKAS, wardleOptions, wardlePort := prepareAggregatedWardleAPIServer(ctx, t, testNamespace, kubeBinaryVersion, wardleBinaryVersion, nil, false)
 | 
					 | 
				
			||||||
	kubeClientConfig := getKubeConfig(testKAS)
 | 
						kubeClientConfig := getKubeConfig(testKAS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wardleCertDir, _ := os.MkdirTemp("", "test-integration-wardle-server")
 | 
						wardleCertDir, _ := os.MkdirTemp("", "test-integration-wardle-server")
 | 
				
			||||||
@@ -685,7 +679,7 @@ func TestAggregatedAPIServerRejectRedirectResponse(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func prepareAggregatedWardleAPIServer(ctx context.Context, t *testing.T, namespace, kubebinaryVersion, wardleBinaryVersion string, kubeAPIServerFlags []string, withUID bool) (*kastesting.TestServer, *sampleserver.WardleServerOptions, int) {
 | 
					func prepareAggregatedWardleAPIServer(ctx context.Context, t *testing.T, namespace, wardleBinaryVersion string, kubeAPIServerFlags []string, withUID bool) (*kastesting.TestServer, *sampleserver.WardleServerOptions, int) {
 | 
				
			||||||
	// makes the kube-apiserver very responsive.  it's normally a minute
 | 
						// makes the kube-apiserver very responsive.  it's normally a minute
 | 
				
			||||||
	dynamiccertificates.FileRefreshDuration = 1 * time.Second
 | 
						dynamiccertificates.FileRefreshDuration = 1 * time.Second
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -697,22 +691,17 @@ func prepareAggregatedWardleAPIServer(ctx context.Context, t *testing.T, namespa
 | 
				
			|||||||
	// endpoints cannot have loopback IPs so we need to override the resolver itself
 | 
						// endpoints cannot have loopback IPs so we need to override the resolver itself
 | 
				
			||||||
	t.Cleanup(app.SetServiceResolverForTests(staticURLServiceResolver(fmt.Sprintf("https://127.0.0.1:%d", wardlePort))))
 | 
						t.Cleanup(app.SetServiceResolverForTests(staticURLServiceResolver(fmt.Sprintf("https://127.0.0.1:%d", wardlePort))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO figure out how to actually make BinaryVersion/EmulationVersion work with Wardle and KAS at the same time when Alpha FG are being set
 | 
					 | 
				
			||||||
	if withUID {
 | 
					 | 
				
			||||||
		kubebinaryVersion = ""
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	testServer := kastesting.StartTestServerOrDie(t,
 | 
						testServer := kastesting.StartTestServerOrDie(t,
 | 
				
			||||||
		&kastesting.TestServerInstanceOptions{
 | 
							&kastesting.TestServerInstanceOptions{
 | 
				
			||||||
			EnableCertAuth: true,
 | 
								EnableCertAuth: true,
 | 
				
			||||||
			BinaryVersion:  kubebinaryVersion,
 | 
					 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		kubeAPIServerFlags,
 | 
							kubeAPIServerFlags,
 | 
				
			||||||
		framework.SharedEtcd())
 | 
							framework.SharedEtcd())
 | 
				
			||||||
	t.Cleanup(func() { testServer.TearDownFn() })
 | 
						t.Cleanup(func() { testServer.TearDownFn() })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, _ = featuregate.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister(
 | 
						componentGlobalsRegistry := testServer.ServerOpts.Options.GenericServerRunOptions.ComponentGlobalsRegistry
 | 
				
			||||||
		apiserver.WardleComponentName, utilversion.NewEffectiveVersion(wardleBinaryVersion),
 | 
						_, _ = componentGlobalsRegistry.ComponentGlobalsOrRegister(
 | 
				
			||||||
 | 
							apiserver.WardleComponentName, basecompatibility.NewEffectiveVersionFromString(wardleBinaryVersion, "", ""),
 | 
				
			||||||
		featuregate.NewVersionedFeatureGate(version.MustParse(wardleBinaryVersion)))
 | 
							featuregate.NewVersionedFeatureGate(version.MustParse(wardleBinaryVersion)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kubeClient := client.NewForConfigOrDie(getKubeConfig(testServer))
 | 
						kubeClient := client.NewForConfigOrDie(getKubeConfig(testServer))
 | 
				
			||||||
@@ -740,6 +729,7 @@ func prepareAggregatedWardleAPIServer(ctx context.Context, t *testing.T, namespa
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wardleOptions := sampleserver.NewWardleServerOptions(os.Stdout, os.Stderr)
 | 
						wardleOptions := sampleserver.NewWardleServerOptions(os.Stdout, os.Stderr)
 | 
				
			||||||
 | 
						wardleOptions.ComponentGlobalsRegistry = componentGlobalsRegistry
 | 
				
			||||||
	// ensure this is a SAN on the generated cert for service FQDN
 | 
						// ensure this is a SAN on the generated cert for service FQDN
 | 
				
			||||||
	wardleOptions.AlternateDNS = []string{
 | 
						wardleOptions.AlternateDNS = []string{
 | 
				
			||||||
		fmt.Sprintf("api.%s.svc", namespace),
 | 
							fmt.Sprintf("api.%s.svc", namespace),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,9 +35,13 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	genericapiserver "k8s.io/apiserver/pkg/server"
 | 
						genericapiserver "k8s.io/apiserver/pkg/server"
 | 
				
			||||||
	genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
						genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
 | 
				
			||||||
 | 
						"k8s.io/apiserver/pkg/util/compatibility"
 | 
				
			||||||
 | 
						utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
				
			||||||
	client "k8s.io/client-go/kubernetes"
 | 
						client "k8s.io/client-go/kubernetes"
 | 
				
			||||||
	"k8s.io/client-go/rest"
 | 
						"k8s.io/client-go/rest"
 | 
				
			||||||
	"k8s.io/client-go/util/cert"
 | 
						"k8s.io/client-go/util/cert"
 | 
				
			||||||
 | 
						basecompatibility "k8s.io/component-base/compatibility"
 | 
				
			||||||
 | 
						featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
				
			||||||
	aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
 | 
						aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
 | 
				
			||||||
	netutils "k8s.io/utils/net"
 | 
						netutils "k8s.io/utils/net"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -136,6 +140,17 @@ func StartTestServer(ctx context.Context, t testing.TB, setup TestServerSetup) (
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts := options.NewServerRunOptions()
 | 
						opts := options.NewServerRunOptions()
 | 
				
			||||||
 | 
						// If EmulationVersion of DefaultFeatureGate is set during test, we need to propagate it to the apiserver ComponentGlobalsRegistry.
 | 
				
			||||||
 | 
						featureGate := utilfeature.DefaultMutableFeatureGate.DeepCopy()
 | 
				
			||||||
 | 
						effectiveVersion := compatibility.DefaultKubeEffectiveVersionForTest()
 | 
				
			||||||
 | 
						effectiveVersion.SetEmulationVersion(featureGate.EmulationVersion())
 | 
				
			||||||
 | 
						// set up new instance of ComponentGlobalsRegistry instead of using the DefaultComponentGlobalsRegistry to avoid contention in parallel tests.
 | 
				
			||||||
 | 
						componentGlobalsRegistry := basecompatibility.NewComponentGlobalsRegistry()
 | 
				
			||||||
 | 
						if err := componentGlobalsRegistry.Register(basecompatibility.DefaultKubeComponent, effectiveVersion, featureGate); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						opts.GenericServerRunOptions.ComponentGlobalsRegistry = componentGlobalsRegistry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts.SecureServing.Listener = listener
 | 
						opts.SecureServing.Listener = listener
 | 
				
			||||||
	opts.SecureServing.BindAddress = netutils.ParseIPSloppy("127.0.0.1")
 | 
						opts.SecureServing.BindAddress = netutils.ParseIPSloppy("127.0.0.1")
 | 
				
			||||||
	opts.SecureServing.ServerCert.CertDirectory = certDir
 | 
						opts.SecureServing.ServerCert.CertDirectory = certDir
 | 
				
			||||||
@@ -158,6 +173,18 @@ func StartTestServer(ctx context.Context, t testing.TB, setup TestServerSetup) (
 | 
				
			|||||||
		setup.ModifyServerRunOptions(opts)
 | 
							setup.ModifyServerRunOptions(opts)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If the local ComponentGlobalsRegistry is changed by ModifyServerRunOptions,
 | 
				
			||||||
 | 
						// we need to copy the new feature values back to the DefaultFeatureGate because most feature checks still use the DefaultFeatureGate.
 | 
				
			||||||
 | 
						if !featureGate.EmulationVersion().EqualTo(utilfeature.DefaultMutableFeatureGate.EmulationVersion()) {
 | 
				
			||||||
 | 
							featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultMutableFeatureGate, effectiveVersion.EmulationVersion())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for f := range utilfeature.DefaultMutableFeatureGate.GetAll() {
 | 
				
			||||||
 | 
							if featureGate.Enabled(f) != utilfeature.DefaultFeatureGate.Enabled(f) {
 | 
				
			||||||
 | 
								featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, f, featureGate.Enabled(f))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						utilfeature.DefaultMutableFeatureGate.AddMetrics()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	completedOptions, err := opts.Complete(ctx)
 | 
						completedOptions, err := opts.Complete(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1230,9 +1230,8 @@ func TestMutablePodSchedulingDirectives(t *testing.T) {
 | 
				
			|||||||
// Test disabling of RelaxedDNSSearchValidation after a Pod has been created
 | 
					// Test disabling of RelaxedDNSSearchValidation after a Pod has been created
 | 
				
			||||||
func TestRelaxedDNSSearchValidation(t *testing.T) {
 | 
					func TestRelaxedDNSSearchValidation(t *testing.T) {
 | 
				
			||||||
	// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
 | 
						// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
 | 
				
			||||||
	server := kubeapiservertesting.StartTestServerOrDie(t,
 | 
						server := kubeapiservertesting.StartTestServerOrDie(t, nil,
 | 
				
			||||||
		&kubeapiservertesting.TestServerInstanceOptions{BinaryVersion: "1.32"},
 | 
							append(framework.DefaultTestServerFlags(), "--emulated-version=1.32"), framework.SharedEtcd())
 | 
				
			||||||
		framework.DefaultTestServerFlags(), framework.SharedEtcd())
 | 
					 | 
				
			||||||
	defer server.TearDownFn()
 | 
						defer server.TearDownFn()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	client := clientset.NewForConfigOrDie(server.ClientConfig)
 | 
						client := clientset.NewForConfigOrDie(server.ClientConfig)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,7 @@ package service
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/version"
 | 
						"fmt"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,10 +34,8 @@ import (
 | 
				
			|||||||
	clientset "k8s.io/client-go/kubernetes"
 | 
						clientset "k8s.io/client-go/kubernetes"
 | 
				
			||||||
	servicecontroller "k8s.io/cloud-provider/controllers/service"
 | 
						servicecontroller "k8s.io/cloud-provider/controllers/service"
 | 
				
			||||||
	fakecloud "k8s.io/cloud-provider/fake"
 | 
						fakecloud "k8s.io/cloud-provider/fake"
 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
					 | 
				
			||||||
	controllersmetrics "k8s.io/component-base/metrics/prometheus/controllers"
 | 
						controllersmetrics "k8s.io/component-base/metrics/prometheus/controllers"
 | 
				
			||||||
	kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
 | 
						kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/test/integration/framework"
 | 
						"k8s.io/kubernetes/test/integration/framework"
 | 
				
			||||||
	"k8s.io/utils/net"
 | 
						"k8s.io/utils/net"
 | 
				
			||||||
	utilpointer "k8s.io/utils/pointer"
 | 
						utilpointer "k8s.io/utils/pointer"
 | 
				
			||||||
@@ -708,13 +706,12 @@ func Test_ServiceLoadBalancerIPMode(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, tc := range testCases {
 | 
						for _, tc := range testCases {
 | 
				
			||||||
		t.Run("", func(t *testing.T) {
 | 
							t.Run("", func(t *testing.T) {
 | 
				
			||||||
			var testServerOptions *kubeapiservertesting.TestServerInstanceOptions
 | 
								serverFlags := framework.DefaultTestServerFlags()
 | 
				
			||||||
			if !tc.ipModeEnabled {
 | 
								if !tc.ipModeEnabled {
 | 
				
			||||||
				testServerOptions = &kubeapiservertesting.TestServerInstanceOptions{EmulationVersion: "1.31"}
 | 
									serverFlags = append(serverFlags, "--emulated-version=1.31")
 | 
				
			||||||
				featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.31"))
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LoadBalancerIPMode, tc.ipModeEnabled)
 | 
								serverFlags = append(serverFlags, fmt.Sprintf("--feature-gates=LoadBalancerIPMode=%v", tc.ipModeEnabled))
 | 
				
			||||||
			server := kubeapiservertesting.StartTestServerOrDie(t, testServerOptions, framework.DefaultTestServerFlags(), framework.SharedEtcd())
 | 
								server := kubeapiservertesting.StartTestServerOrDie(t, nil, serverFlags, framework.SharedEtcd())
 | 
				
			||||||
			defer server.TearDownFn()
 | 
								defer server.TearDownFn()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			client, err := clientset.NewForConfig(server.ClientConfig)
 | 
								client, err := clientset.NewForConfig(server.ClientConfig)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user