k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kubeadm/app/features/features.go (about) 1 /* 2 Copyright 2017 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 "fmt" 21 "sort" 22 "strconv" 23 "strings" 24 25 "github.com/pkg/errors" 26 27 "k8s.io/apimachinery/pkg/util/version" 28 "k8s.io/component-base/featuregate" 29 "k8s.io/klog/v2" 30 ) 31 32 const ( 33 // PublicKeysECDSA is expected to be alpha in v1.19 34 PublicKeysECDSA = "PublicKeysECDSA" 35 // RootlessControlPlane is expected to be in alpha in v1.22 36 RootlessControlPlane = "RootlessControlPlane" 37 // EtcdLearnerMode is expected to be in alpha in v1.27, beta in v1.29 38 EtcdLearnerMode = "EtcdLearnerMode" 39 // WaitForAllControlPlaneComponents is expected to be alpha in v1.30 40 WaitForAllControlPlaneComponents = "WaitForAllControlPlaneComponents" 41 ) 42 43 // InitFeatureGates are the default feature gates for the init command 44 var InitFeatureGates = FeatureList{ 45 PublicKeysECDSA: { 46 FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Deprecated}, 47 DeprecationMessage: "The PublicKeysECDSA feature gate is deprecated and will be removed when v1beta3 is removed." + 48 " v1beta4 supports a new option 'ClusterConfiguration.EncryptionAlgorithm'.", 49 }, 50 RootlessControlPlane: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}}, 51 EtcdLearnerMode: {FeatureSpec: featuregate.FeatureSpec{Default: true, PreRelease: featuregate.Beta}}, 52 WaitForAllControlPlaneComponents: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}}, 53 } 54 55 // Feature represents a feature being gated 56 type Feature struct { 57 featuregate.FeatureSpec 58 MinimumVersion *version.Version 59 HiddenInHelpText bool 60 DeprecationMessage string 61 } 62 63 // FeatureList represents a list of feature gates 64 type FeatureList map[string]Feature 65 66 // ValidateVersion ensures that a feature gate list is compatible with the chosen Kubernetes version 67 func ValidateVersion(allFeatures FeatureList, requestedFeatures map[string]bool, requestedVersion string) error { 68 if requestedVersion == "" { 69 return nil 70 } 71 parsedExpVersion, err := version.ParseSemantic(requestedVersion) 72 if err != nil { 73 return errors.Wrapf(err, "error parsing version %s", requestedVersion) 74 } 75 for k := range requestedFeatures { 76 if minVersion := allFeatures[k].MinimumVersion; minVersion != nil { 77 if !parsedExpVersion.AtLeast(minVersion) { 78 return errors.Errorf( 79 "the requested Kubernetes version (%s) is incompatible with the %s feature gate, which needs %s as a minimum", 80 requestedVersion, k, minVersion) 81 } 82 } 83 } 84 return nil 85 } 86 87 // Enabled indicates whether a feature name has been enabled 88 func Enabled(featureList map[string]bool, featureName string) bool { 89 if enabled, ok := featureList[featureName]; ok { 90 return enabled 91 } 92 return InitFeatureGates[featureName].Default 93 } 94 95 // Supports indicates whether a feature name is supported on the given 96 // feature set 97 func Supports(featureList FeatureList, featureName string) bool { 98 for k := range featureList { 99 if featureName == k { 100 return true 101 } 102 } 103 return false 104 } 105 106 // KnownFeatures returns a slice of strings describing the FeatureList features. 107 func KnownFeatures(f *FeatureList) []string { 108 var known []string 109 for k, v := range *f { 110 if v.HiddenInHelpText { 111 continue 112 } 113 114 pre := "" 115 if v.PreRelease != featuregate.GA { 116 pre = fmt.Sprintf("%s - ", v.PreRelease) 117 } 118 known = append(known, fmt.Sprintf("%s=true|false (%sdefault=%t)", k, pre, v.Default)) 119 } 120 sort.Strings(known) 121 return known 122 } 123 124 // NewFeatureGate parses a string of the form "key1=value1,key2=value2,..." into a 125 // map[string]bool of known keys or returns an error. 126 func NewFeatureGate(f *FeatureList, value string) (map[string]bool, error) { 127 featureGate := map[string]bool{} 128 for _, s := range strings.Split(value, ",") { 129 if len(s) == 0 { 130 continue 131 } 132 133 arr := strings.SplitN(s, "=", 2) 134 if len(arr) != 2 { 135 return nil, errors.Errorf("missing bool value for feature-gate key:%s", s) 136 } 137 138 k := strings.TrimSpace(arr[0]) 139 v := strings.TrimSpace(arr[1]) 140 141 featureSpec, ok := (*f)[k] 142 if !ok { 143 return nil, errors.Errorf("unrecognized feature-gate key: %s", k) 144 } 145 146 if featureSpec.PreRelease == featuregate.Deprecated { 147 klog.Warningf("Setting deprecated feature gate %s=%s. It will be removed in a future release.", k, v) 148 } 149 150 boolValue, err := strconv.ParseBool(v) 151 if err != nil { 152 return nil, errors.Errorf("invalid value %v for feature-gate key: %s, use true|false instead", v, k) 153 } 154 featureGate[k] = boolValue 155 } 156 157 return featureGate, nil 158 } 159 160 // CheckDeprecatedFlags takes a list of existing feature gate flags and validates against the current feature flag set. 161 // It used during upgrades for ensuring consistency of feature gates used in an existing cluster, that might 162 // be created with a previous version of kubeadm, with the set of features currently supported by kubeadm 163 func CheckDeprecatedFlags(f *FeatureList, features map[string]bool) map[string]string { 164 deprecatedMsg := map[string]string{} 165 for k := range features { 166 featureSpec, ok := (*f)[k] 167 if !ok { 168 // This case should never happen, it is implemented only as a sentinel 169 // for removal of flags executed when flags are still in use (always before deprecate, then after one cycle remove) 170 deprecatedMsg[k] = fmt.Sprintf("Unknown feature gate flag: %s", k) 171 } 172 173 if featureSpec.PreRelease == featuregate.Deprecated { 174 if _, ok := deprecatedMsg[k]; !ok { 175 deprecatedMsg[k] = featureSpec.DeprecationMessage 176 } 177 } 178 } 179 180 return deprecatedMsg 181 }