mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 10:19:50 +00:00
client-go/features: warn when ordering initialization issue
ReplaceFeatureGates logs a warning when the default env var implementation has been already used. Such a situation indicates a potential ordering issue and usually is unwanted.
This commit is contained in:
parent
d74c57d4f5
commit
04bbd3481f
@ -77,6 +77,10 @@ type envVarFeatureGates struct {
|
|||||||
// enabled holds a map[Feature]bool
|
// enabled holds a map[Feature]bool
|
||||||
// with values explicitly set via env var
|
// with values explicitly set via env var
|
||||||
enabled atomic.Value
|
enabled atomic.Value
|
||||||
|
|
||||||
|
// readEnvVars holds the boolean value which
|
||||||
|
// indicates whether readEnvVarsOnce has been called.
|
||||||
|
readEnvVars atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enabled returns true if the key is enabled. If the key is not known, this call will panic.
|
// Enabled returns true if the key is enabled. If the key is not known, this call will panic.
|
||||||
@ -116,6 +120,7 @@ func (f *envVarFeatureGates) getEnabledMapFromEnvVar() map[Feature]bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.enabled.Store(featureGatesState)
|
f.enabled.Store(featureGatesState)
|
||||||
|
f.readEnvVars.Store(true)
|
||||||
|
|
||||||
for feature, featureSpec := range f.known {
|
for feature, featureSpec := range f.known {
|
||||||
if featureState, ok := featureGatesState[feature]; ok {
|
if featureState, ok := featureGatesState[feature]; ok {
|
||||||
@ -127,3 +132,7 @@ func (f *envVarFeatureGates) getEnabledMapFromEnvVar() map[Feature]bool {
|
|||||||
})
|
})
|
||||||
return f.enabled.Load().(map[Feature]bool)
|
return f.enabled.Load().(map[Feature]bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *envVarFeatureGates) hasAlreadyReadEnvVar() bool {
|
||||||
|
return f.readEnvVars.Load()
|
||||||
|
}
|
||||||
|
@ -146,3 +146,11 @@ func TestEnvVarFeatureGatesEnabledPanic(t *testing.T) {
|
|||||||
target := newEnvVarFeatureGates(nil)
|
target := newEnvVarFeatureGates(nil)
|
||||||
require.PanicsWithError(t, fmt.Errorf("feature %q is not registered in FeatureGates %q", "UnknownFeature", target.callSiteName).Error(), func() { target.Enabled("UnknownFeature") })
|
require.PanicsWithError(t, fmt.Errorf("feature %q is not registered in FeatureGates %q", "UnknownFeature", target.callSiteName).Error(), func() { target.Enabled("UnknownFeature") })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHasAlreadyReadEnvVar(t *testing.T) {
|
||||||
|
target := newEnvVarFeatureGates(nil)
|
||||||
|
require.False(t, target.hasAlreadyReadEnvVar())
|
||||||
|
|
||||||
|
_ = target.getEnabledMapFromEnvVar()
|
||||||
|
require.True(t, target.hasAlreadyReadEnvVar())
|
||||||
|
}
|
||||||
|
@ -17,6 +17,9 @@ limitations under the License.
|
|||||||
package features
|
package features
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -99,8 +102,23 @@ func AddFeaturesToExistingFeatureGates(registry Registry) error {
|
|||||||
// // then replace client-go's feature gates implementation with your implementation
|
// // then replace client-go's feature gates implementation with your implementation
|
||||||
// clientgofeaturegate.ReplaceFeatureGates(utilfeature.DefaultMutableFeatureGate)
|
// clientgofeaturegate.ReplaceFeatureGates(utilfeature.DefaultMutableFeatureGate)
|
||||||
func ReplaceFeatureGates(newFeatureGates Gates) {
|
func ReplaceFeatureGates(newFeatureGates Gates) {
|
||||||
|
if replaceFeatureGatesWithWarningIndicator(newFeatureGates) {
|
||||||
|
utilruntime.HandleError(errors.New("the default feature gates implementation has already been used and now it's being overwritten. This might lead to unexpected behaviour. Check your initialization order"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func replaceFeatureGatesWithWarningIndicator(newFeatureGates Gates) bool {
|
||||||
|
shouldProduceWarning := false
|
||||||
|
|
||||||
|
if defaultFeatureGates, ok := FeatureGates().(*envVarFeatureGates); ok {
|
||||||
|
if defaultFeatureGates.hasAlreadyReadEnvVar() {
|
||||||
|
shouldProduceWarning = true
|
||||||
|
}
|
||||||
|
}
|
||||||
wrappedFeatureGates := &featureGatesWrapper{newFeatureGates}
|
wrappedFeatureGates := &featureGatesWrapper{newFeatureGates}
|
||||||
featureGates.Store(wrappedFeatureGates)
|
featureGates.Store(wrappedFeatureGates)
|
||||||
|
|
||||||
|
return shouldProduceWarning
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
Loading…
Reference in New Issue
Block a user