k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kube-controller-manager/app/options/options_test.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 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 // Sort GCIgnoredResources because it's built from a map, which means the 179 // insertion order is random. 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", // Note: This field should have no effect in CM now, and "0.0.0.0" is the default value. 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"}, // note: this does not match /healthz/ or /healthz/* 449 AlwaysAllowGroups: []string{"system:masters"}, 450 }, 451 Master: "192.168.4.20", 452 Metrics: &metrics.Options{}, 453 Logs: logs.NewOptions(), 454 } 455 456 // Sort GCIgnoredResources because it's built from a map, which means the 457 // insertion order is random. 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 // flag set to parse the args that are required to start the kube controller manager 469 for _, f := range s.Flags([]string{""}, []string{""}, nil).FlagSets { 470 fs.AddFlagSet(f) 471 } 472 473 fs.Parse(args) 474 // Sort GCIgnoredResources because it's built from a map, which means the 475 // insertion order is random. 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", // Note: This field should have no effect in CM now, and "0.0.0.0" is the default value. 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 // Sort GCIgnoredResources because it's built from a map, which means the 659 // insertion order is random. 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 /* empty errs */ 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 // max endpoints per slice should be a positive integer <= 1000 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 }