k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/controlplane/apiserver/options/validation_test.go (about) 1 /* 2 Copyright 2023 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 options 18 19 import ( 20 "strings" 21 "testing" 22 23 kubeapiserveradmission "k8s.io/apiserver/pkg/admission" 24 genericoptions "k8s.io/apiserver/pkg/server/options" 25 utilfeature "k8s.io/apiserver/pkg/util/feature" 26 "k8s.io/component-base/featuregate" 27 basemetrics "k8s.io/component-base/metrics" 28 "k8s.io/kubernetes/pkg/features" 29 30 peerreconcilers "k8s.io/apiserver/pkg/reconcilers" 31 featuregatetesting "k8s.io/component-base/featuregate/testing" 32 kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options" 33 ) 34 35 func TestValidateAPIPriorityAndFairness(t *testing.T) { 36 const conflict = "conflicts with --enable-priority-and-fairness=true" 37 tests := []struct { 38 runtimeConfig string 39 errShouldContain string 40 }{ 41 { 42 runtimeConfig: "api/all=false", 43 errShouldContain: conflict, 44 }, 45 { 46 runtimeConfig: "api/beta=false", 47 errShouldContain: "", 48 }, 49 { 50 runtimeConfig: "api/ga=false", 51 errShouldContain: conflict, 52 }, 53 { 54 runtimeConfig: "api/ga=true", 55 errShouldContain: "", 56 }, 57 { 58 runtimeConfig: "flowcontrol.apiserver.k8s.io/v1beta1=false", 59 errShouldContain: "", 60 }, 61 { 62 runtimeConfig: "flowcontrol.apiserver.k8s.io/v1beta2=false", 63 errShouldContain: "", 64 }, 65 { 66 runtimeConfig: "flowcontrol.apiserver.k8s.io/v1beta3=false", 67 errShouldContain: "", 68 }, 69 { 70 runtimeConfig: "flowcontrol.apiserver.k8s.io/v1beta3=true", 71 errShouldContain: "", 72 }, 73 { 74 runtimeConfig: "flowcontrol.apiserver.k8s.io/v1=true", 75 errShouldContain: "", 76 }, 77 { 78 runtimeConfig: "flowcontrol.apiserver.k8s.io/v1=false", 79 errShouldContain: conflict, 80 }, 81 { 82 runtimeConfig: "flowcontrol.apiserver.k8s.io/v1beta3=true,flowcontrol.apiserver.k8s.io/v1=false", 83 errShouldContain: conflict, 84 }, 85 } 86 87 for _, test := range tests { 88 t.Run(test.runtimeConfig, func(t *testing.T) { 89 options := &Options{ 90 Features: &genericoptions.FeatureOptions{ 91 EnablePriorityAndFairness: true, 92 }, 93 APIEnablement: genericoptions.NewAPIEnablementOptions(), 94 } 95 options.APIEnablement.RuntimeConfig.Set(test.runtimeConfig) 96 97 var errMessageGot string 98 if errs := validateAPIPriorityAndFairness(options); len(errs) > 0 { 99 errMessageGot = errs[0].Error() 100 } 101 102 switch { 103 case len(test.errShouldContain) == 0: 104 if len(errMessageGot) > 0 { 105 t.Errorf("Expected no error, but got: %q", errMessageGot) 106 } 107 default: 108 if !strings.Contains(errMessageGot, test.errShouldContain) { 109 t.Errorf("Expected error message to contain: %q, but got: %q", test.errShouldContain, errMessageGot) 110 } 111 } 112 }) 113 } 114 } 115 116 func TestValidateUnknownVersionInteroperabilityProxy(t *testing.T) { 117 tests := []struct { 118 name string 119 featureEnabled bool 120 errShouldContain string 121 peerCAFile string 122 peerAdvertiseAddress peerreconcilers.PeerAdvertiseAddress 123 }{ 124 { 125 name: "feature disabled but peerCAFile set", 126 featureEnabled: false, 127 peerCAFile: "foo", 128 errShouldContain: "--peer-ca-file requires UnknownVersionInteroperabilityProxy feature to be turned on", 129 }, 130 { 131 name: "feature disabled but peerAdvertiseIP set", 132 featureEnabled: false, 133 peerAdvertiseAddress: peerreconcilers.PeerAdvertiseAddress{PeerAdvertiseIP: "1.2.3.4"}, 134 errShouldContain: "--peer-advertise-ip requires UnknownVersionInteroperabilityProxy feature to be turned on", 135 }, 136 { 137 name: "feature disabled but peerAdvertisePort set", 138 featureEnabled: false, 139 peerAdvertiseAddress: peerreconcilers.PeerAdvertiseAddress{PeerAdvertisePort: "1"}, 140 errShouldContain: "--peer-advertise-port requires UnknownVersionInteroperabilityProxy feature to be turned on", 141 }, 142 } 143 144 for _, test := range tests { 145 t.Run(test.name, func(t *testing.T) { 146 options := &Options{ 147 PeerCAFile: test.peerCAFile, 148 PeerAdvertiseAddress: test.peerAdvertiseAddress, 149 } 150 if test.featureEnabled { 151 featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.UnknownVersionInteroperabilityProxy, true) 152 } 153 var errMessageGot string 154 if errs := validateUnknownVersionInteroperabilityProxyFlags(options); len(errs) > 0 { 155 errMessageGot = errs[0].Error() 156 } 157 if !strings.Contains(errMessageGot, test.errShouldContain) { 158 t.Errorf("Expected error message to contain: %q, but got: %q", test.errShouldContain, errMessageGot) 159 } 160 161 }) 162 } 163 } 164 165 func TestValidateUnknownVersionInteroperabilityProxyFeature(t *testing.T) { 166 const conflict = "UnknownVersionInteroperabilityProxy feature requires StorageVersionAPI feature flag to be enabled" 167 tests := []struct { 168 name string 169 featuresEnabled []featuregate.Feature 170 }{ 171 { 172 name: "enabled: UnknownVersionInteroperabilityProxy, disabled: StorageVersionAPI", 173 featuresEnabled: []featuregate.Feature{features.UnknownVersionInteroperabilityProxy}, 174 }, 175 } 176 177 for _, test := range tests { 178 t.Run(test.name, func(t *testing.T) { 179 for _, feature := range test.featuresEnabled { 180 featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, feature, true) 181 } 182 var errMessageGot string 183 if errs := validateUnknownVersionInteroperabilityProxyFeature(); len(errs) > 0 { 184 errMessageGot = errs[0].Error() 185 } 186 if !strings.Contains(errMessageGot, conflict) { 187 t.Errorf("Expected error message to contain: %q, but got: %q", conflict, errMessageGot) 188 } 189 }) 190 } 191 } 192 193 func TestValidateOptions(t *testing.T) { 194 testCases := []struct { 195 name string 196 options *Options 197 expectErrors bool 198 }{ 199 { 200 name: "validate master count equal 0", 201 expectErrors: true, 202 options: &Options{ 203 GenericServerRunOptions: &genericoptions.ServerRunOptions{}, 204 Etcd: &genericoptions.EtcdOptions{}, 205 SecureServing: &genericoptions.SecureServingOptionsWithLoopback{}, 206 Audit: &genericoptions.AuditOptions{}, 207 Admission: &kubeoptions.AdmissionOptions{ 208 GenericAdmission: &genericoptions.AdmissionOptions{ 209 EnablePlugins: []string{"foo"}, 210 Plugins: kubeapiserveradmission.NewPlugins(), 211 }, 212 PluginNames: []string{"foo"}, 213 }, 214 Authentication: &kubeoptions.BuiltInAuthenticationOptions{ 215 APIAudiences: []string{"bar"}, 216 ServiceAccounts: &kubeoptions.ServiceAccountAuthenticationOptions{ 217 Issuers: []string{"baz"}, 218 }, 219 }, 220 APIEnablement: genericoptions.NewAPIEnablementOptions(), 221 Metrics: &basemetrics.Options{}, 222 ServiceAccountSigningKeyFile: "", 223 Features: &genericoptions.FeatureOptions{}, 224 }, 225 }, 226 { 227 name: "validate token request enable not attempted", 228 expectErrors: true, 229 options: &Options{ 230 GenericServerRunOptions: &genericoptions.ServerRunOptions{}, 231 Etcd: &genericoptions.EtcdOptions{}, 232 SecureServing: &genericoptions.SecureServingOptionsWithLoopback{}, 233 Audit: &genericoptions.AuditOptions{}, 234 Admission: &kubeoptions.AdmissionOptions{ 235 GenericAdmission: &genericoptions.AdmissionOptions{ 236 EnablePlugins: []string{""}, 237 Plugins: kubeapiserveradmission.NewPlugins(), 238 }, 239 PluginNames: []string{""}, 240 }, 241 Authentication: &kubeoptions.BuiltInAuthenticationOptions{ 242 ServiceAccounts: &kubeoptions.ServiceAccountAuthenticationOptions{}, 243 }, 244 APIEnablement: genericoptions.NewAPIEnablementOptions(), 245 Metrics: &basemetrics.Options{}, 246 ServiceAccountSigningKeyFile: "", 247 Features: &genericoptions.FeatureOptions{}, 248 }, 249 }, 250 } 251 252 for _, tc := range testCases { 253 t.Run(tc.name, func(t *testing.T) { 254 errs := tc.options.Validate() 255 if len(errs) > 0 && !tc.expectErrors { 256 t.Errorf("expected no errors, errors found %+v", errs) 257 } 258 259 if len(errs) == 0 && tc.expectErrors { 260 t.Errorf("expected errors, no errors found") 261 } 262 }) 263 } 264 }