rebase: bump the k8s-dependencies group in /e2e with 3 updates

Bumps the k8s-dependencies group in /e2e with 3 updates: [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery), [k8s.io/cloud-provider](https://github.com/kubernetes/cloud-provider) and [k8s.io/pod-security-admission](https://github.com/kubernetes/pod-security-admission).


Updates `k8s.io/apimachinery` from 0.32.3 to 0.33.0
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.32.3...v0.33.0)

Updates `k8s.io/cloud-provider` from 0.32.3 to 0.33.0
- [Commits](https://github.com/kubernetes/cloud-provider/compare/v0.32.3...v0.33.0)

Updates `k8s.io/pod-security-admission` from 0.32.3 to 0.33.0
- [Commits](https://github.com/kubernetes/pod-security-admission/compare/v0.32.3...v0.33.0)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-version: 0.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: k8s-dependencies
- dependency-name: k8s.io/cloud-provider
  dependency-version: 0.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: k8s-dependencies
- dependency-name: k8s.io/pod-security-admission
  dependency-version: 0.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: k8s-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2025-05-06 11:20:01 +00:00
committed by mergify[bot]
parent d52dc2c4ba
commit dd77e72800
359 changed files with 11145 additions and 18557 deletions

View File

@ -0,0 +1,82 @@
/*
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 flag
import (
"github.com/spf13/pflag"
)
// TrackerValue wraps a non-boolean value and stores true in the provided boolean when it is set.
type TrackerValue struct {
value pflag.Value
provided *bool
}
// BoolTrackerValue wraps a boolean value and stores true in the provided boolean when it is set.
type BoolTrackerValue struct {
boolValue
provided *bool
}
type boolValue interface {
pflag.Value
IsBoolFlag() bool
}
var _ pflag.Value = &TrackerValue{}
var _ boolValue = &BoolTrackerValue{}
// NewTracker returns a Value wrapping the given value which stores true in the provided boolean when it is set.
func NewTracker(value pflag.Value, provided *bool) pflag.Value {
if value == nil {
panic("value must not be nil")
}
if provided == nil {
panic("provided boolean must not be nil")
}
if boolValue, ok := value.(boolValue); ok {
return &BoolTrackerValue{boolValue: boolValue, provided: provided}
}
return &TrackerValue{value: value, provided: provided}
}
func (f *TrackerValue) String() string {
return f.value.String()
}
func (f *TrackerValue) Set(value string) error {
err := f.value.Set(value)
if err == nil {
*f.provided = true
}
return err
}
func (f *TrackerValue) Type() string {
return f.value.Type()
}
func (f *BoolTrackerValue) Set(value string) error {
err := f.boolValue.Set(value)
if err == nil {
*f.provided = true
}
return err
}

13
e2e/vendor/k8s.io/component-base/compatibility/OWNERS generated vendored Normal file
View File

@ -0,0 +1,13 @@
# 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
- jpbetz
reviewers:
- sig-api-machinery-api-reviewers
- siyuanfoundation
labels:
- sig/api-machinery

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package featuregate
package compatibility
import (
"fmt"
@ -26,38 +26,12 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/version"
cliflag "k8s.io/component-base/cli/flag"
baseversion "k8s.io/component-base/version"
"k8s.io/component-base/featuregate"
"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 (
// DefaultKubeComponent is the component name for k8s control plane components.
DefaultKubeComponent = "kube"
klogLevel = 2
@ -65,10 +39,10 @@ const (
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 {
effectiveVersion baseversion.MutableEffectiveVersion
featureGate MutableVersionedFeatureGate
effectiveVersion MutableEffectiveVersion
featureGate featuregate.MutableVersionedFeatureGate
// emulationVersionMapping contains the mapping from the emulation version of this component
// to the emulation version of another component.
@ -84,22 +58,24 @@ type ComponentGlobals struct {
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 {
// EffectiveVersionFor returns the EffectiveVersion registered under the component.
// 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.
// 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.
// 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.
// 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(fs *pflag.FlagSet)
// 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
// SetFallback calls Set() if it has never been called.
SetFallback() error
@ -118,10 +94,17 @@ type ComponentGlobalsRegistry interface {
type componentGlobalsRegistry struct {
componentGlobals map[string]*ComponentGlobals
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
// 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
// featureGatesConfigFlags stores a pointer to the flag value, allowing other commands
// to append to the feature gates configuration rather than overwriting it
featureGatesConfigFlags *cliflag.ColonSeparatedMultimapStringString
// set stores if the Set() function for the registry is already called.
set bool
}
@ -140,10 +123,11 @@ func (r *componentGlobalsRegistry) Reset() {
r.componentGlobals = make(map[string]*ComponentGlobals)
r.emulationVersionConfig = nil
r.featureGatesConfig = nil
r.featureGatesConfigFlags = nil
r.set = false
}
func (r *componentGlobalsRegistry) EffectiveVersionFor(component string) baseversion.EffectiveVersion {
func (r *componentGlobalsRegistry) EffectiveVersionFor(component string) EffectiveVersion {
r.mutex.RLock()
defer r.mutex.RUnlock()
globals, ok := r.componentGlobals[component]
@ -153,7 +137,7 @@ func (r *componentGlobalsRegistry) EffectiveVersionFor(component string) basever
return globals.effectiveVersion
}
func (r *componentGlobalsRegistry) FeatureGateFor(component string) FeatureGate {
func (r *componentGlobalsRegistry) FeatureGateFor(component string) featuregate.FeatureGate {
r.mutex.RLock()
defer r.mutex.RUnlock()
globals, ok := r.componentGlobals[component]
@ -163,7 +147,7 @@ func (r *componentGlobalsRegistry) FeatureGateFor(component string) 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 {
return fmt.Errorf("component globals of %s already registered", component)
}
@ -182,7 +166,7 @@ func (r *componentGlobalsRegistry) unsafeRegister(component string, effectiveVer
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 {
return fmt.Errorf("cannot register nil effectiveVersion")
}
@ -191,7 +175,7 @@ func (r *componentGlobalsRegistry) Register(component string, effectiveVersion b
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()
defer r.mutex.Unlock()
globals, ok := r.componentGlobals[component]
@ -219,22 +203,16 @@ func (r *componentGlobalsRegistry) unsafeKnownFeatures() []string {
func (r *componentGlobalsRegistry) unsafeVersionFlagOptions(isEmulation bool) []string {
var vs []string
for component, globals := range r.componentGlobals {
binaryVer := globals.effectiveVersion.BinaryVersion()
if isEmulation {
if globals.dependentEmulationVersion {
continue
}
// emulated version could be between binaryMajor.{binaryMinor} and binaryMajor.{binaryMinor}
// 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()))
vs = append(vs, fmt.Sprintf("%s=%s", component, globals.effectiveVersion.AllowedEmulationVersionRange()))
} else {
if globals.dependentMinCompatibilityVersion {
continue
}
// min compatibility version could be between binaryMajor.{binaryMinor-1} and binaryMajor.{binaryMinor}
vs = append(vs, fmt.Sprintf("%s=%s..%s (default=%s)", component,
binaryVer.SubtractMinor(1).String(), binaryVer.String(), globals.effectiveVersion.MinCompatibilityVersion().String()))
vs = append(vs, fmt.Sprintf("%s=%s", component, globals.effectiveVersion.AllowedMinCompatibilityVersionRange()))
}
}
sort.Strings(vs)
@ -252,19 +230,17 @@ func (r *componentGlobalsRegistry) AddFlags(fs *pflag.FlagSet) {
globals.featureGate.Close()
}
}
if r.emulationVersionConfig != nil || r.featureGatesConfig != nil {
klog.Warning("calling componentGlobalsRegistry.AddFlags more than once, the registry will be set by the latest flags")
}
r.emulationVersionConfig = []string{}
r.featureGatesConfig = make(map[string][]string)
fs.StringSliceVar(&r.emulationVersionConfig, "emulated-version", r.emulationVersionConfig, ""+
"The versions different components emulate their capabilities (APIs, features, ...) of.\n"+
"If set, the component will emulate the behavior of this version instead of the underlying binary version.\n"+
"Version format could only be major.minor, for example: '--emulated-version=wardle=1.2,kube=1.31'. Options are:\n"+strings.Join(r.unsafeVersionFlagOptions(true), "\n")+
"If the component is not specified, defaults to \"kube\"")
"Version format could only be major.minor, for example: '--emulated-version=wardle=1.2,kube=1.31'.\nOptions are: "+strings.Join(r.unsafeVersionFlagOptions(true), ",")+
"\nIf the component is not specified, defaults to \"kube\"")
fs.Var(cliflag.NewColonSeparatedMultimapStringStringAllowDefaultEmptyKey(&r.featureGatesConfig), "feature-gates", "Comma-separated list of component:key=value pairs that describe feature gates for alpha/experimental features of different components.\n"+
if r.featureGatesConfigFlags == nil {
r.featureGatesConfigFlags = cliflag.NewColonSeparatedMultimapStringStringAllowDefaultEmptyKey(&r.featureGatesConfig)
}
fs.Var(r.featureGatesConfigFlags, "feature-gates", "Comma-separated list of component:key=value pairs that describe feature gates for alpha/experimental features of different components.\n"+
"If the component is not specified, defaults to \"kube\". This flag can be repeatedly invoked. For example: --feature-gates 'wardle:featureA=true,wardle:featureB=false' --feature-gates 'kube:featureC=true'"+
"Options are:\n"+strings.Join(r.unsafeKnownFeatures(), "\n"))
}
@ -441,7 +417,7 @@ func (r *componentGlobalsRegistry) SetEmulationVersionMapping(fromComponent, toC
return fmt.Errorf("EmulationVersion from %s to %s already exists", fromComponent, toComponent)
}
versionMapping[toComponent] = f
klog.V(klogLevel).Infof("setting the default EmulationVersion of %s based on mapping from the default EmulationVersion of %s", fromComponent, toComponent)
klog.V(klogLevel).Infof("setting the default EmulationVersion of %s based on mapping from the default EmulationVersion of %s", toComponent, fromComponent)
defaultFromVersion := r.componentGlobals[fromComponent].effectiveVersion.EmulationVersion()
emulationVersions, err := r.getFullEmulationVersionConfig(map[string]*version.Version{fromComponent: defaultFromVersion})
if err != nil {

View File

@ -0,0 +1,239 @@
/*
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"
apimachineryversion "k8s.io/apimachinery/pkg/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
// Info returns the version information of a component.
Info() *apimachineryversion.Info
}
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 {
return m.emulationVersion.Load()
}
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
}
// Info returns the version information of a component.
// If the binary version is nil, it returns nil.
func (m *effectiveVersion) Info() *apimachineryversion.Info {
binVer := m.BinaryVersion()
if binVer == nil {
return nil
}
info := baseversion.Get()
info.Major = version.Itoa(binVer.Major())
info.Minor = version.Itoa(binVer.Minor())
if info.GitVersion == "" {
info.GitVersion = binVer.String()
}
if ev := m.EmulationVersion(); ev != nil {
info.EmulationMajor = version.Itoa(ev.Major())
info.EmulationMinor = version.Itoa(ev.Minor())
}
if mcv := m.MinCompatibilityVersion(); mcv != nil {
info.MinCompatibilityMajor = version.Itoa(mcv.Major())
info.MinCompatibilityMinor = version.Itoa(mcv.Minor())
}
return &info
}
// 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())
}

View File

@ -16,4 +16,4 @@ limitations under the License.
// +k8s:deepcopy-gen=package
package config // import "k8s.io/component-base/config"
package config

View File

@ -17,4 +17,4 @@ limitations under the License.
// +k8s:deepcopy-gen=package
// +k8s:conversion-gen=k8s.io/component-base/config
package v1alpha1 // import "k8s.io/component-base/config/v1alpha1"
package v1alpha1

View File

@ -268,7 +268,6 @@ func NewVersionedFeatureGate(emulationVersion *version.Version) *featureGate {
f.enabledRaw.Store(map[string]bool{})
f.emulationVersion.Store(emulationVersion)
f.queriedFeatures.Store(sets.Set[Feature]{})
klog.V(1).Infof("new feature gate with emulationVersion=%s", f.emulationVersion.Load().String())
return f
}
@ -319,7 +318,6 @@ func (f *featureGate) unsafeSetFromMap(enabled map[Feature]bool, m map[string]bo
// Copy existing state
known := map[Feature]VersionedSpecs{}
for k, v := range f.known.Load().(map[Feature]VersionedSpecs) {
sort.Sort(v)
known[k] = v
}
@ -422,19 +420,52 @@ func (f *featureGate) AddVersioned(features map[Feature]VersionedSpecs) error {
if f.closed {
return fmt.Errorf("cannot add a feature gate after adding it to the flag set")
}
// Copy existing state
known := f.GetAllVersioned()
for name, specs := range features {
sort.Sort(specs)
if existingSpec, found := known[name]; found {
sort.Sort(existingSpec)
if reflect.DeepEqual(existingSpec, specs) {
continue
}
return fmt.Errorf("feature gate %q with different spec already exists: %v", name, existingSpec)
}
// Validate new specs are well-formed
var lastVersion *version.Version
var wasBeta, wasGA, wasDeprecated bool
for i, spec := range specs {
if spec.Version == nil {
return fmt.Errorf("feature %q did not provide a version", name)
}
if len(spec.Version.Components()) != 2 {
return fmt.Errorf("feature %q specified patch version: %s", name, spec.Version.String())
}
// gates that begin as deprecated must indicate their prior state
if i == 0 && spec.PreRelease == Deprecated && spec.Version.Minor() != 0 {
return fmt.Errorf("feature %q introduced as deprecated must provide a 1.0 entry indicating initial state", name)
}
if i > 0 {
// versions must strictly increase
if !lastVersion.LessThan(spec.Version) {
return fmt.Errorf("feature %q lists version transitions in non-increasing order (%s <= %s)", name, spec.Version, lastVersion)
}
// stability must not regress from ga --> {beta,alpha} or beta --> alpha, and
// Deprecated state must be the terminal state
switch {
case spec.PreRelease != Deprecated && wasDeprecated:
return fmt.Errorf("deprecated feature %q must not resurrect from its terminal state", name)
case spec.PreRelease == Alpha && (wasBeta || wasGA):
return fmt.Errorf("feature %q regresses stability from more stable level to %s in %s", name, spec.PreRelease, spec.Version)
case spec.PreRelease == Beta && wasGA:
return fmt.Errorf("feature %q regresses stability from more stable level to %s in %s", name, spec.PreRelease, spec.Version)
}
}
lastVersion = spec.Version
wasBeta = wasBeta || spec.PreRelease == Beta
wasGA = wasGA || spec.PreRelease == GA
wasDeprecated = wasDeprecated || spec.PreRelease == Deprecated
}
known[name] = specs
}

View File

@ -29,4 +29,4 @@ limitations under the License.
// The LoggingAlphaOptions and LoggingBetaOptions feature gates control whether
// these unstable features can get enabled. This can be used to ensure that
// command invocations do not accidentally rely on unstable features.
package v1 // import "k8s.io/component-base/logs/api/v1"
package v1

View File

@ -17,6 +17,7 @@ limitations under the License.
package v1
import (
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/component-base/featuregate"
)
@ -31,17 +32,16 @@ const (
// used by a call chain.
ContextualLogging featuregate.Feature = "ContextualLogging"
// contextualLoggingDefault is now true because the feature reached beta
// and performance comparisons showed no relevant degradation when
// enabling it.
contextualLoggingDefault = true
// Allow fine-tuning of experimental, alpha-quality logging options.
//
// Per https://groups.google.com/g/kubernetes-sig-architecture/c/Nxsc7pfe5rw/m/vF2djJh0BAAJ
// we want to avoid a proliferation of feature gates. This feature gate:
// - will guard *a group* of logging options whose quality level is alpha.
// - will never graduate to beta or stable.
//
// IMPORTANT: Unlike typical feature gates, LoggingAlphaOptions is NOT affected by
// emulation version changes. Its behavior remains constant regardless of the
// emulation version being used.
LoggingAlphaOptions featuregate.Feature = "LoggingAlphaOptions"
// Allow fine-tuning of experimental, beta-quality logging options.
@ -51,22 +51,32 @@ const (
// - will guard *a group* of logging options whose quality level is beta.
// - is thus *introduced* as beta
// - will never graduate to stable.
//
// IMPORTANT: Unlike typical feature gates, LoggingBetaOptions is NOT affected by
// emulation version changes. Its behavior remains constant regardless of the
// emulation version being used.
LoggingBetaOptions featuregate.Feature = "LoggingBetaOptions"
// Stable logging options. Always enabled.
LoggingStableOptions featuregate.Feature = "LoggingStableOptions"
)
func featureGates() map[featuregate.Feature]featuregate.FeatureSpec {
return map[featuregate.Feature]featuregate.FeatureSpec{
ContextualLogging: {Default: contextualLoggingDefault, PreRelease: featuregate.Beta},
LoggingAlphaOptions: {Default: false, PreRelease: featuregate.Alpha},
LoggingBetaOptions: {Default: true, PreRelease: featuregate.Beta},
func featureGates() map[featuregate.Feature]featuregate.VersionedSpecs {
return map[featuregate.Feature]featuregate.VersionedSpecs{
ContextualLogging: {
{Version: version.MustParse("1.24"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.30"), Default: true, PreRelease: featuregate.Beta},
},
LoggingAlphaOptions: {
{Version: version.MustParse("1.24"), Default: false, PreRelease: featuregate.Alpha},
},
LoggingBetaOptions: {
{Version: version.MustParse("1.24"), Default: true, PreRelease: featuregate.Beta},
},
}
}
// AddFeatureGates adds all feature gates used by this package.
func AddFeatureGates(mutableFeatureGate featuregate.MutableFeatureGate) error {
return mutableFeatureGate.Add(featureGates())
func AddFeatureGates(mutableFeatureGate featuregate.MutableVersionedFeatureGate) error {
return mutableFeatureGate.AddVersioned(featureGates())
}

View File

@ -27,7 +27,7 @@ import (
"sync/atomic"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp" //nolint:depguard
"github.com/spf13/pflag"
"k8s.io/klog/v2"
@ -153,7 +153,7 @@ func Validate(c *LoggingConfiguration, featureGate featuregate.FeatureGate, fldP
errs = append(errs, field.Invalid(fldPath.Child("format"), c.Format, "Unsupported log format"))
} else if format != nil {
if format.feature != LoggingStableOptions {
enabled := featureGates()[format.feature].Default
enabled := featureGates()[format.feature][len(featureGates()[format.feature])-1].Default
if featureGate != nil {
enabled = featureGate.Enabled(format.feature)
}
@ -228,7 +228,7 @@ func apply(c *LoggingConfiguration, options *LoggingOptions, featureGate feature
p := &parameters{
C: c,
Options: options,
ContextualLoggingEnabled: contextualLoggingDefault,
ContextualLoggingEnabled: true,
}
if featureGate != nil {
p.ContextualLoggingEnabled = featureGate.Enabled(ContextualLogging)

View File

@ -20,7 +20,9 @@ import (
"fmt"
"io"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
dto "github.com/prometheus/client_model/go"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"k8s.io/component-base/metrics"
@ -33,6 +35,14 @@ type TB interface {
Fatalf(format string, args ...any)
}
// MetricFamily is a type alias which enables writing gatherers in tests
// without importing prometheus directly (https://github.com/kubernetes/kubernetes/issues/99876).
type MetricFamily = dto.MetricFamily
// GathererFunc is a type alias which enables writing gatherers as a function in tests
// without importing prometheus directly (https://github.com/kubernetes/kubernetes/issues/99876).
type GathererFunc = prometheus.GathererFunc
// CollectAndCompare registers the provided Collector with a newly created
// pedantic Registry. It then does the same as GatherAndCompare, gathering the
// metrics from the pedantic Registry.

View File

@ -26,4 +26,4 @@ limitations under the License.
// The "v1" package name is just a reminder that API compatibility rules apply,
// not an indication of the stability of all features covered by it.
package v1 // import "k8s.io/component-base/tracing/api/v1"
package v1

View File

@ -66,5 +66,5 @@ const (
// DefaultKubeBinaryVersion is the hard coded k8 binary version based on the latest K8s release.
// It is supposed to be consistent with gitMajor and gitMinor, except for local tests, where gitMajor and gitMinor are "".
// Should update for each minor release!
DefaultKubeBinaryVersion = "1.32"
DefaultKubeBinaryVersion = "1.33"
)

View File

@ -19,43 +19,14 @@ package version
import (
"fmt"
"runtime"
"sync/atomic"
"k8s.io/apimachinery/pkg/util/version"
apimachineryversion "k8s.io/apimachinery/pkg/version"
)
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
// what code a binary was built from.
// The caller should use BinaryMajor and BinaryMinor to determine
// the binary version. The Major and Minor fields are still set by git version for backwards compatibility.
func Get() apimachineryversion.Info {
// These variables typically come from -ldflags settings and in
// their absence fallback to the settings in ./base.go
@ -71,129 +42,3 @@ func Get() apimachineryversion.Info {
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))
}
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-1}...1.{binaryMinor}.
maxEmuVer := binaryVersion
minEmuVer := binaryVersion.SubtractMinor(1)
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-1} for alpha.
maxCompVer := binaryVersion.SubtractMinor(1)
minCompVer := binaryVersion.SubtractMinor(1)
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 equal to the binary version at 1.31 for kube components.
// emulationVersion is introduced in 1.31, so it is only allowed to be equal to the binary version at 1.31.
func ValidateKubeEffectiveVersion(effectiveVersion EffectiveVersion) error {
binaryVersion := version.MajorMinor(effectiveVersion.BinaryVersion().Major(), effectiveVersion.BinaryVersion().Minor())
if binaryVersion.EqualTo(version.MajorMinor(1, 31)) && !effectiveVersion.EmulationVersion().EqualTo(binaryVersion) {
return fmt.Errorf("emulation version needs to be equal to binary version(%s) in compatibility-version alpha, got %s",
binaryVersion.String(), effectiveVersion.EmulationVersion().String())
}
return nil
}

View File

@ -25,7 +25,7 @@ type Reader interface {
GetFlagz() map[string]string
}
// NamedFlagSetsGetter implements Reader for cliflag.NamedFlagSets
// NamedFlagSetsReader implements Reader for cliflag.NamedFlagSets
type NamedFlagSetsReader struct {
FlagSets cliflag.NamedFlagSets
}

View File

@ -23,15 +23,15 @@ import (
"math/rand"
"net/http"
"sort"
"strings"
"sync"
"github.com/munnerz/goautoneg"
"k8s.io/component-base/zpages/httputil"
"k8s.io/klog/v2"
)
const (
DefaultFlagzPath = "/flagz"
flagzHeaderFmt = `
%s flags
Warning: This endpoint is not meant to be machine parseable, has no formatting compatibility guarantees and is for debugging purposes only.
@ -40,8 +40,7 @@ Warning: This endpoint is not meant to be machine parseable, has no formatting c
)
var (
flagzSeparators = []string{":", ": ", "=", " "}
errUnsupportedMediaType = fmt.Errorf("media type not acceptable, must be: text/plain")
delimiters = []string{":", ": ", "=", " "}
)
type registry struct {
@ -59,13 +58,13 @@ func Install(m mux, componentName string, flagReader Reader) {
}
func (reg *registry) installHandler(m mux, componentName string, flagReader Reader) {
m.Handle("/flagz", reg.handleFlags(componentName, flagReader))
m.Handle(DefaultFlagzPath, reg.handleFlags(componentName, flagReader))
}
func (reg *registry) handleFlags(componentName string, flagReader Reader) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !acceptableMediaType(r) {
http.Error(w, errUnsupportedMediaType.Error(), http.StatusNotAcceptable)
if !httputil.AcceptableMediaType(r) {
http.Error(w, httputil.ErrUnsupportedMediaType.Error(), http.StatusNotAcceptable)
return
}
@ -76,8 +75,8 @@ func (reg *registry) handleFlags(componentName string, flagReader Reader) http.H
return
}
randomIndex := rand.Intn(len(flagzSeparators))
separator := flagzSeparators[randomIndex]
randomIndex := rand.Intn(len(delimiters))
separator := delimiters[randomIndex]
// Randomize the delimiter for printing to prevent scraping of the response.
printSortedFlags(&reg.response, flagReader.GetFlagz(), separator)
})
@ -90,29 +89,6 @@ func (reg *registry) handleFlags(componentName string, flagReader Reader) http.H
}
}
func acceptableMediaType(r *http.Request) bool {
accepts := goautoneg.ParseAccept(r.Header.Get("Accept"))
for _, accept := range accepts {
if !mediaTypeMatches(accept) {
continue
}
if len(accept.Params) == 0 {
return true
}
if len(accept.Params) == 1 {
if charset, ok := accept.Params["charset"]; ok && strings.EqualFold(charset, "utf-8") {
return true
}
}
}
return false
}
func mediaTypeMatches(a goautoneg.Accept) bool {
return (a.Type == "text" || a.Type == "*") &&
(a.SubType == "plain" || a.SubType == "*")
}
func printSortedFlags(w io.Writer, flags map[string]string, separator string) {
var sortedKeys []string
for key := range flags {

View File

@ -0,0 +1,54 @@
/*
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 httputil
import (
"fmt"
"net/http"
"strings"
"github.com/munnerz/goautoneg"
)
// ErrUnsupportedMediaType is the error returned when the request's
// Accept header does not contain "text/plain".
var ErrUnsupportedMediaType = fmt.Errorf("media type not acceptable, must be: text/plain")
// AcceptableMediaType checks if the request's Accept header contains
// a supported media type with optional "charset=utf-8" parameter.
func AcceptableMediaType(r *http.Request) bool {
accepts := goautoneg.ParseAccept(r.Header.Get("Accept"))
for _, accept := range accepts {
if !mediaTypeMatches(accept) {
continue
}
if len(accept.Params) == 0 {
return true
}
if len(accept.Params) == 1 {
if charset, ok := accept.Params["charset"]; ok && strings.EqualFold(charset, "utf-8") {
return true
}
}
}
return false
}
func mediaTypeMatches(a goautoneg.Accept) bool {
return (a.Type == "text" || a.Type == "*") &&
(a.SubType == "plain" || a.SubType == "*")
}