1
16
17 package options
18
19 import (
20 "fmt"
21 "reflect"
22 "sort"
23 "strings"
24 "testing"
25 "time"
26
27 "github.com/google/go-cmp/cmp"
28 "github.com/spf13/pflag"
29
30 eventv1 "k8s.io/api/events/v1"
31 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32 utilerrors "k8s.io/apimachinery/pkg/util/errors"
33 apiserveroptions "k8s.io/apiserver/pkg/server/options"
34 cpconfig "k8s.io/cloud-provider/config"
35 serviceconfig "k8s.io/cloud-provider/controllers/service/config"
36 cpoptions "k8s.io/cloud-provider/options"
37 componentbaseconfig "k8s.io/component-base/config"
38 "k8s.io/component-base/logs"
39 "k8s.io/component-base/metrics"
40 cmconfig "k8s.io/controller-manager/config"
41 cmoptions "k8s.io/controller-manager/options"
42 migration "k8s.io/controller-manager/pkg/leadermigration/options"
43 netutils "k8s.io/utils/net"
44
45 clientgofeaturegate "k8s.io/client-go/features"
46 kubecontrollerconfig "k8s.io/kubernetes/cmd/kube-controller-manager/app/config"
47 kubectrlmgrconfig "k8s.io/kubernetes/pkg/controller/apis/config"
48 csrsigningconfig "k8s.io/kubernetes/pkg/controller/certificates/signer/config"
49 cronjobconfig "k8s.io/kubernetes/pkg/controller/cronjob/config"
50 daemonconfig "k8s.io/kubernetes/pkg/controller/daemon/config"
51 deploymentconfig "k8s.io/kubernetes/pkg/controller/deployment/config"
52 endpointconfig "k8s.io/kubernetes/pkg/controller/endpoint/config"
53 endpointsliceconfig "k8s.io/kubernetes/pkg/controller/endpointslice/config"
54 endpointslicemirroringconfig "k8s.io/kubernetes/pkg/controller/endpointslicemirroring/config"
55 garbagecollectorconfig "k8s.io/kubernetes/pkg/controller/garbagecollector/config"
56 jobconfig "k8s.io/kubernetes/pkg/controller/job/config"
57 namespaceconfig "k8s.io/kubernetes/pkg/controller/namespace/config"
58 nodeipamconfig "k8s.io/kubernetes/pkg/controller/nodeipam/config"
59 nodelifecycleconfig "k8s.io/kubernetes/pkg/controller/nodelifecycle/config"
60 poautosclerconfig "k8s.io/kubernetes/pkg/controller/podautoscaler/config"
61 podgcconfig "k8s.io/kubernetes/pkg/controller/podgc/config"
62 replicasetconfig "k8s.io/kubernetes/pkg/controller/replicaset/config"
63 replicationconfig "k8s.io/kubernetes/pkg/controller/replication/config"
64 resourcequotaconfig "k8s.io/kubernetes/pkg/controller/resourcequota/config"
65 serviceaccountconfig "k8s.io/kubernetes/pkg/controller/serviceaccount/config"
66 statefulsetconfig "k8s.io/kubernetes/pkg/controller/statefulset/config"
67 ttlafterfinishedconfig "k8s.io/kubernetes/pkg/controller/ttlafterfinished/config"
68 validatingadmissionpolicystatusconfig "k8s.io/kubernetes/pkg/controller/validatingadmissionpolicystatus/config"
69 attachdetachconfig "k8s.io/kubernetes/pkg/controller/volume/attachdetach/config"
70 ephemeralvolumeconfig "k8s.io/kubernetes/pkg/controller/volume/ephemeral/config"
71 persistentvolumeconfig "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/config"
72 )
73
74 var args = []string{
75 "--allocate-node-cidrs=true",
76 "--attach-detach-reconcile-sync-period=30s",
77 "--cidr-allocator-type=CloudAllocator",
78 "--cloud-config=/cloud-config",
79 "--cloud-provider=gce",
80 "--cluster-cidr=1.2.3.4/24",
81 "--cluster-name=k8s",
82 "--cluster-signing-cert-file=/cluster-signing-cert",
83 "--cluster-signing-key-file=/cluster-signing-key",
84 "--cluster-signing-kubelet-serving-cert-file=/cluster-signing-kubelet-serving/cert-file",
85 "--cluster-signing-kubelet-serving-key-file=/cluster-signing-kubelet-serving/key-file",
86 "--cluster-signing-kubelet-client-cert-file=/cluster-signing-kubelet-client/cert-file",
87 "--cluster-signing-kubelet-client-key-file=/cluster-signing-kubelet-client/key-file",
88 "--cluster-signing-kube-apiserver-client-cert-file=/cluster-signing-kube-apiserver-client/cert-file",
89 "--cluster-signing-kube-apiserver-client-key-file=/cluster-signing-kube-apiserver-client/key-file",
90 "--cluster-signing-legacy-unknown-cert-file=/cluster-signing-legacy-unknown/cert-file",
91 "--cluster-signing-legacy-unknown-key-file=/cluster-signing-legacy-unknown/key-file",
92 "--concurrent-deployment-syncs=10",
93 "--concurrent-horizontal-pod-autoscaler-syncs=10",
94 "--concurrent-statefulset-syncs=15",
95 "--concurrent-endpoint-syncs=10",
96 "--concurrent-ephemeralvolume-syncs=10",
97 "--concurrent-service-endpoint-syncs=10",
98 "--concurrent-gc-syncs=30",
99 "--concurrent-namespace-syncs=20",
100 "--concurrent-job-syncs=10",
101 "--concurrent-cron-job-syncs=10",
102 "--concurrent-replicaset-syncs=10",
103 "--concurrent-resource-quota-syncs=10",
104 "--concurrent-service-syncs=2",
105 "--concurrent-serviceaccount-token-syncs=10",
106 "--concurrent_rc_syncs=10",
107 "--concurrent-validating-admission-policy-status-syncs=9",
108 "--configure-cloud-routes=false",
109 "--contention-profiling=true",
110 "--controller-start-interval=2m",
111 "--controllers=foo,bar",
112 "--disable-attach-detach-reconcile-sync=true",
113 "--enable-dynamic-provisioning=false",
114 "--enable-garbage-collector=false",
115 "--enable-hostpath-provisioner=true",
116 "--cluster-signing-duration=10h",
117 "--flex-volume-plugin-dir=/flex-volume-plugin",
118 "--volume-host-cidr-denylist=127.0.0.1/28,feed::/16",
119 "--volume-host-allow-local-loopback=false",
120 "--horizontal-pod-autoscaler-downscale-delay=2m",
121 "--horizontal-pod-autoscaler-sync-period=45s",
122 "--horizontal-pod-autoscaler-upscale-delay=1m",
123 "--horizontal-pod-autoscaler-downscale-stabilization=3m",
124 "--horizontal-pod-autoscaler-cpu-initialization-period=90s",
125 "--horizontal-pod-autoscaler-initial-readiness-delay=50s",
126 "--http2-max-streams-per-connection=47",
127 "--kube-api-burst=100",
128 "--kube-api-content-type=application/json",
129 "--kube-api-qps=50.0",
130 "--kubeconfig=/kubeconfig",
131 "--large-cluster-size-threshold=100",
132 "--leader-elect=false",
133 "--leader-elect-lease-duration=30s",
134 "--leader-elect-renew-deadline=15s",
135 "--leader-elect-resource-lock=configmap",
136 "--leader-elect-retry-period=5s",
137 "--legacy-service-account-token-clean-up-period=8760h",
138 "--master=192.168.4.20",
139 "--max-endpoints-per-slice=200",
140 "--min-resync-period=8h",
141 "--mirroring-concurrent-service-endpoint-syncs=2",
142 "--mirroring-max-endpoints-per-subset=1000",
143 "--namespace-sync-period=10m",
144 "--node-cidr-mask-size=48",
145 "--node-cidr-mask-size-ipv4=48",
146 "--node-cidr-mask-size-ipv6=108",
147 "--node-eviction-rate=0.2",
148 "--node-monitor-grace-period=30s",
149 "--node-monitor-period=10s",
150 "--node-startup-grace-period=30s",
151 "--profiling=false",
152 "--pv-recycler-increment-timeout-nfs=45",
153 "--pv-recycler-minimum-timeout-hostpath=45",
154 "--pv-recycler-minimum-timeout-nfs=200",
155 "--pv-recycler-timeout-increment-hostpath=45",
156 "--pvclaimbinder-sync-period=30s",
157 "--resource-quota-sync-period=10m",
158 "--route-reconciliation-period=30s",
159 "--secondary-node-eviction-rate=0.05",
160 "--service-account-private-key-file=/service-account-private-key",
161 "--terminated-pod-gc-threshold=12000",
162 "--unhealthy-zone-threshold=0.6",
163 "--use-service-account-credentials=true",
164 "--cert-dir=/a/b/c",
165 "--bind-address=192.168.4.21",
166 "--secure-port=10001",
167 "--concurrent-ttl-after-finished-syncs=8",
168 }
169
170 func TestAddFlags(t *testing.T) {
171 fs := pflag.NewFlagSet("addflagstest", pflag.ContinueOnError)
172 s, _ := NewKubeControllerManagerOptions()
173 for _, f := range s.Flags([]string{""}, []string{""}, nil).FlagSets {
174 fs.AddFlagSet(f)
175 }
176
177 fs.Parse(args)
178
179
180 sort.Sort(sortedGCIgnoredResources(s.GarbageCollectorController.GCIgnoredResources))
181
182 expected := &KubeControllerManagerOptions{
183 Generic: &cmoptions.GenericControllerManagerConfigurationOptions{
184 GenericControllerManagerConfiguration: &cmconfig.GenericControllerManagerConfiguration{
185 Address: "0.0.0.0",
186 MinResyncPeriod: metav1.Duration{Duration: 8 * time.Hour},
187 ClientConnection: componentbaseconfig.ClientConnectionConfiguration{
188 Kubeconfig: "/kubeconfig",
189 ContentType: "application/json",
190 QPS: 50.0,
191 Burst: 100,
192 },
193 ControllerStartInterval: metav1.Duration{Duration: 2 * time.Minute},
194 LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
195 ResourceLock: "configmap",
196 LeaderElect: false,
197 LeaseDuration: metav1.Duration{Duration: 30 * time.Second},
198 RenewDeadline: metav1.Duration{Duration: 15 * time.Second},
199 RetryPeriod: metav1.Duration{Duration: 5 * time.Second},
200 ResourceName: "kube-controller-manager",
201 ResourceNamespace: "kube-system",
202 },
203 Controllers: []string{"foo", "bar"},
204 },
205 Debugging: &cmoptions.DebuggingOptions{
206 DebuggingConfiguration: &componentbaseconfig.DebuggingConfiguration{
207 EnableProfiling: false,
208 EnableContentionProfiling: true,
209 },
210 },
211 LeaderMigration: &migration.LeaderMigrationOptions{},
212 },
213 KubeCloudShared: &cpoptions.KubeCloudSharedOptions{
214 KubeCloudSharedConfiguration: &cpconfig.KubeCloudSharedConfiguration{
215 UseServiceAccountCredentials: true,
216 RouteReconciliationPeriod: metav1.Duration{Duration: 30 * time.Second},
217 NodeMonitorPeriod: metav1.Duration{Duration: 10 * time.Second},
218 ClusterName: "k8s",
219 ClusterCIDR: "1.2.3.4/24",
220 AllocateNodeCIDRs: true,
221 CIDRAllocatorType: "CloudAllocator",
222 ConfigureCloudRoutes: false,
223 },
224 CloudProvider: &cpoptions.CloudProviderOptions{
225 CloudProviderConfiguration: &cpconfig.CloudProviderConfiguration{
226 Name: "gce",
227 CloudConfigFile: "/cloud-config",
228 },
229 },
230 },
231 ServiceController: &cpoptions.ServiceControllerOptions{
232 ServiceControllerConfiguration: &serviceconfig.ServiceControllerConfiguration{
233 ConcurrentServiceSyncs: 2,
234 },
235 },
236 AttachDetachController: &AttachDetachControllerOptions{
237 &attachdetachconfig.AttachDetachControllerConfiguration{
238 ReconcilerSyncLoopPeriod: metav1.Duration{Duration: 30 * time.Second},
239 DisableAttachDetachReconcilerSync: true,
240 },
241 },
242 CSRSigningController: &CSRSigningControllerOptions{
243 &csrsigningconfig.CSRSigningControllerConfiguration{
244 ClusterSigningCertFile: "/cluster-signing-cert",
245 ClusterSigningKeyFile: "/cluster-signing-key",
246 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
247 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
248 CertFile: "/cluster-signing-kubelet-serving/cert-file",
249 KeyFile: "/cluster-signing-kubelet-serving/key-file",
250 },
251 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
252 CertFile: "/cluster-signing-kubelet-client/cert-file",
253 KeyFile: "/cluster-signing-kubelet-client/key-file",
254 },
255 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
256 CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
257 KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
258 },
259 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
260 CertFile: "/cluster-signing-legacy-unknown/cert-file",
261 KeyFile: "/cluster-signing-legacy-unknown/key-file",
262 },
263 },
264 },
265 DaemonSetController: &DaemonSetControllerOptions{
266 &daemonconfig.DaemonSetControllerConfiguration{
267 ConcurrentDaemonSetSyncs: 2,
268 },
269 },
270 DeploymentController: &DeploymentControllerOptions{
271 &deploymentconfig.DeploymentControllerConfiguration{
272 ConcurrentDeploymentSyncs: 10,
273 },
274 },
275 StatefulSetController: &StatefulSetControllerOptions{
276 &statefulsetconfig.StatefulSetControllerConfiguration{
277 ConcurrentStatefulSetSyncs: 15,
278 },
279 },
280 DeprecatedFlags: &DeprecatedControllerOptions{
281 &kubectrlmgrconfig.DeprecatedControllerConfiguration{},
282 },
283 EndpointController: &EndpointControllerOptions{
284 &endpointconfig.EndpointControllerConfiguration{
285 ConcurrentEndpointSyncs: 10,
286 },
287 },
288 EndpointSliceController: &EndpointSliceControllerOptions{
289 &endpointsliceconfig.EndpointSliceControllerConfiguration{
290 ConcurrentServiceEndpointSyncs: 10,
291 MaxEndpointsPerSlice: 200,
292 },
293 },
294 EndpointSliceMirroringController: &EndpointSliceMirroringControllerOptions{
295 &endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration{
296 MirroringConcurrentServiceEndpointSyncs: 2,
297 MirroringMaxEndpointsPerSubset: 1000,
298 },
299 },
300 EphemeralVolumeController: &EphemeralVolumeControllerOptions{
301 &ephemeralvolumeconfig.EphemeralVolumeControllerConfiguration{
302 ConcurrentEphemeralVolumeSyncs: 10,
303 },
304 },
305 GarbageCollectorController: &GarbageCollectorControllerOptions{
306 &garbagecollectorconfig.GarbageCollectorControllerConfiguration{
307 ConcurrentGCSyncs: 30,
308 GCIgnoredResources: []garbagecollectorconfig.GroupResource{
309 {Group: "", Resource: "events"},
310 {Group: eventv1.GroupName, Resource: "events"},
311 },
312 EnableGarbageCollector: false,
313 },
314 },
315 HPAController: &HPAControllerOptions{
316 &poautosclerconfig.HPAControllerConfiguration{
317 ConcurrentHorizontalPodAutoscalerSyncs: 10,
318 HorizontalPodAutoscalerSyncPeriod: metav1.Duration{Duration: 45 * time.Second},
319 HorizontalPodAutoscalerUpscaleForbiddenWindow: metav1.Duration{Duration: 1 * time.Minute},
320 HorizontalPodAutoscalerDownscaleForbiddenWindow: metav1.Duration{Duration: 2 * time.Minute},
321 HorizontalPodAutoscalerDownscaleStabilizationWindow: metav1.Duration{Duration: 3 * time.Minute},
322 HorizontalPodAutoscalerCPUInitializationPeriod: metav1.Duration{Duration: 90 * time.Second},
323 HorizontalPodAutoscalerInitialReadinessDelay: metav1.Duration{Duration: 50 * time.Second},
324 HorizontalPodAutoscalerTolerance: 0.1,
325 },
326 },
327 JobController: &JobControllerOptions{
328 &jobconfig.JobControllerConfiguration{
329 ConcurrentJobSyncs: 10,
330 },
331 },
332 CronJobController: &CronJobControllerOptions{
333 &cronjobconfig.CronJobControllerConfiguration{
334 ConcurrentCronJobSyncs: 10,
335 },
336 },
337 NamespaceController: &NamespaceControllerOptions{
338 &namespaceconfig.NamespaceControllerConfiguration{
339 NamespaceSyncPeriod: metav1.Duration{Duration: 10 * time.Minute},
340 ConcurrentNamespaceSyncs: 20,
341 },
342 },
343 NodeIPAMController: &NodeIPAMControllerOptions{
344 &nodeipamconfig.NodeIPAMControllerConfiguration{
345 NodeCIDRMaskSize: 48,
346 NodeCIDRMaskSizeIPv4: 48,
347 NodeCIDRMaskSizeIPv6: 108,
348 },
349 },
350 NodeLifecycleController: &NodeLifecycleControllerOptions{
351 &nodelifecycleconfig.NodeLifecycleControllerConfiguration{
352 NodeEvictionRate: 0.2,
353 SecondaryNodeEvictionRate: 0.05,
354 NodeMonitorGracePeriod: metav1.Duration{Duration: 30 * time.Second},
355 NodeStartupGracePeriod: metav1.Duration{Duration: 30 * time.Second},
356 LargeClusterSizeThreshold: 100,
357 UnhealthyZoneThreshold: 0.6,
358 },
359 },
360 PersistentVolumeBinderController: &PersistentVolumeBinderControllerOptions{
361 &persistentvolumeconfig.PersistentVolumeBinderControllerConfiguration{
362 PVClaimBinderSyncPeriod: metav1.Duration{Duration: 30 * time.Second},
363 VolumeConfiguration: persistentvolumeconfig.VolumeConfiguration{
364 EnableDynamicProvisioning: false,
365 EnableHostPathProvisioning: true,
366 FlexVolumePluginDir: "/flex-volume-plugin",
367 PersistentVolumeRecyclerConfiguration: persistentvolumeconfig.PersistentVolumeRecyclerConfiguration{
368 MaximumRetry: 3,
369 MinimumTimeoutNFS: 200,
370 IncrementTimeoutNFS: 45,
371 MinimumTimeoutHostPath: 45,
372 IncrementTimeoutHostPath: 45,
373 },
374 },
375 VolumeHostCIDRDenylist: []string{"127.0.0.1/28", "feed::/16"},
376 VolumeHostAllowLocalLoopback: false,
377 },
378 },
379 PodGCController: &PodGCControllerOptions{
380 &podgcconfig.PodGCControllerConfiguration{
381 TerminatedPodGCThreshold: 12000,
382 },
383 },
384 ReplicaSetController: &ReplicaSetControllerOptions{
385 &replicasetconfig.ReplicaSetControllerConfiguration{
386 ConcurrentRSSyncs: 10,
387 },
388 },
389 ReplicationController: &ReplicationControllerOptions{
390 &replicationconfig.ReplicationControllerConfiguration{
391 ConcurrentRCSyncs: 10,
392 },
393 },
394 ResourceQuotaController: &ResourceQuotaControllerOptions{
395 &resourcequotaconfig.ResourceQuotaControllerConfiguration{
396 ResourceQuotaSyncPeriod: metav1.Duration{Duration: 10 * time.Minute},
397 ConcurrentResourceQuotaSyncs: 10,
398 },
399 },
400 SAController: &SAControllerOptions{
401 &serviceaccountconfig.SAControllerConfiguration{
402 ServiceAccountKeyFile: "/service-account-private-key",
403 ConcurrentSATokenSyncs: 10,
404 },
405 },
406 LegacySATokenCleaner: &LegacySATokenCleanerOptions{
407 &serviceaccountconfig.LegacySATokenCleanerConfiguration{
408 CleanUpPeriod: metav1.Duration{Duration: 365 * 24 * time.Hour},
409 },
410 },
411 TTLAfterFinishedController: &TTLAfterFinishedControllerOptions{
412 &ttlafterfinishedconfig.TTLAfterFinishedControllerConfiguration{
413 ConcurrentTTLSyncs: 8,
414 },
415 },
416 ValidatingAdmissionPolicyStatusController: &ValidatingAdmissionPolicyStatusControllerOptions{
417 &validatingadmissionpolicystatusconfig.ValidatingAdmissionPolicyStatusControllerConfiguration{
418 ConcurrentPolicySyncs: 9,
419 },
420 },
421 SecureServing: (&apiserveroptions.SecureServingOptions{
422 BindPort: 10001,
423 BindAddress: netutils.ParseIPSloppy("192.168.4.21"),
424 ServerCert: apiserveroptions.GeneratableKeyCert{
425 CertDirectory: "/a/b/c",
426 PairName: "kube-controller-manager",
427 },
428 HTTP2MaxStreamsPerConnection: 47,
429 }).WithLoopback(),
430 Authentication: &apiserveroptions.DelegatingAuthenticationOptions{
431 CacheTTL: 10 * time.Second,
432 TokenRequestTimeout: 10 * time.Second,
433 WebhookRetryBackoff: apiserveroptions.DefaultAuthWebhookRetryBackoff(),
434 ClientCert: apiserveroptions.ClientCertAuthenticationOptions{},
435 RequestHeader: apiserveroptions.RequestHeaderAuthenticationOptions{
436 UsernameHeaders: []string{"x-remote-user"},
437 GroupHeaders: []string{"x-remote-group"},
438 ExtraHeaderPrefixes: []string{"x-remote-extra-"},
439 },
440 RemoteKubeConfigFileOptional: true,
441 },
442 Authorization: &apiserveroptions.DelegatingAuthorizationOptions{
443 AllowCacheTTL: 10 * time.Second,
444 DenyCacheTTL: 10 * time.Second,
445 ClientTimeout: 10 * time.Second,
446 WebhookRetryBackoff: apiserveroptions.DefaultAuthWebhookRetryBackoff(),
447 RemoteKubeConfigFileOptional: true,
448 AlwaysAllowPaths: []string{"/healthz", "/readyz", "/livez"},
449 AlwaysAllowGroups: []string{"system:masters"},
450 },
451 Master: "192.168.4.20",
452 Metrics: &metrics.Options{},
453 Logs: logs.NewOptions(),
454 }
455
456
457
458 sort.Sort(sortedGCIgnoredResources(expected.GarbageCollectorController.GCIgnoredResources))
459
460 if !reflect.DeepEqual(expected, s) {
461 t.Errorf("Got different run options than expected.\nDifference detected on:\n%s", cmp.Diff(expected, s))
462 }
463 }
464
465 func TestApplyTo(t *testing.T) {
466 fs := pflag.NewFlagSet("addflagstest", pflag.ContinueOnError)
467 s, _ := NewKubeControllerManagerOptions()
468
469 for _, f := range s.Flags([]string{""}, []string{""}, nil).FlagSets {
470 fs.AddFlagSet(f)
471 }
472
473 fs.Parse(args)
474
475
476 sort.Sort(sortedGCIgnoredResources(s.GarbageCollectorController.GCIgnoredResources))
477
478 expected := &kubecontrollerconfig.Config{
479 ComponentConfig: kubectrlmgrconfig.KubeControllerManagerConfiguration{
480 Generic: cmconfig.GenericControllerManagerConfiguration{
481 Address: "0.0.0.0",
482 MinResyncPeriod: metav1.Duration{Duration: 8 * time.Hour},
483 ClientConnection: componentbaseconfig.ClientConnectionConfiguration{
484 Kubeconfig: "/kubeconfig",
485 ContentType: "application/json",
486 QPS: 50.0,
487 Burst: 100,
488 },
489 ControllerStartInterval: metav1.Duration{Duration: 2 * time.Minute},
490 LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
491 ResourceLock: "configmap",
492 LeaderElect: false,
493 LeaseDuration: metav1.Duration{Duration: 30 * time.Second},
494 RenewDeadline: metav1.Duration{Duration: 15 * time.Second},
495 RetryPeriod: metav1.Duration{Duration: 5 * time.Second},
496 ResourceName: "kube-controller-manager",
497 ResourceNamespace: "kube-system",
498 },
499 Controllers: []string{"foo", "bar"},
500 Debugging: componentbaseconfig.DebuggingConfiguration{
501 EnableProfiling: false,
502 EnableContentionProfiling: true,
503 },
504 },
505 KubeCloudShared: cpconfig.KubeCloudSharedConfiguration{
506 UseServiceAccountCredentials: true,
507 RouteReconciliationPeriod: metav1.Duration{Duration: 30 * time.Second},
508 NodeMonitorPeriod: metav1.Duration{Duration: 10 * time.Second},
509 ClusterName: "k8s",
510 ClusterCIDR: "1.2.3.4/24",
511 AllocateNodeCIDRs: true,
512 CIDRAllocatorType: "CloudAllocator",
513 ConfigureCloudRoutes: false,
514 CloudProvider: cpconfig.CloudProviderConfiguration{
515 Name: "gce",
516 CloudConfigFile: "/cloud-config",
517 },
518 },
519 ServiceController: serviceconfig.ServiceControllerConfiguration{
520 ConcurrentServiceSyncs: 2,
521 },
522 AttachDetachController: attachdetachconfig.AttachDetachControllerConfiguration{
523 ReconcilerSyncLoopPeriod: metav1.Duration{Duration: 30 * time.Second},
524 DisableAttachDetachReconcilerSync: true,
525 },
526 CSRSigningController: csrsigningconfig.CSRSigningControllerConfiguration{
527 ClusterSigningCertFile: "/cluster-signing-cert",
528 ClusterSigningKeyFile: "/cluster-signing-key",
529 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
530 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
531 CertFile: "/cluster-signing-kubelet-serving/cert-file",
532 KeyFile: "/cluster-signing-kubelet-serving/key-file",
533 },
534 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
535 CertFile: "/cluster-signing-kubelet-client/cert-file",
536 KeyFile: "/cluster-signing-kubelet-client/key-file",
537 },
538 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
539 CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
540 KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
541 },
542 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
543 CertFile: "/cluster-signing-legacy-unknown/cert-file",
544 KeyFile: "/cluster-signing-legacy-unknown/key-file",
545 },
546 },
547 DaemonSetController: daemonconfig.DaemonSetControllerConfiguration{
548 ConcurrentDaemonSetSyncs: 2,
549 },
550 DeploymentController: deploymentconfig.DeploymentControllerConfiguration{
551 ConcurrentDeploymentSyncs: 10,
552 },
553 StatefulSetController: statefulsetconfig.StatefulSetControllerConfiguration{
554 ConcurrentStatefulSetSyncs: 15,
555 },
556 DeprecatedController: kubectrlmgrconfig.DeprecatedControllerConfiguration{},
557 EndpointController: endpointconfig.EndpointControllerConfiguration{
558 ConcurrentEndpointSyncs: 10,
559 },
560 EndpointSliceController: endpointsliceconfig.EndpointSliceControllerConfiguration{
561 ConcurrentServiceEndpointSyncs: 10,
562 MaxEndpointsPerSlice: 200,
563 },
564 EndpointSliceMirroringController: endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration{
565 MirroringConcurrentServiceEndpointSyncs: 2,
566 MirroringMaxEndpointsPerSubset: 1000,
567 },
568 EphemeralVolumeController: ephemeralvolumeconfig.EphemeralVolumeControllerConfiguration{
569 ConcurrentEphemeralVolumeSyncs: 10,
570 },
571 GarbageCollectorController: garbagecollectorconfig.GarbageCollectorControllerConfiguration{
572 ConcurrentGCSyncs: 30,
573 GCIgnoredResources: []garbagecollectorconfig.GroupResource{
574 {Group: "", Resource: "events"},
575 {Group: eventv1.GroupName, Resource: "events"},
576 },
577 EnableGarbageCollector: false,
578 },
579 HPAController: poautosclerconfig.HPAControllerConfiguration{
580 ConcurrentHorizontalPodAutoscalerSyncs: 10,
581 HorizontalPodAutoscalerSyncPeriod: metav1.Duration{Duration: 45 * time.Second},
582 HorizontalPodAutoscalerUpscaleForbiddenWindow: metav1.Duration{Duration: 1 * time.Minute},
583 HorizontalPodAutoscalerDownscaleForbiddenWindow: metav1.Duration{Duration: 2 * time.Minute},
584 HorizontalPodAutoscalerDownscaleStabilizationWindow: metav1.Duration{Duration: 3 * time.Minute},
585 HorizontalPodAutoscalerCPUInitializationPeriod: metav1.Duration{Duration: 90 * time.Second},
586 HorizontalPodAutoscalerInitialReadinessDelay: metav1.Duration{Duration: 50 * time.Second},
587 HorizontalPodAutoscalerTolerance: 0.1,
588 },
589 JobController: jobconfig.JobControllerConfiguration{
590 ConcurrentJobSyncs: 10,
591 },
592 CronJobController: cronjobconfig.CronJobControllerConfiguration{
593 ConcurrentCronJobSyncs: 10,
594 },
595 NamespaceController: namespaceconfig.NamespaceControllerConfiguration{
596 NamespaceSyncPeriod: metav1.Duration{Duration: 10 * time.Minute},
597 ConcurrentNamespaceSyncs: 20,
598 },
599 NodeIPAMController: nodeipamconfig.NodeIPAMControllerConfiguration{
600 NodeCIDRMaskSize: 48,
601 NodeCIDRMaskSizeIPv4: 48,
602 NodeCIDRMaskSizeIPv6: 108,
603 },
604 NodeLifecycleController: nodelifecycleconfig.NodeLifecycleControllerConfiguration{
605 NodeEvictionRate: 0.2,
606 SecondaryNodeEvictionRate: 0.05,
607 NodeMonitorGracePeriod: metav1.Duration{Duration: 30 * time.Second},
608 NodeStartupGracePeriod: metav1.Duration{Duration: 30 * time.Second},
609 LargeClusterSizeThreshold: 100,
610 UnhealthyZoneThreshold: 0.6,
611 },
612 PersistentVolumeBinderController: persistentvolumeconfig.PersistentVolumeBinderControllerConfiguration{
613 PVClaimBinderSyncPeriod: metav1.Duration{Duration: 30 * time.Second},
614 VolumeConfiguration: persistentvolumeconfig.VolumeConfiguration{
615 EnableDynamicProvisioning: false,
616 EnableHostPathProvisioning: true,
617 FlexVolumePluginDir: "/flex-volume-plugin",
618 PersistentVolumeRecyclerConfiguration: persistentvolumeconfig.PersistentVolumeRecyclerConfiguration{
619 MaximumRetry: 3,
620 MinimumTimeoutNFS: 200,
621 IncrementTimeoutNFS: 45,
622 MinimumTimeoutHostPath: 45,
623 IncrementTimeoutHostPath: 45,
624 },
625 },
626 VolumeHostCIDRDenylist: []string{"127.0.0.1/28", "feed::/16"},
627 VolumeHostAllowLocalLoopback: false,
628 },
629 PodGCController: podgcconfig.PodGCControllerConfiguration{
630 TerminatedPodGCThreshold: 12000,
631 },
632 ReplicaSetController: replicasetconfig.ReplicaSetControllerConfiguration{
633 ConcurrentRSSyncs: 10,
634 },
635 ReplicationController: replicationconfig.ReplicationControllerConfiguration{
636 ConcurrentRCSyncs: 10,
637 },
638 ResourceQuotaController: resourcequotaconfig.ResourceQuotaControllerConfiguration{
639 ResourceQuotaSyncPeriod: metav1.Duration{Duration: 10 * time.Minute},
640 ConcurrentResourceQuotaSyncs: 10,
641 },
642 SAController: serviceaccountconfig.SAControllerConfiguration{
643 ServiceAccountKeyFile: "/service-account-private-key",
644 ConcurrentSATokenSyncs: 10,
645 },
646 LegacySATokenCleaner: serviceaccountconfig.LegacySATokenCleanerConfiguration{
647 CleanUpPeriod: metav1.Duration{Duration: 365 * 24 * time.Hour},
648 },
649 TTLAfterFinishedController: ttlafterfinishedconfig.TTLAfterFinishedControllerConfiguration{
650 ConcurrentTTLSyncs: 8,
651 },
652 ValidatingAdmissionPolicyStatusController: validatingadmissionpolicystatusconfig.ValidatingAdmissionPolicyStatusControllerConfiguration{
653 ConcurrentPolicySyncs: 9,
654 },
655 },
656 }
657
658
659
660 sort.Sort(sortedGCIgnoredResources(expected.ComponentConfig.GarbageCollectorController.GCIgnoredResources))
661
662 c := &kubecontrollerconfig.Config{}
663 s.ApplyTo(c, []string{""}, []string{""}, nil)
664
665 if !reflect.DeepEqual(expected.ComponentConfig, c.ComponentConfig) {
666 t.Errorf("Got different configuration than expected.\nDifference detected on:\n%s", cmp.Diff(expected.ComponentConfig, c.ComponentConfig))
667 }
668 }
669
670 func TestValidateControllersOptions(t *testing.T) {
671 testCases := []struct {
672 name string
673 expectErrors bool
674 expectedErrorSubString string
675 options interface {
676 Validate() []error
677 }
678 }{
679 {
680 name: "AttachDetachControllerOptions reconciler sync loop period less than one second",
681 expectErrors: true,
682 expectedErrorSubString: "duration time must be greater than one second",
683 options: &AttachDetachControllerOptions{
684 &attachdetachconfig.AttachDetachControllerConfiguration{
685 ReconcilerSyncLoopPeriod: metav1.Duration{Duration: time.Second / 2},
686 DisableAttachDetachReconcilerSync: true,
687 },
688 },
689 },
690 {
691 name: "CSRSigningControllerOptions KubeletServingSignerConfiguration no cert file",
692 expectErrors: true,
693 expectedErrorSubString: "cannot specify key without cert",
694 options: &CSRSigningControllerOptions{
695 &csrsigningconfig.CSRSigningControllerConfiguration{
696 ClusterSigningCertFile: "",
697 ClusterSigningKeyFile: "",
698 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
699 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
700 CertFile: "",
701 KeyFile: "/cluster-signing-kubelet-serving/key-file",
702 },
703 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
704 CertFile: "/cluster-signing-kubelet-client/cert-file",
705 KeyFile: "/cluster-signing-kubelet-client/key-file",
706 },
707 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
708 CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
709 KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
710 },
711 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
712 CertFile: "/cluster-signing-legacy-unknown/cert-file",
713 KeyFile: "/cluster-signing-legacy-unknown/key-file",
714 },
715 },
716 },
717 },
718 {
719 name: "CSRSigningControllerOptions KubeletServingSignerConfiguration no key file",
720 expectErrors: true,
721 expectedErrorSubString: "cannot specify cert without key",
722 options: &CSRSigningControllerOptions{
723 &csrsigningconfig.CSRSigningControllerConfiguration{
724 ClusterSigningCertFile: "",
725 ClusterSigningKeyFile: "",
726 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
727 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
728 CertFile: "/cluster-signing-kubelet-serving/cert-file",
729 KeyFile: "",
730 },
731 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
732 CertFile: "/cluster-signing-kubelet-client/cert-file",
733 KeyFile: "/cluster-signing-kubelet-client/key-file",
734 },
735 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
736 CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
737 KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
738 },
739 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
740 CertFile: "/cluster-signing-legacy-unknown/cert-file",
741 KeyFile: "/cluster-signing-legacy-unknown/key-file",
742 },
743 },
744 },
745 },
746 {
747 name: "CSRSigningControllerOptions KubeletClientSignerConfiguration no cert file",
748 expectErrors: true,
749 expectedErrorSubString: "cannot specify key without cert",
750 options: &CSRSigningControllerOptions{
751 &csrsigningconfig.CSRSigningControllerConfiguration{
752 ClusterSigningCertFile: "",
753 ClusterSigningKeyFile: "",
754 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
755 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
756 CertFile: "/cluster-signing-kubelet-serving/cert-file",
757 KeyFile: "/cluster-signing-kubelet-serving/key-file",
758 },
759 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
760 CertFile: "",
761 KeyFile: "/cluster-signing-kubelet-client/key-file",
762 },
763 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
764 CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
765 KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
766 },
767 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
768 CertFile: "/cluster-signing-legacy-unknown/cert-file",
769 KeyFile: "/cluster-signing-legacy-unknown/key-file",
770 },
771 },
772 },
773 },
774 {
775 name: "CSRSigningControllerOptions KubeletClientSignerConfiguration no key file",
776 expectErrors: true,
777 expectedErrorSubString: "cannot specify cert without key",
778 options: &CSRSigningControllerOptions{
779 &csrsigningconfig.CSRSigningControllerConfiguration{
780 ClusterSigningCertFile: "",
781 ClusterSigningKeyFile: "",
782 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
783 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
784 CertFile: "/cluster-signing-kubelet-serving/cert-file",
785 KeyFile: "/cluster-signing-kubelet-serving/key-file",
786 },
787 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
788 CertFile: "/cluster-signing-kubelet-client/cert-file",
789 KeyFile: "",
790 },
791 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
792 CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
793 KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
794 },
795 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
796 CertFile: "/cluster-signing-legacy-unknown/cert-file",
797 KeyFile: "/cluster-signing-legacy-unknown/key-file",
798 },
799 },
800 },
801 },
802 {
803 name: "CSRSigningControllerOptions KubeAPIServerClientSignerConfiguration no cert file",
804 expectErrors: true,
805 expectedErrorSubString: "cannot specify key without cert",
806 options: &CSRSigningControllerOptions{
807 &csrsigningconfig.CSRSigningControllerConfiguration{
808 ClusterSigningCertFile: "",
809 ClusterSigningKeyFile: "",
810 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
811 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
812 CertFile: "/cluster-signing-kubelet-serving/cert-file",
813 KeyFile: "/cluster-signing-kubelet-serving/key-file",
814 },
815 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
816 CertFile: "/cluster-signing-kubelet-client/cert-file",
817 KeyFile: "/cluster-signing-kubelet-client/key-file",
818 },
819 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
820 CertFile: "",
821 KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
822 },
823 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
824 CertFile: "/cluster-signing-legacy-unknown/cert-file",
825 KeyFile: "/cluster-signing-legacy-unknown/key-file",
826 },
827 },
828 },
829 },
830 {
831 name: "CSRSigningControllerOptions KubeAPIServerClientSignerConfiguration no key file",
832 expectErrors: true,
833 expectedErrorSubString: "cannot specify cert without key",
834 options: &CSRSigningControllerOptions{
835 &csrsigningconfig.CSRSigningControllerConfiguration{
836 ClusterSigningCertFile: "",
837 ClusterSigningKeyFile: "",
838 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
839 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
840 CertFile: "/cluster-signing-kubelet-serving/cert-file",
841 KeyFile: "/cluster-signing-kubelet-serving/key-file",
842 },
843 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
844 CertFile: "/cluster-signing-kubelet-client/cert-file",
845 KeyFile: "/cluster-signing-kubelet-client/key-file",
846 },
847 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
848 CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
849 KeyFile: "",
850 },
851 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
852 CertFile: "/cluster-signing-legacy-unknown/cert-file",
853 KeyFile: "/cluster-signing-legacy-unknown/key-file",
854 },
855 },
856 },
857 },
858 {
859 name: "CSRSigningControllerOptions LegacyUnknownSignerConfiguration no cert file",
860 expectErrors: true,
861 expectedErrorSubString: "cannot specify key without cert",
862 options: &CSRSigningControllerOptions{
863 &csrsigningconfig.CSRSigningControllerConfiguration{
864 ClusterSigningCertFile: "",
865 ClusterSigningKeyFile: "",
866 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
867 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
868 CertFile: "/cluster-signing-kubelet-serving/cert-file",
869 KeyFile: "/cluster-signing-kubelet-serving/key-file",
870 },
871 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
872 CertFile: "/cluster-signing-kubelet-client/cert-file",
873 KeyFile: "/cluster-signing-kubelet-client/key-file",
874 },
875 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
876 CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
877 KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
878 },
879 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
880 CertFile: "",
881 KeyFile: "/cluster-signing-legacy-unknown/key-file",
882 },
883 },
884 },
885 },
886 {
887 name: "CSRSigningControllerOptions LegacyUnknownSignerConfiguration no key file",
888 expectErrors: true,
889 expectedErrorSubString: "cannot specify cert without key",
890 options: &CSRSigningControllerOptions{
891 &csrsigningconfig.CSRSigningControllerConfiguration{
892 ClusterSigningCertFile: "",
893 ClusterSigningKeyFile: "",
894 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
895 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
896 CertFile: "/cluster-signing-kubelet-serving/cert-file",
897 KeyFile: "/cluster-signing-kubelet-serving/key-file",
898 },
899 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
900 CertFile: "/cluster-signing-kubelet-client/cert-file",
901 KeyFile: "/cluster-signing-kubelet-client/key-file",
902 },
903 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
904 CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
905 KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
906 },
907 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
908 CertFile: "/cluster-signing-legacy-unknown/cert-file",
909 KeyFile: "",
910 },
911 },
912 },
913 },
914 {
915 name: "CSRSigningControllerOptions specific file set along with cluster single signing file",
916 expectErrors: true,
917 expectedErrorSubString: "cannot specify --cluster-signing-{cert,key}-file and other --cluster-signing-*-file flags at the same time",
918 options: &CSRSigningControllerOptions{
919 &csrsigningconfig.CSRSigningControllerConfiguration{
920 ClusterSigningCertFile: "/cluster-signing-cert-file",
921 ClusterSigningKeyFile: "/cluster-signing-key-file",
922 ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
923 KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
924 CertFile: "/cluster-signing-kubelet-serving/cert-file",
925 KeyFile: "",
926 },
927 KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
928 CertFile: "",
929 KeyFile: "",
930 },
931 KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
932 CertFile: "",
933 KeyFile: "",
934 },
935 LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
936 CertFile: "",
937 KeyFile: "",
938 },
939 },
940 },
941 },
942 {
943 name: "EndpointSliceControllerOptions ConcurrentServiceEndpointSyncs lower than minConcurrentServiceEndpointSyncs (1)",
944 expectErrors: true,
945 expectedErrorSubString: "concurrent-service-endpoint-syncs must not be less than 1",
946 options: &EndpointSliceControllerOptions{
947 &endpointsliceconfig.EndpointSliceControllerConfiguration{
948 ConcurrentServiceEndpointSyncs: 0,
949 MaxEndpointsPerSlice: 200,
950 },
951 },
952 },
953 {
954 name: "EndpointSliceControllerOptions ConcurrentServiceEndpointSyncs greater than maxConcurrentServiceEndpointSyncs (50)",
955 expectErrors: true,
956 expectedErrorSubString: "concurrent-service-endpoint-syncs must not be more than 50",
957 options: &EndpointSliceControllerOptions{
958 &endpointsliceconfig.EndpointSliceControllerConfiguration{
959 ConcurrentServiceEndpointSyncs: 51,
960 MaxEndpointsPerSlice: 200,
961 },
962 },
963 },
964 {
965 name: "EndpointSliceControllerOptions MaxEndpointsPerSlice lower than minMaxEndpointsPerSlice (1)",
966 expectErrors: true,
967 expectedErrorSubString: "max-endpoints-per-slice must not be less than 1",
968 options: &EndpointSliceControllerOptions{
969 &endpointsliceconfig.EndpointSliceControllerConfiguration{
970 ConcurrentServiceEndpointSyncs: 10,
971 MaxEndpointsPerSlice: 0,
972 },
973 },
974 },
975 {
976 name: "EndpointSliceControllerOptions MaxEndpointsPerSlice greater than maxMaxEndpointsPerSlice (1000)",
977 expectErrors: true,
978 expectedErrorSubString: "max-endpoints-per-slice must not be more than 1000",
979 options: &EndpointSliceControllerOptions{
980 &endpointsliceconfig.EndpointSliceControllerConfiguration{
981 ConcurrentServiceEndpointSyncs: 10,
982 MaxEndpointsPerSlice: 1001,
983 },
984 },
985 },
986 {
987 name: "EndpointSliceMirroringControllerOptions MirroringConcurrentServiceEndpointSyncs lower than mirroringMinConcurrentServiceEndpointSyncs (1)",
988 expectErrors: true,
989 expectedErrorSubString: "mirroring-concurrent-service-endpoint-syncs must not be less than 1",
990 options: &EndpointSliceMirroringControllerOptions{
991 &endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration{
992 MirroringConcurrentServiceEndpointSyncs: 0,
993 MirroringMaxEndpointsPerSubset: 100,
994 },
995 },
996 },
997 {
998 name: "EndpointSliceMirroringControllerOptions MirroringConcurrentServiceEndpointSyncs greater than mirroringMaxConcurrentServiceEndpointSyncs (50)",
999 expectErrors: true,
1000 expectedErrorSubString: "mirroring-concurrent-service-endpoint-syncs must not be more than 50",
1001 options: &EndpointSliceMirroringControllerOptions{
1002 &endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration{
1003 MirroringConcurrentServiceEndpointSyncs: 51,
1004 MirroringMaxEndpointsPerSubset: 100,
1005 },
1006 },
1007 },
1008 {
1009 name: "EndpointSliceMirroringControllerOptions MirroringMaxEndpointsPerSubset lower than mirroringMinMaxEndpointsPerSubset (1)",
1010 expectErrors: true,
1011 expectedErrorSubString: "mirroring-max-endpoints-per-subset must not be less than 1",
1012 options: &EndpointSliceMirroringControllerOptions{
1013 &endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration{
1014 MirroringConcurrentServiceEndpointSyncs: 10,
1015 MirroringMaxEndpointsPerSubset: 0,
1016 },
1017 },
1018 },
1019 {
1020 name: "EndpointSliceMirroringControllerOptions MirroringMaxEndpointsPerSubset greater than mirroringMaxMaxEndpointsPerSubset (1000)",
1021 expectErrors: true,
1022 expectedErrorSubString: "mirroring-max-endpoints-per-subset must not be more than 1000",
1023 options: &EndpointSliceMirroringControllerOptions{
1024 &endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration{
1025 MirroringConcurrentServiceEndpointSyncs: 10,
1026 MirroringMaxEndpointsPerSubset: 1001,
1027 },
1028 },
1029 },
1030 {
1031 name: "EphemeralVolumeControllerOptions ConcurrentEphemeralVolumeSyncs equal 0",
1032 expectErrors: true,
1033 expectedErrorSubString: "concurrent-ephemeralvolume-syncs must be greater than 0",
1034 options: &EphemeralVolumeControllerOptions{
1035 &ephemeralvolumeconfig.EphemeralVolumeControllerConfiguration{
1036 ConcurrentEphemeralVolumeSyncs: 0,
1037 },
1038 },
1039 },
1040 {
1041 name: "HPAControllerOptions ConcurrentHorizontalPodAutoscalerSyncs equal 0",
1042 expectErrors: true,
1043 expectedErrorSubString: "concurrent-horizontal-pod-autoscaler-syncs must be greater than 0",
1044 options: &HPAControllerOptions{
1045 &poautosclerconfig.HPAControllerConfiguration{
1046 ConcurrentHorizontalPodAutoscalerSyncs: 0,
1047 HorizontalPodAutoscalerSyncPeriod: metav1.Duration{Duration: 45 * time.Second},
1048 HorizontalPodAutoscalerUpscaleForbiddenWindow: metav1.Duration{Duration: 1 * time.Minute},
1049 HorizontalPodAutoscalerDownscaleForbiddenWindow: metav1.Duration{Duration: 2 * time.Minute},
1050 HorizontalPodAutoscalerDownscaleStabilizationWindow: metav1.Duration{Duration: 3 * time.Minute},
1051 HorizontalPodAutoscalerCPUInitializationPeriod: metav1.Duration{Duration: 90 * time.Second},
1052 HorizontalPodAutoscalerInitialReadinessDelay: metav1.Duration{Duration: 50 * time.Second},
1053 HorizontalPodAutoscalerTolerance: 0.1,
1054 },
1055 },
1056 },
1057 {
1058 name: "NodeIPAMControllerOptions service cluster ip range more than two entries",
1059 expectErrors: true,
1060 expectedErrorSubString: "--service-cluster-ip-range can not contain more than two entries",
1061 options: &NodeIPAMControllerOptions{
1062 &nodeipamconfig.NodeIPAMControllerConfiguration{
1063 ServiceCIDR: "10.0.0.0/16,244.0.0.0/16,3000::/108",
1064 NodeCIDRMaskSize: 48,
1065 NodeCIDRMaskSizeIPv4: 48,
1066 NodeCIDRMaskSizeIPv6: 108,
1067 },
1068 },
1069 },
1070 {
1071 name: "StatefulSetControllerOptions ConcurrentStatefulSetSyncs equal 0",
1072 expectErrors: true,
1073 expectedErrorSubString: "concurrent-statefulset-syncs must be greater than 0",
1074 options: &StatefulSetControllerOptions{
1075 &statefulsetconfig.StatefulSetControllerConfiguration{
1076 ConcurrentStatefulSetSyncs: 0,
1077 },
1078 },
1079 },
1080 {
1081 name: "JobControllerOptions ConcurrentJobSyncs equal 0",
1082 expectErrors: true,
1083 expectedErrorSubString: "concurrent-job-syncs must be greater than 0",
1084 options: &JobControllerOptions{
1085 &jobconfig.JobControllerConfiguration{
1086 ConcurrentJobSyncs: 0,
1087 },
1088 },
1089 },
1090 {
1091 name: "CronJobControllerOptions ConcurrentCronJobSyncs equal 0",
1092 expectErrors: true,
1093 expectedErrorSubString: "concurrent-cron-job-syncs must be greater than 0",
1094 options: &CronJobControllerOptions{
1095 &cronjobconfig.CronJobControllerConfiguration{
1096 ConcurrentCronJobSyncs: 0,
1097 },
1098 },
1099 },
1100
1101 {
1102 name: "CronJobControllerOptions",
1103 expectErrors: false,
1104 options: &CronJobControllerOptions{
1105 &cronjobconfig.CronJobControllerConfiguration{
1106 ConcurrentCronJobSyncs: 10,
1107 },
1108 },
1109 },
1110 {
1111 name: "DaemonSetControllerOptions",
1112 expectErrors: false,
1113 options: &DaemonSetControllerOptions{
1114 &daemonconfig.DaemonSetControllerConfiguration{
1115 ConcurrentDaemonSetSyncs: 2,
1116 },
1117 },
1118 },
1119 {
1120 name: "DeploymentControllerOptions",
1121 expectErrors: false,
1122 options: &DeploymentControllerOptions{
1123 &deploymentconfig.DeploymentControllerConfiguration{
1124 ConcurrentDeploymentSyncs: 10,
1125 },
1126 },
1127 },
1128 {
1129 name: "DeprecatedControllerOptions",
1130 expectErrors: false,
1131 options: &DeprecatedControllerOptions{
1132 &kubectrlmgrconfig.DeprecatedControllerConfiguration{},
1133 },
1134 },
1135 {
1136 name: "EndpointControllerOptions",
1137 expectErrors: false,
1138 options: &EndpointControllerOptions{
1139 &endpointconfig.EndpointControllerConfiguration{
1140 ConcurrentEndpointSyncs: 10,
1141 },
1142 },
1143 },
1144 {
1145 name: "GarbageCollectorControllerOptions",
1146 expectErrors: false,
1147 options: &GarbageCollectorControllerOptions{
1148 &garbagecollectorconfig.GarbageCollectorControllerConfiguration{
1149 ConcurrentGCSyncs: 30,
1150 GCIgnoredResources: []garbagecollectorconfig.GroupResource{
1151 {Group: "", Resource: "events"},
1152 {Group: eventv1.GroupName, Resource: "events"},
1153 },
1154 EnableGarbageCollector: false,
1155 },
1156 },
1157 },
1158 {
1159 name: "JobControllerOptions",
1160 expectErrors: false,
1161 options: &JobControllerOptions{
1162 &jobconfig.JobControllerConfiguration{
1163 ConcurrentJobSyncs: 10,
1164 },
1165 },
1166 },
1167 {
1168 name: "NamespaceControllerOptions",
1169 expectErrors: false,
1170 options: &NamespaceControllerOptions{
1171 &namespaceconfig.NamespaceControllerConfiguration{
1172 NamespaceSyncPeriod: metav1.Duration{Duration: 10 * time.Minute},
1173 ConcurrentNamespaceSyncs: 20,
1174 },
1175 },
1176 },
1177 {
1178 name: "NodeLifecycleControllerOptions",
1179 expectErrors: false,
1180 options: &NodeLifecycleControllerOptions{
1181 &nodelifecycleconfig.NodeLifecycleControllerConfiguration{
1182 NodeEvictionRate: 0.2,
1183 SecondaryNodeEvictionRate: 0.05,
1184 NodeMonitorGracePeriod: metav1.Duration{Duration: 30 * time.Second},
1185 NodeStartupGracePeriod: metav1.Duration{Duration: 30 * time.Second},
1186 LargeClusterSizeThreshold: 100,
1187 UnhealthyZoneThreshold: 0.6,
1188 },
1189 },
1190 },
1191 {
1192 name: "PodGCControllerOptions",
1193 expectErrors: false,
1194 options: &PodGCControllerOptions{
1195 &podgcconfig.PodGCControllerConfiguration{
1196 TerminatedPodGCThreshold: 12000,
1197 },
1198 },
1199 },
1200 {
1201 name: "ReplicaSetControllerOptions",
1202 expectErrors: false,
1203 options: &ReplicaSetControllerOptions{
1204 &replicasetconfig.ReplicaSetControllerConfiguration{
1205 ConcurrentRSSyncs: 10,
1206 },
1207 },
1208 },
1209 {
1210 name: "ReplicationControllerOptions",
1211 expectErrors: false,
1212 options: &ReplicationControllerOptions{
1213 &replicationconfig.ReplicationControllerConfiguration{
1214 ConcurrentRCSyncs: 10,
1215 },
1216 },
1217 },
1218 {
1219 name: "ResourceQuotaControllerOptions",
1220 expectErrors: false,
1221 options: &ResourceQuotaControllerOptions{
1222 &resourcequotaconfig.ResourceQuotaControllerConfiguration{
1223 ResourceQuotaSyncPeriod: metav1.Duration{Duration: 10 * time.Minute},
1224 ConcurrentResourceQuotaSyncs: 10,
1225 },
1226 },
1227 },
1228 {
1229 name: "SAControllerOptions",
1230 expectErrors: false,
1231 options: &SAControllerOptions{
1232 &serviceaccountconfig.SAControllerConfiguration{
1233 ServiceAccountKeyFile: "/service-account-private-key",
1234 ConcurrentSATokenSyncs: 10,
1235 },
1236 },
1237 },
1238 {
1239 name: "LegacySATokenCleanerOptions",
1240 expectErrors: false,
1241 options: &LegacySATokenCleanerOptions{
1242 &serviceaccountconfig.LegacySATokenCleanerConfiguration{
1243 CleanUpPeriod: metav1.Duration{Duration: 24 * 365 * time.Hour},
1244 },
1245 },
1246 },
1247 {
1248 name: "TTLAfterFinishedControllerOptions",
1249 expectErrors: false,
1250 options: &TTLAfterFinishedControllerOptions{
1251 &ttlafterfinishedconfig.TTLAfterFinishedControllerConfiguration{
1252 ConcurrentTTLSyncs: 8,
1253 },
1254 },
1255 },
1256 }
1257
1258 for _, tc := range testCases {
1259 t.Run(tc.name, func(t *testing.T) {
1260 errs := tc.options.Validate()
1261 if len(errs) > 0 && !tc.expectErrors {
1262 t.Errorf("expected no errors, errors found %+v", errs)
1263 }
1264
1265 if len(errs) == 0 && tc.expectErrors {
1266 t.Errorf("expected errors, no errors found")
1267 }
1268
1269 if len(errs) > 0 && tc.expectErrors {
1270 gotErr := utilerrors.NewAggregate(errs).Error()
1271 if !strings.Contains(gotErr, tc.expectedErrorSubString) {
1272 t.Errorf("expected error: %s, got err: %v", tc.expectedErrorSubString, gotErr)
1273 }
1274 }
1275 })
1276 }
1277 }
1278
1279 func TestValidateControllerManagerOptions(t *testing.T) {
1280 opts, err := NewKubeControllerManagerOptions()
1281 if err != nil {
1282 t.Errorf("expected no error, error found %+v", err)
1283 }
1284
1285 opts.EndpointSliceController.MaxEndpointsPerSlice = 1001
1286
1287 if err := opts.Validate([]string{"*"}, []string{""}, nil); err == nil {
1288 t.Error("expected error, no error found")
1289 }
1290 }
1291
1292 func TestControllerManagerAliases(t *testing.T) {
1293 opts, err := NewKubeControllerManagerOptions()
1294 if err != nil {
1295 t.Errorf("expected no error, error found %+v", err)
1296 }
1297 opts.Generic.Controllers = []string{"deployment", "-job", "-cronjob-controller", "podgc", "token-cleaner-controller"}
1298 expectedControllers := []string{"deployment-controller", "-job-controller", "-cronjob-controller", "pod-garbage-collector-controller", "token-cleaner-controller"}
1299
1300 allControllers := []string{
1301 "bootstrap-signer-controller",
1302 "job-controller",
1303 "deployment-controller",
1304 "cronjob-controller",
1305 "namespace-controller",
1306 "pod-garbage-collector-controller",
1307 "token-cleaner-controller",
1308 }
1309 disabledByDefaultControllers := []string{
1310 "bootstrap-signer-controller",
1311 "token-cleaner-controller",
1312 }
1313 controllerAliases := map[string]string{
1314 "bootstrapsigner": "bootstrap-signer-controller",
1315 "job": "job-controller",
1316 "deployment": "deployment-controller",
1317 "cronjob": "cronjob-controller",
1318 "namespace": "namespace-controller",
1319 "podgc": "pod-garbage-collector-controller",
1320 "tokencleaner": "token-cleaner-controller",
1321 }
1322
1323 if err := opts.Validate(allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
1324 t.Errorf("expected no error, error found %v", err)
1325 }
1326
1327 cfg := &kubecontrollerconfig.Config{}
1328 if err := opts.ApplyTo(cfg, allControllers, disabledByDefaultControllers, controllerAliases); err != nil {
1329 t.Errorf("expected no error, error found %v", err)
1330 }
1331 if !reflect.DeepEqual(cfg.ComponentConfig.Generic.Controllers, expectedControllers) {
1332 t.Errorf("controller aliases not resolved correctly, expected %+v, got %+v", expectedControllers, cfg.ComponentConfig.Generic.Controllers)
1333 }
1334 }
1335
1336 func TestWatchListClientFlagUsage(t *testing.T) {
1337 assertWatchListClientFeatureDefaultValue(t)
1338
1339 fs := pflag.NewFlagSet("addflagstest", pflag.ContinueOnError)
1340 s, _ := NewKubeControllerManagerOptions()
1341 for _, f := range s.Flags([]string{""}, []string{""}, nil).FlagSets {
1342 fs.AddFlagSet(f)
1343 }
1344
1345 fgFlagName := "feature-gates"
1346 fg := fs.Lookup(fgFlagName)
1347 if fg == nil {
1348 t.Fatalf("didn't find %q flag", fgFlagName)
1349 }
1350
1351 expectedWatchListClientString := "WatchListClient=true|false (BETA - default=false)"
1352 if !strings.Contains(fg.Usage, expectedWatchListClientString) {
1353 t.Fatalf("%q flag doesn't contain the expected usage for %v feature gate.\nExpected = %v\nUsage = %v", fgFlagName, clientgofeaturegate.WatchListClient, expectedWatchListClientString, fg.Usage)
1354 }
1355 }
1356
1357 func TestWatchListClientFlagChange(t *testing.T) {
1358 assertWatchListClientFeatureDefaultValue(t)
1359
1360 fs := pflag.NewFlagSet("addflagstest", pflag.ContinueOnError)
1361 s, _ := NewKubeControllerManagerOptions()
1362 for _, f := range s.Flags([]string{""}, []string{""}, nil).FlagSets {
1363 fs.AddFlagSet(f)
1364 }
1365
1366 args := []string{fmt.Sprintf("--feature-gates=%v=true", clientgofeaturegate.WatchListClient)}
1367 if err := fs.Parse(args); err != nil {
1368 t.Fatal(err)
1369 }
1370
1371 watchListClientValue := clientgofeaturegate.FeatureGates().Enabled(clientgofeaturegate.WatchListClient)
1372 if !watchListClientValue {
1373 t.Fatalf("expected %q feature gate to be enabled after setting the command line flag", clientgofeaturegate.WatchListClient)
1374 }
1375 }
1376
1377 func assertWatchListClientFeatureDefaultValue(t *testing.T) {
1378 watchListClientDefaultValue := clientgofeaturegate.FeatureGates().Enabled(clientgofeaturegate.WatchListClient)
1379 if watchListClientDefaultValue {
1380 t.Fatalf("expected %q feature gate to be disabled for KCM", clientgofeaturegate.WatchListClient)
1381 }
1382 }
1383
1384 type sortedGCIgnoredResources []garbagecollectorconfig.GroupResource
1385
1386 func (r sortedGCIgnoredResources) Len() int {
1387 return len(r)
1388 }
1389
1390 func (r sortedGCIgnoredResources) Less(i, j int) bool {
1391 if r[i].Group < r[j].Group {
1392 return true
1393 } else if r[i].Group > r[j].Group {
1394 return false
1395 }
1396 return r[i].Resource < r[j].Resource
1397 }
1398
1399 func (r sortedGCIgnoredResources) Swap(i, j int) {
1400 r[i], r[j] = r[j], r[i]
1401 }
1402
View as plain text