1
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
34 PublicKeysECDSA = "PublicKeysECDSA"
35
36 RootlessControlPlane = "RootlessControlPlane"
37
38 EtcdLearnerMode = "EtcdLearnerMode"
39
40 UpgradeAddonsBeforeControlPlane = "UpgradeAddonsBeforeControlPlane"
41
42 WaitForAllControlPlaneComponents = "WaitForAllControlPlaneComponents"
43 )
44
45
46 var InitFeatureGates = FeatureList{
47 PublicKeysECDSA: {
48 FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Deprecated},
49 DeprecationMessage: "The PublicKeysECDSA feature gate is deprecated and will be removed when v1beta3 is removed." +
50 " v1beta4 supports a new option 'ClusterConfiguration.EncryptionAlgorithm'.",
51 },
52 RootlessControlPlane: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
53 EtcdLearnerMode: {FeatureSpec: featuregate.FeatureSpec{Default: true, PreRelease: featuregate.Beta}},
54 UpgradeAddonsBeforeControlPlane: {
55 FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Deprecated},
56 DeprecationMessage: "The UpgradeAddonsBeforeControlPlane feature gate is deprecated and will be removed in a future release.",
57 },
58 WaitForAllControlPlaneComponents: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
59 }
60
61
62 type Feature struct {
63 featuregate.FeatureSpec
64 MinimumVersion *version.Version
65 HiddenInHelpText bool
66 DeprecationMessage string
67 }
68
69
70 type FeatureList map[string]Feature
71
72
73 func ValidateVersion(allFeatures FeatureList, requestedFeatures map[string]bool, requestedVersion string) error {
74 if requestedVersion == "" {
75 return nil
76 }
77 parsedExpVersion, err := version.ParseSemantic(requestedVersion)
78 if err != nil {
79 return errors.Wrapf(err, "error parsing version %s", requestedVersion)
80 }
81 for k := range requestedFeatures {
82 if minVersion := allFeatures[k].MinimumVersion; minVersion != nil {
83 if !parsedExpVersion.AtLeast(minVersion) {
84 return errors.Errorf(
85 "the requested Kubernetes version (%s) is incompatible with the %s feature gate, which needs %s as a minimum",
86 requestedVersion, k, minVersion)
87 }
88 }
89 }
90 return nil
91 }
92
93
94 func Enabled(featureList map[string]bool, featureName string) bool {
95 if enabled, ok := featureList[featureName]; ok {
96 return enabled
97 }
98 return InitFeatureGates[featureName].Default
99 }
100
101
102
103 func Supports(featureList FeatureList, featureName string) bool {
104 for k := range featureList {
105 if featureName == k {
106 return true
107 }
108 }
109 return false
110 }
111
112
113 func KnownFeatures(f *FeatureList) []string {
114 var known []string
115 for k, v := range *f {
116 if v.HiddenInHelpText {
117 continue
118 }
119
120 pre := ""
121 if v.PreRelease != featuregate.GA {
122 pre = fmt.Sprintf("%s - ", v.PreRelease)
123 }
124 known = append(known, fmt.Sprintf("%s=true|false (%sdefault=%t)", k, pre, v.Default))
125 }
126 sort.Strings(known)
127 return known
128 }
129
130
131
132 func NewFeatureGate(f *FeatureList, value string) (map[string]bool, error) {
133 featureGate := map[string]bool{}
134 for _, s := range strings.Split(value, ",") {
135 if len(s) == 0 {
136 continue
137 }
138
139 arr := strings.SplitN(s, "=", 2)
140 if len(arr) != 2 {
141 return nil, errors.Errorf("missing bool value for feature-gate key:%s", s)
142 }
143
144 k := strings.TrimSpace(arr[0])
145 v := strings.TrimSpace(arr[1])
146
147 featureSpec, ok := (*f)[k]
148 if !ok {
149 return nil, errors.Errorf("unrecognized feature-gate key: %s", k)
150 }
151
152 if featureSpec.PreRelease == featuregate.Deprecated {
153 klog.Warningf("Setting deprecated feature gate %s=%s. It will be removed in a future release.", k, v)
154 }
155
156 boolValue, err := strconv.ParseBool(v)
157 if err != nil {
158 return nil, errors.Errorf("invalid value %v for feature-gate key: %s, use true|false instead", v, k)
159 }
160 featureGate[k] = boolValue
161 }
162
163 return featureGate, nil
164 }
165
166
167
168
169 func CheckDeprecatedFlags(f *FeatureList, features map[string]bool) map[string]string {
170 deprecatedMsg := map[string]string{}
171 for k := range features {
172 featureSpec, ok := (*f)[k]
173 if !ok {
174
175
176 deprecatedMsg[k] = fmt.Sprintf("Unknown feature gate flag: %s", k)
177 }
178
179 if featureSpec.PreRelease == featuregate.Deprecated {
180 if _, ok := deprecatedMsg[k]; !ok {
181 deprecatedMsg[k] = featureSpec.DeprecationMessage
182 }
183 }
184 }
185
186 return deprecatedMsg
187 }
188
View as plain text