...

Source file src/k8s.io/client-go/features/features.go

Documentation: k8s.io/client-go/features

     1  /*
     2  Copyright 2024 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package features
    18  
    19  import (
    20  	"errors"
    21  
    22  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    23  	"sync/atomic"
    24  )
    25  
    26  // NOTE: types Feature, FeatureSpec, prerelease (and its values)
    27  // were duplicated from the component-base repository
    28  //
    29  // for more information please refer to https://docs.google.com/document/d/1g9BGCRw-7ucUxO6OtCWbb3lfzUGA_uU9178wLdXAIfs
    30  
    31  const (
    32  	// Values for PreRelease.
    33  	Alpha = prerelease("ALPHA")
    34  	Beta  = prerelease("BETA")
    35  	GA    = prerelease("")
    36  
    37  	// Deprecated
    38  	Deprecated = prerelease("DEPRECATED")
    39  )
    40  
    41  type prerelease string
    42  
    43  type Feature string
    44  
    45  type FeatureSpec struct {
    46  	// Default is the default enablement state for the feature
    47  	Default bool
    48  	// LockToDefault indicates that the feature is locked to its default and cannot be changed
    49  	LockToDefault bool
    50  	// PreRelease indicates the maturity level of the feature
    51  	PreRelease prerelease
    52  }
    53  
    54  // Gates indicates whether a given feature is enabled or not.
    55  type Gates interface {
    56  	// Enabled returns true if the key is enabled.
    57  	Enabled(key Feature) bool
    58  }
    59  
    60  // Registry represents an external feature gates registry.
    61  type Registry interface {
    62  	// Add adds existing feature gates to the provided registry.
    63  	//
    64  	// As of today, this method is used by AddFeaturesToExistingFeatureGates and
    65  	// ReplaceFeatureGates to take control of the features exposed by this library.
    66  	Add(map[Feature]FeatureSpec) error
    67  }
    68  
    69  // FeatureGates returns the feature gates exposed by this library.
    70  //
    71  // By default, only the default features gates will be returned.
    72  // The default implementation allows controlling the features
    73  // via environmental variables.
    74  // For example, if you have a feature named "MyFeature"
    75  // setting an environmental variable "KUBE_FEATURE_MyFeature"
    76  // will allow you to configure the state of that feature.
    77  //
    78  // Please note that the actual set of the feature gates
    79  // might be overwritten by calling ReplaceFeatureGates method.
    80  func FeatureGates() Gates {
    81  	return featureGates.Load().(*featureGatesWrapper).Gates
    82  }
    83  
    84  // AddFeaturesToExistingFeatureGates adds the default feature gates to the provided registry.
    85  // Usually this function is combined with ReplaceFeatureGates to take control of the
    86  // features exposed by this library.
    87  func AddFeaturesToExistingFeatureGates(registry Registry) error {
    88  	return registry.Add(defaultKubernetesFeatureGates)
    89  }
    90  
    91  // ReplaceFeatureGates overwrites the default implementation of the feature gates
    92  // used by this library.
    93  //
    94  // Useful for binaries that would like to have full control of the features
    95  // exposed by this library, such as allowing consumers of a binary
    96  // to interact with the features via a command line flag.
    97  //
    98  // For example:
    99  //
   100  //	// first, register client-go's features to your registry.
   101  //	clientgofeaturegate.AddFeaturesToExistingFeatureGates(utilfeature.DefaultMutableFeatureGate)
   102  //	// then replace client-go's feature gates implementation with your implementation
   103  //	clientgofeaturegate.ReplaceFeatureGates(utilfeature.DefaultMutableFeatureGate)
   104  func ReplaceFeatureGates(newFeatureGates Gates) {
   105  	if replaceFeatureGatesWithWarningIndicator(newFeatureGates) {
   106  		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"))
   107  	}
   108  }
   109  
   110  func replaceFeatureGatesWithWarningIndicator(newFeatureGates Gates) bool {
   111  	shouldProduceWarning := false
   112  
   113  	if defaultFeatureGates, ok := FeatureGates().(*envVarFeatureGates); ok {
   114  		if defaultFeatureGates.hasAlreadyReadEnvVar() {
   115  			shouldProduceWarning = true
   116  		}
   117  	}
   118  	wrappedFeatureGates := &featureGatesWrapper{newFeatureGates}
   119  	featureGates.Store(wrappedFeatureGates)
   120  
   121  	return shouldProduceWarning
   122  }
   123  
   124  func init() {
   125  	envVarGates := newEnvVarFeatureGates(defaultKubernetesFeatureGates)
   126  
   127  	wrappedFeatureGates := &featureGatesWrapper{envVarGates}
   128  	featureGates.Store(wrappedFeatureGates)
   129  }
   130  
   131  // featureGatesWrapper a thin wrapper to satisfy featureGates variable (atomic.Value).
   132  // That is, all calls to Store for a given Value must use values of the same concrete type.
   133  type featureGatesWrapper struct {
   134  	Gates
   135  }
   136  
   137  var (
   138  	// featureGates is a shared global FeatureGates.
   139  	//
   140  	// Top-level commands/options setup that needs to modify this feature gates
   141  	// should use AddFeaturesToExistingFeatureGates followed by ReplaceFeatureGates.
   142  	featureGates = &atomic.Value{}
   143  )
   144  

View as plain text